Skip to content

The 12 Aug 2026 departure, entered into production

20 September 2026. The second real departure entered into the live system, and the first containing travellers who bought only part of the package.

Read 2026-09-18-real-group-accounting-test.md first — it explains how the accounting is judged, and why it is judged against the owner's own books rather than against tests.

The departure

12Aug-18D-6E-A. 16 pilgrims, 18 days, departing Srinagar 12 August 2026 and returning 29 August.

  • 13 travelled on the block: IndiGo, PNR V4DJXB, 13 seats at ₹56,010 = ₹7,28,130, no free seats.
  • 3 bought "FIT round way, visa, ground" — individual tickets, their own fare, no hotel. Nothing on the sheet states what those seats cost. It is derived: the ticket cost charged to the departure (₹9,26,252) less the block (₹7,28,130) is ₹1,98,122, over 3 travellers ≈ ₹66,041 each. With that figure the sheet reconciles to the Busy ledger exactly, which is what makes the derivation safe to act on.
  • Two rows below the numbered pilgrims carry a name but no serial number, ₹50,000 received and −₹50,000 discount. They are treated as not part of this departure; counting them takes group sales past the figure the sheet itself states. Recorded in the run log as an assumption the owner can overturn.
  • ₹11,200 of service charge (₹700 × 16) is the company's own charge, inside the price the customer pays. The sheet's GRP INPUT (SALES) of ₹17,93,800 is the billed ₹18,05,000 less that.

The scoreboard

Entered through the app as the people who would have entered it — a cashier records each receipt, a different person verifies it, operations approves, ticketing assigns the seats.

Operational refusals 1
Escalations to a super-admin 0 — production has no such account
Entries waiting to post 0
Value left in Stock-in-Hand after departure ₹0
Trial balance ₹66,24,998.02 both sides
Departure cost, the system ₹16,51,274.01
Departure cost, the Busy ledger ₹16,51,274

The one paisa is the FIT rounding: ₹1,98,122 over three seats does not divide into whole paise, and FITInventory holds a price per seat rather than a total.

The single refusal is not a defect in this departure: the ACCOUNTANT cannot approve a journal voucher at all, because finance.journals.approve is held only by FINANCE_MANAGER, CEO, GM and SUPER_ADMIN. The finance manager is therefore both the usual maker and one of only four approvers, which is a decision the owner owes rather than a bug to fix.

The books against the owner's own sheet

the system the sheet
Package revenue (4000) ₹17,93,800 ₹17,93,800
Service charge (4150) ₹11,200 ₹11,200
Departure cost ₹16,51,274.01 ₹16,51,274
Gross profit on the trip ₹1,42,526 ₹1,42,526
Billed to customers ₹18,05,000 ₹18,05,000

Two margin figures are both true and should not be confused: ₹1,42,526 is the profit on the trip, which is what the sheet reports; ₹1,53,726 is what the company made including its own service charge. The run log prints the second.

Where the cost sits

Air — block ₹7,28,130 + individual ₹1,98,122.01 ₹9,26,252.01
Hotels ₹2,76,640
Catering ₹1,56,832
Ground transport ₹64,750
Visa ₹1,82,400
Other (reconciliation adjustment, unattributed transfers, consumables) ₹2,26,800
Total ₹16,51,274.01

What this load changed in the software

