# Cron jobs — TBO booking-detail sync + Payment reminders

Do scheduled scripts. Dono standalone hain — express app se alag chalte hain,
apna DB pool lete hain, chalkar exit ho jaate hain.

| job | schedule | kya karta hai |
|---|---|---|
| `tbo-hcn-sync` | 00:00, 06:00, 12:00, 18:00 | TBO se hotel confirmation number uthata hai; supplier par booking cancel ho gayi ho to DB ka status sync karta hai |
| `payment-reminders` | har ghante `:00` | Refundable HOLD bookings ko `LastCancellationDeadline` se 48h / 24h / 3h pehle payment reminder mail |

Schedule `ecosystem.cron.config.js` (project root) me hai — git me track hota
hai, to dev / UAT / prod par timing ek jaisi rehti hai.

---

## Files

```
scripts/cron/
├── syncBookingStatus.js        TBO GetBookingDetail poll + status sync
├── sendPaymentReminders.js     48H / 24H / 3H reminder mails
└── README.md                   ye file

app/services/
├── tboAuthService.js                  TBO Authenticate -> TokenId (20h cached)
├── hotelPaymentReminderService.js     reminder logic
├── hotelPaymentReminderTemplate.js    48H / 24H / 3H mail HTML
└── hotelBookingEmailService.js        resolveRecipients() + parseSupplierDate()

sql/
├── 2026_09_10_hotel_bookings_hcn.sql
└── 2026_09_10_hotel_booking_reminder_logs.sql

ecosystem.cron.config.js        dono jobs ka PM2 schedule
```

---

# Deploy

## 0. Pehle ye teen cheezein verify karo

Inke bina deploy mat karo. Har ek **chup-chaap** fail hoti hai — koi error
nahi dikhta, aur pata mahine baad chalta hai.

**SendGrid key mail bhej sakti hai?**

```bash
curl -s -o /dev/null -w "%{http_code}\n" \
  -X POST https://api.sendgrid.com/v3/mail/send \
  -H "Authorization: Bearer <SMTP_PASS wali key>" \
  -H "Content-Type: application/json" \
  -d '{"personalizations":[{"to":[{"email":"you@example.com"}]}],
       "from":{"email":"no-reply@fdking.com"},
       "subject":"test","content":[{"type":"text/plain","value":"test"}]}'
```

`202` chahiye. `401` = key invalid. `403` = key me "Mail Send" permission nahi
ya sender verify nahi (SendGrid → Settings → Sender Authentication).

**TBO credentials sahi platform ke hain?**

```bash
curl -s -X POST http://Sharedapi.tektravels.com/SharedData.svc/rest/Authenticate \
  -H 'Content-Type: application/json' \
  -d '{"ClientId":"ApiIntegrationNew","UserName":"<TBO_BOOKING_USERNAME>",
       "Password":"<TBO_BOOKING_PASSWORD>","EndUserIp":"<server ka IP>"}'
```

`TokenId` aana chahiye.

**Server ka outbound IP TBO ne whitelist kiya hai?**
`TBO_END_USER_IP` wahi IP hona chahiye.

## 1. Code

Dev: `development` par push karo, CI pull karke
`pm2 restart Booking-Window-Hotel-Front-API` kar deta hai.

UAT / prod: CI nahi hai, haath se —

```bash
ssh <server>
cd <app-path>
git fetch origin && git checkout <branch> && git pull
```

## 2. Migrations (ek baar per environment)

CI ye nahi chalata.

```bash
mysql -h <db-host> -u <user> -p fdk_hotels < sql/2026_09_10_hotel_bookings_hcn.sql
mysql -h <db-host> -u <user> -p fdk_hotels < sql/2026_09_10_hotel_booking_reminder_logs.sql
```

Verify:

```sql
SHOW COLUMNS FROM hotel_bookings LIKE '%hcn%';            -- 4 columns
SHOW COLUMNS FROM hotel_bookings LIKE 'hotel_confirmation_no';
SHOW TABLES LIKE 'hotel_booking_reminder_logs';
```

`hotel_bookings` badi table hai to ALTER ke waqt lock lag sakta hai — kam
traffic wale window me chalao. MySQL 8 par column wale ALTER ke ant me
`, ALGORITHM=INSTANT` lagakar dekh lo. Index wala ALTER kabhi instant nahi hota.

