split export

This commit is contained in:
Marshal
2026-07-18 09:12:52 +00:00
parent 6100a121d2
commit 406fbf6c45
14 changed files with 1092 additions and 41 deletions

View File

@@ -150,10 +150,18 @@ export class BookingNotifierService {
): Promise<void> {
const payMinutes = Math.max(1, Math.round((deadline.getTime() - Date.now()) / 60_000));
const eat = deadline.toLocaleString('en-GB', { timeZone: 'Africa/Addis_Ababa' });
const leftover = totalWagons - offeredWagons;
// With auto-placement on, the leftover is booked FOR the customer on another
// train (its own invoice) — telling them to rebook it themselves would be
// wrong. Without it, the leftover returns to the contract to rebook.
const leftoverCopy =
process.env.FREIGHT_AUTO_REMAINDER === 'true'
? `The remaining ${leftover} will be booked for you on another train, with its own invoice. `
: `The remaining ${leftover} return${leftover === 1 ? 's' : ''} to your contract — book them yourself in a later window. `;
const msg =
`Only ${offeredWagons} of ${totalWagons} wagons fit the train for booking ${b.reference ?? b.id}. ` +
`Pay within ${payMinutes} minute${payMinutes === 1 ? '' : 's'} to accept and ship ${offeredWagons} wagon${offeredWagons === 1 ? '' : 's'} now. ` +
`The remaining ${totalWagons - offeredWagons} return${totalWagons - offeredWagons === 1 ? 's' : ''} to your contract — book them yourself in a later window. ` +
leftoverCopy +
`If you do not pay, the booking stays whole and you can rebook in the next window. Deadline: ${eat} EAT.`;
await this.notifyContact(b, msg, 'PAY NOW (PARTIAL)');
// HIGH: a split is a change to what the customer ordered AND a live payment
@@ -164,6 +172,23 @@ export class BookingNotifierService {
});
}
/**
* The wagons that did not fit the train the customer just paid for have been
* auto-booked as their own booking (`remainder`) — they ride another train and
* are billed separately. Sent instead of leaving the customer to rebook.
*/
remainderPlaced(remainder: Booking, parentReference: string): void {
const msg =
`The wagons left over from booking ${parentReference} have been booked as ` +
`${remainder.reference ?? remainder.id} on another train. ` +
`It carries its own invoice — pay it to secure that slot.`;
void this.notifyContact(remainder, msg, 'REMAINDER BOOKED');
this.inApp(remainder, 'Leftover wagons booked', msg, {
type: NotificationType.INVOICE_ISSUED,
priority: NotificationPriority.HIGH,
});
}
secured(b: Booking, reason: 'paid' | 'gov', scheduleId?: string | null): void {
void (async () => {
const label = await this.scheduleLabel(scheduleId ?? b.trainScheduleId);