Skip to content

Inventory API

Hotels, airline quota blocks, FIT inventory, B2B flight offers, food, ground transfers, visa cases, and tickets.


Hotels

Handler: handleHotels at src/lib/api.ts:15385.

Route Method Permission Purpose
/hotels GET (read-only) List hotels joined to active Supplier rows
/hotels POST hotels.create Create hotel contract; posts hotel_purchase journal (DR Stock-in-Hand, CR Supplier Payable); ensures supplier record
/hotels/:id PATCH hotels.edit Update hotel fields
/hotels/:id DELETE hotels.delete Remove hotel

POST /hotels — inventory journal

Cite: src/lib/api.ts:15394.

Input{ supplierId?, city, starRating?, distanceFromHaram?, roomType, totalRooms, pricePerNight, currency, exchangeRate?, leaseFromDate, leaseToDate, gstEnabled, gstRate, gstAmount, ... }.

Work:

  1. ensureHotelSupplierRecord auto-creates a Supplier if supplierId isn't passed.
  2. Compute leaseDays = (leaseToDate - leaseFromDate).
  3. totalCostOriginal = pricePerNight × totalRooms × leaseDays.
  4. If non-INR with exchangeRate, convert to INR for the GL journal.
  5. Insert SupplierTransaction row recording the purchase.
  6. Post perpetual-inventory journal (idempotent — skipped if a prior journal for this hotel already exists):
  7. DR Stock-in-Hand (1310, ASSET) — base cost in INR
  8. DR GST Input Credit (1400, ASSET) — if gstAmount > 0
  9. CR Supplier Payable sub-ledger — gross amount in INR

Parity with airline blocks

Hotel inventory is treated as stock-at-cost until rooms are consumed by GroupHotelAssignment. The expense fires when the assignment is made, not when the contract is signed. Matches createQuotaBlockFinanceEntries (api.ts:17135).

Hotel assignments (allocate to groups)

Handler: handleHotelAssignmentsRoute at src/lib/api.ts:15916.

Route Method Permission Purpose
/hotels/assignments GET (read-only) List all assignments
/hotels/assignments POST hotels.edit Assign rooms from a hotel to a group
/hotels/assignments/:id PATCH hotels.edit Update assignment
/hotels/assignments/:id DELETE Remove assignment

Hotel low-stock thresholds

Handler: handleHotelThresholds at src/lib/api.ts:15869.

Route Method Purpose
/hotels/thresholds/hotels GET, POST Set global low-room threshold
/hotels/thresholds/food GET, POST Set global low-stock threshold for food items

Food inventory

Handler: handleFoodInventory at src/lib/api.ts:27531.

Route Method Permission Purpose
/hotels/food GET (read-only) List food items
/hotels/food POST hotels.create Create food inventory item
/hotels/food/:id PATCH hotels.edit Update item
/hotels/food/:id DELETE hotels.delete Remove item
/hotels/food/import POST hotels.create Bulk import food items (JSON)
/hotels/food/import-file POST hotels.create Bulk import from uploaded file

Food assignments

Handler: handleFoodAssignments at src/lib/api.ts:26279.

Route Method Permission Purpose
/hotels/food/assignments GET (read-only) List meal assignments
/hotels/food/assignments POST hotels.edit Assign meals to a group
/hotels/food/assignments/:id DELETE hotels.edit Remove assignment

Ground transfers

Handlers: handleGroundTransferInventory at src/lib/api.ts:16348, handleGroundTransferAssignments at src/lib/api.ts:16460.

Route Method Permission Purpose
/inventory/ground-transfers GET (read-only) List
/inventory/ground-transfers POST inventory.create Create transfer offering
/inventory/ground-transfers/:id PATCH, DELETE inventory.edit CRUD
/inventory/ground-transfers/:id/assign POST inventory.edit Assign to a group
/ground-transfers/assignments GET (read-only) List assignments
/ground-transfers/assignments POST inventory.edit Create assignment
/ground-transfers/assignments/:id PATCH, DELETE inventory.edit Update / remove

Airlines

Handler: handleInventoryAirlines at src/lib/api.ts:18049.

Route Method Permission Purpose
/inventory/airlines GET (read-only) List airlines
/inventory/airlines POST inventory.create Create airline (code, name, flightNumbers[])
/inventory/airlines/:id PATCH inventory.edit Update
/inventory/airlines/:id DELETE inventory.edit Hard-delete

Airline quota blocks

Handler: handleInventoryQuotaBlocks at src/lib/api.ts:18103.

Route Method Permission Purpose
/inventory/quota-blocks GET (read-only) List quota blocks with live seat math
/inventory/quota-blocks POST inventory.create Create block; posts DR Stock-in-Hand / CR Supplier Payable
/inventory/quota-blocks/:id PATCH inventory.edit Update
/inventory/quota-blocks/:id DELETE inventory.edit Delete (reverses journals)
/inventory/quota-blocks/:id/manifest GET (read-only) Passenger manifest
/inventory/quota-blocks/:id/b2b-passengers PATCH inventory.edit Attach B2B passengers sold through partners
/inventory/quota-blocks/:id/finance-events GET finance.create ( ) Finance event history