## 3. `.env` (git me nahi jaati — haath se, har server par)

```bash
TBO_AUTH_URL='http://Sharedapi.tektravels.com/SharedData.svc/rest/Authenticate'
TBO_CLIENT_ID='ApiIntegrationNew'
TBO_BOOKING_USERNAME='BookingWindow'
TBO_BOOKING_PASSWORD='<password>'
TBO_URL_V5=https://hotelbe.tektravels.com/hotelservice.svc/rest/Getbookingdetail/
TBO_END_USER_IP=<is server ka outbound IP>

REMINDER_FROM_EMAIL='FDKING <no-reply@fdking.com>'
```

`TBO_URL_V5` aur `TBO_END_USER_IP` shayad pehle se hon — check kar lo.

> **`TBO_BOOKING_USERNAME` ko `TBO_USERNAME` se mat milao.** Ye do alag TBO
> accounts hain. Bookings middleware ke `BookingWindow` account se hoti hain,
> aur GetBookingDetail sirf usi account ki bookings deta hai jisne book kiya
> ho. Galat account par error aata hai `"Invalid BookingId or TraceId."` — jo
> padhne me BookingId ki galti lagta hai, par hai nahi.

```bash
pm2 restart <app-name> --update-env
```

`--update-env` zaroori hai, warna PM2 purani env pakde rehta hai.

## 4. Dry run — cron chalu karne se PEHLE

```bash
cd <app-path>
node scripts/cron/syncBookingStatus.js --dry-run --limit=5
node scripts/cron/sendPaymentReminders.js --dry-run
```

Dekhna kya hai:

- `picker: N refundable HOLD booking(s) mili`
- `WOULD #<id> 48H -> <emails>` — **ye emails padho.** Ye asli agents hain;
  agle step ke baad inhe mail chala jaayega.
- `hotel_booking_reminder_logs table nahi mili` — migration reh gayi

## 5. Cron register (ek baar per server)

```bash
pm2 start ecosystem.cron.config.js
pm2 save
pm2 list
```

`pm2 save` chhodna mat — iske bina server reboot par dono jobs gayab.
`status: stopped` normal hai; cron job do runs ke beech stopped hi rehta hai.

## 6. Pehle 24 ghante

```bash
pm2 logs payment-reminders --lines 50
pm2 logs tbo-hcn-sync --lines 50
```

Har run ke ant me: `due 5 | sent 3 | skipped 2 | failed 0`

```sql
-- Aaj kya-kya gaya
SELECT reminder_type, status, COUNT(*)
  FROM hotel_booking_reminder_logs
 WHERE DATE(created_at) = CURDATE()
 GROUP BY reminder_type, status;

-- Jo fail ho rahe hain (haftey me ek baar dekho)
SELECT booking_id, reminder_type, attempts, error_message, updated_at
  FROM hotel_booking_reminder_logs
 WHERE status = 'FAILED' ORDER BY updated_at DESC LIMIT 20;

-- HCN sync booking tak pahunch raha hai?
SELECT booking_id, booking_status, hotel_confirmation_no, is_hcn_updated,
       hcn_last_checked_at, hcn_check_attempts, hcn_last_error
  FROM hotel_bookings
 WHERE source = 'TBO' AND hcn_last_checked_at IS NOT NULL
 ORDER BY hcn_last_checked_at DESC LIMIT 10;
```

## Rollback

```bash
pm2 stop payment-reminders tbo-hcn-sync
pm2 save
```

Dono jobs sirf apne naye columns/table me likhte hain (aur cancel hone par
`booking_status`), to band karne se kuch adhoora nahi rehta. Schema wapas
chahiye to dono SQL files ke neeche rollback statements hain.

---

# Kaam kaise karta hai

## tbo-hcn-sync

Picker:

```sql
source = 'TBO' AND booking_status IN (1, 3)
AND checkout_date >= CURDATE() - 2 days
AND ( is_hcn_updated = 0  -- har run
      OR hcn_last_checked_at < NOW() - 11 HOUR )  -- har doosre run
AND hcn_check_attempts < 200
```

Har booking par: TokenId lo → `POST {BookingId, EndUserIp, TokenId}` →
`buildUpdate()` se UPDATE banao.