Nine faults were found by doing it. Every one of them would have put something wrong into the company's books or in front of a pilgrim, rather than merely inconveniencing the load:

  1. The PNR was tagged. The loader wrote V4DJXB-r2 in every mode — a suffix that keeps practice runs apart on a test database. On production that is a booking reference the airline never issued, on the block and on every seat. Now the real reference in production, tagged only in preview.
  2. A refusal reached for a super-admin. When the block purchase was refused the loader tried to have a super-admin do it instead. Production deliberately has no such account — proving ordinary staff can do their own jobs is the point of the exercise — so it crashed instead of reporting. It now refuses the way every other step does.
  3. A diagnostic created a real departure. The last step of the replay invents a departure and a booking to measure what a group rate sheet does to revenue. On production that left a phantom UMR-12AUG-B-18D and a ₹1,15,000 draft booking nobody made, visible wherever departures are listed. Skipped in production; the rows were removed.
  4. The service charge was never set. The loader recorded it as an assumption and then billed as though it did not exist, so the system's margin came out ₹11,200 above the sheet's gross profit. It now sets serviceChargePerPax on the departure (FIN-039), and the departure also carries the operator's own code (INV-005).
  5. The service charge did not survive being priced. create_booking() inserts a booking before it is priced, and the FIN-039 trigger caps the charge at the booking's own price — so the cap read LEAST(₹700, ₹0) and zeroed every charge, and the later pricing update never went back. Nothing reached 4150 and the whole sale sat in 4000. This was not a loader fault: any booking taken through the app on a departure that charges a service fee lost it.
  6. The caterers were credited the wrong way round. The sheet spells Makkah MACCA, which the extractor's city matcher did not know, so it could not tell the two catering tables apart and fell back to row order — Madinah first on this departure. Gowhar was owed ₹1,12,723 and Muneer ₹44,109, not the reverse.
  7. Land costs were entered as miscellaneous expenses. The cost report builds Meals from GroupFoodAssignment and Ground from GroupGroundTransferAssignment, so catering and transport entered as GroupExpense made the departure's total right and every per-passenger land figure zero. They are now bought as inventory and assigned, which also stops a catering bill being typed twice — once as the payable, once as the cost.
  8. A pilgrim introduced by a sub-agent showed as a walk-in. Customer.source is free text and the screens know two words; rows written as Agent read back as Direct. The bookings and the ledger were right throughout — only the customer screens lied. Normalised at the route, again by trigger, and existing rows corrected.
  9. An individual ticket was not treated as a flight. The itinerary labelled the return leg with the outbound flight number, because the query asked FITInventory for its return times but not its return flight number; and a traveller's journey gave a FIT ticket one nameless outbound segment and no return at all, so anyone on their own ticket appeared never to come home. The departure's flight times were also hard-coded to another departure's clock.

The reporting side of individual seats is still wrong in the same way and is being worked on: the FIT overview reports "Open Seats 3 / 3", "0 linked groups" and "Bookings sold 0" for a row the database correctly records as fully allocated, linked to the departure, and flown.

Two walls that a re-load hits

Both are correct rules, and both cost a run to learn:

  • A posted voucher cannot be deleted (FIN-031) — Post a reversal instead.
  • Inventory a person has worked on cannot be deleted (AIR §26); it is archived, and its unique code and PNR still block a retry until moved aside.

So a departure cannot be taken out of production through the API key. Re-entering one means running scripts/dev/purge-business-data.sql in the Supabase SQL editor, which suspends the triggers for a single transaction. scripts/dev/remove-departure.mjs removes what it can and stops at these two.

What the system still cannot say about this departure

  • A flat cancellation retention. The business keeps ₹27,000 — a ₹10,000 fee plus ₹17,000 of visa cost already spent. A policy slab holds one percentage at two decimals, so the nearest it can say is 0%. Every cancellation on this departure needs a manager's refund override.
  • An individual ticket's own PNR and fare. FITInventory holds one PNR and one price for a row of N seats. This departure names two PNRs for three travellers; only the first fits.
  • A purchase whose total is known but whose per-seat price is not — hence the paisa.
  • An unsold individual seat. The write-off exists for blocks only (FIN-037), though UnsoldSeatWriteOff.fitId is already there. An unflown FIT seat would sit in stock for ever.
  • A per-pilgrim negotiated price as a rate. Prices on this departure run ₹65,000 to ₹1,52,000, so no group rate sheet applies; setting one would also switch the departure into the invoice-based revenue model, where creating a booking posts no revenue at all.

These are recorded as a backlog item in ../rules/PROGRAM.md and described on ../api/inventory.md rather than left as silence.