Validation rules

Cite: src/lib/api.ts:18103-18520. Cross-leg chronology is validated: arrival time cannot precede departure, return departure cannot precede outbound arrival. Invalid sequences throw 400 with a specific error message.


FIT inventory (free individual traveller)

Handler: handleInventoryFIT at src/lib/api.ts:19346.

Route Method Permission Purpose
/inventory/fit GET (read-only) List FIT rows
/inventory/fit POST inventory.create Create FIT inventory; posts financial journal
/inventory/fit/:id PATCH inventory.edit Update
/inventory/fit/:id DELETE inventory.edit Delete
/inventory/fit/:id/payments GET (read-only) Linked payments
/inventory/fit/:id/finance-events GET finance.create ( ) Finance events

B2B flight offers (partner-sold seats)

Handler: handleInventoryB2BFlights at src/lib/api.ts:26930.

Route Method Permission Purpose
/inventory/b2b-flights GET (read-only) List offers open for partner sale
/inventory/b2b-flights POST inventory.create Create offer (seatsTotal, seatsAvailable, pricePerSeat)
/inventory/b2b-flights/:id PATCH inventory.edit Update
/inventory/b2b-flights/:id DELETE Delete

Partner bookings reduce seatsAvailable atomically (matched-by-version UPDATE in handleSalesBookings POST) — see Bookings.


Inventory reports

Route Method Handler Purpose
/inventory/pnl GET handleInventoryPnl Per-block/hotel P&L
/inventory/utilization GET handleInventoryUtilization Seat / room utilization
/inventory/status GET handleInventoryStatus Overall inventory status

All read-only.

POST /inventory/third-party-sale

Handler: handleThirdPartySale at src/lib/api.ts:26584. Permission: finance.create. Records a sale of inventory to an external party (outside the normal booking flow); posts revenue journal.


Visa

Handler: handleVisaRoute at src/lib/api.ts:13975.

Route Method Permission Purpose
/visa GET (read-only) List visa cases
/visa POST visa.create Create visa case for a booking passenger
/visa/sync POST visa.edit Reconcile per-passenger cases with booking manifests; clean up legacy per-booking cases
/visa/:id GET (read-only) One case + documents + status history + enriched passenger data
/visa/:id/status PATCH visa.edit Change status (NOT_STARTED, APPLIED, UNDER_PROCESS, SENT_TO_EMBASSY, ISSUED, COLLECTED, REJECTED); emails customer + agent
/visa/:id/upload POST tickets.edit ( ) Upload a visa document
/visa/:id/documents GET (read-only) All visa + customer documents merged
/visa/:id/documents/:docId DELETE tickets.edit ( ) Remove a document

Auto-created on ops-approve

When POST /operations/bookings/:id/ops-approve fires, the handler auto-creates a VisaCase for every passenger with needsVisa=true and emits a visa_status_change email. See Bookings.


Tickets

Handlers: handleTickets at src/lib/api.ts:15215, handleTicketById at src/lib/api.ts:14920.

Route Method Permission Purpose
/tickets GET (read-only) List all ticket records with booking/customer/group flight snapshot
/tickets POST tickets.edit Sync ticket records ({bookingId}, {groupId}, or {syncAll:true})
/tickets/:id GET (read-only) One ticket with full context
/tickets/:id PATCH tickets.edit Generic field update
/tickets/:id/name-update PATCH tickets.edit Finalise passenger name; status transitions based on finance clearance
/tickets/:id/issue POST tickets.edit Issue ticket; PNR required; → ISSUED
/tickets/:id/finance-clear POST tickets.edit Grant finance clearance; → FINANCE_CLEARED
/tickets/:id/request-exception POST tickets.edit Request finance exception with emailed proof; → ON_HOLD
/tickets/:id/approve-exception POST tickets.edit Approve finance exception; → FINANCE_CLEARED
/tickets/:id/documents POST tickets.edit Attach TicketDocument

Ticket status machine

NOT_READYFINANCE_CLEARED / ON_HOLDISSUED.

  • Finance clearance is live-recomputed from Booking.balanceAmount <= 0 on each read.
  • A ticket can re-enter NOT_READY if the passenger name changes after clearance.
  • Status history is tracked in TicketStatusHistory (best-effort — may be missing if the migration hasn't run).

Auto-generation on finance-approve

Tickets are auto-created by handleFinanceBookings when finance approves a booking (src/lib/api.ts:13899generateTicketRecordsForBooking). Manual POST /tickets is the resync path (e.g. after booking-passenger changes).