| TBO ne kya kaha | DB me kya likha jaata hai |
|---|---|
| `HotelConfirmationNo` aa gaya | `hotel_confirmation_no`, `is_hcn_updated = 1` |
| `HotelBookingStatus: Cancelled` | `booking_status = 6`, `ops_confirmed = '2'`, `cancel_reason`, `cancellation_date`, `cancellation_response_data` |
| VerifyPrice → Confirmed | `booking_status = 1` |
| VerifyPrice → BookFailed | `booking_status = 0` |
| kuch nahi badla | sirf `hcn_last_checked_at`, `hcn_check_attempts` |
| API fail | `hcn_last_error` + row `hotel_booking_failure_logs` me |

## payment-reminders

Picker:

```sql
booking_status = 3                                    -- HOLD
AND LastCancellationDeadline IS NOT NULL AND <> ''
AND (is_refundable = 1 OR is_refundable = 'true')
```

Phir JS me `deadline - 48h / 24h / 3h`; jiska waqt aa chuka usi ka mail.
Deadline nikal chuki ho to kuch nahi jaata.

Recipients `emailService.resolveRecipients()` se — wahi agent / staff / guest
aur destination-wise CC jo booking mail me jaate hain.

---

# Jaanne layak baatein

**Ek reminder do baar nahi jaata.** `hotel_booking_reminder_logs` par
`UNIQUE KEY (booking_id, reminder_type)`. Bhejne se PEHLE row claim hoti hai
(`PENDING`), mail ke baad `SENT`. Cron restart ho, do run takraayein, ya mail
bhejte waqt process mar jaye — farq nahi padta. De-dupe DB me hai, code me
nahi. Dobara test karna ho to row delete karni padegi.

**Koi test mode nahi hai.** Reminder cron asli agents ko mail bhejta hai. Test
mode jaanbujh kar hataya gaya, kyunki test mail log me `SENT` likh deta aur
usi booking ka asli reminder hamesha ke liye skip ho jaata.

**`LastCancellationDeadline` VARCHAR hai, DATETIME nahi.** Suppliers alag-alag
format bhejte hain (`25-09-2026 23:59:59`, ISO, …). Parsing
`emailService.parseSupplierDate()` se hoti hai aur date-filter JS me lagta hai,
SQL me nahi (string par `> NOW()` bekaar hai). Column ko DATETIME banana abhi
baaki hai — parser ilaaj nahi, patti hai.

**`RECHECK_SYNCED_HOURS = 11` hai, 12 nahi.** Jaanbujh kar cron interval ke
multiple se kam. 12 rakhne par 00:00:05 par check hui booking 12:00:00 ke run
me "12 ghante pure nahi hue" hokar skip ho jaati aur 18:00 tak ruk jaati. Cron
interval badlo to ye constant bhi dobara dekho.

**Confirmed booking kabhi downgrade nahi hoti.** Sirf teen transitions likhe
jaate hain: kuch bhi → Cancelled, VerifyPrice → Confirmed, VerifyPrice →
BookFailed. Ek ajeeb API response se live booking kharab na ho, isliye.

**Pehle se cancelled (6) booking kabhi pick nahi hoti** — to bina HCN aaye jo
booking cancel ho gayi, uska `hotel_confirmation_no` hamesha NULL rahega.

**Raat ke mails.** Zyadatar deadlines `23:59:59` par hoti hain, to 48H aur 24H
reminders raat 12 baje jaayenge — agent subah dekhega. Business-hours window
(9 AM – 8 PM) abhi nahi hai. 48H/24H ke liye jodni chahiye; 3H ke liye kabhi
nahi — wahan der karna matlab bhejna hi nahi.

---

# Flags

```bash
node scripts/cron/sendPaymentReminders.js --dry-run
node scripts/cron/sendPaymentReminders.js --booking-id=2191110
node scripts/cron/sendPaymentReminders.js --limit=50

node scripts/cron/syncBookingStatus.js --dry-run --verbose
node scripts/cron/syncBookingStatus.js --booking-id=2191110
```

`--dry-run` kuch likhta/bhejta nahi. `--booking-id` saare time-window filters
aur advisory lock bypass karta hai.

Schedule badalna ho: `ecosystem.cron.config.js` me `cron_restart` badlo, phir
`pm2 delete ecosystem.cron.config.js && pm2 start ecosystem.cron.config.js && pm2 save`
— `cron_restart` in-place update nahi hota.
