lifecycle

This commit is contained in:
Nathnael
2026-08-18 13:11:09 +00:00
parent 03b16b4ee8
commit dd6df306f2
3 changed files with 79 additions and 13 deletions

View File

@@ -36,9 +36,13 @@ describe('BookingLifecycleNotifierService — operation changes requested', () =
);
});
it('sends a GL-created booking back to the GL who created it, not the customer', async () => {
it('sends a GL-created customs booking back to the GL who created it, not the customer', async () => {
service.operationChangesRequested(
booking({ createdByRole: 'GL_ET', createdByUserId: 'gl-user-1' }),
booking({
customsClearingEnabled: true,
createdByRole: 'GL_ET',
createdByUserId: 'gl-user-1',
}),
'Cargo weight does not match the declaration',
);
await flush();
@@ -54,7 +58,7 @@ describe('BookingLifecycleNotifierService — operation changes requested', () =
expect(notifications.directSend).not.toHaveBeenCalled();
});
it('still tells the customer when the booking is their own', async () => {
it('still tells the customer when the booking is a non-customs self-service booking', async () => {
service.operationChangesRequested(booking(), 'Please attach the packing list');
await flush();
@@ -65,14 +69,38 @@ describe('BookingLifecycleNotifierService — operation changes requested', () =
expect(notifications.directSend).toHaveBeenCalled();
});
it('falls back to the customer when the GL creator is unknown (legacy rows)', async () => {
it('routes a customer-opened customs booking to the clearance desk, not the customer', async () => {
// Path B lets the customer open the ONE_TIME shipment instance themselves
// (contract-booking.service assertGate's customerMayInitiate) — createdByRole
// stays 'CUSTOMER', but GL still owns completing/resubmitting it.
service.operationChangesRequested(
booking({ createdByRole: 'GL_ET', createdByUserId: null }),
booking({ customsClearingEnabled: true, createdByRole: 'CUSTOMER' }),
'Fix the declaration',
);
await flush();
expect(inbox.notify.mock.calls[0][0].recipients).toEqual({ companyId: 'co-1' });
const sent = inbox.notify.mock.calls[0][0];
expect(sent.recipients).toEqual({
permissionKeys: [FREIGHT_PERMS.bookings.clearanceGetNotification],
});
expect(sent.audience).toBe('BACKOFFICE');
expect(notifications.directSend).not.toHaveBeenCalled();
});
it('falls back to the clearance desk when the GL creator is unknown (legacy rows)', async () => {
service.operationChangesRequested(
booking({
customsClearingEnabled: true,
createdByRole: 'GL_ET',
createdByUserId: null,
}),
'Fix the declaration',
);
await flush();
expect(inbox.notify.mock.calls[0][0].recipients).toEqual({
permissionKeys: [FREIGHT_PERMS.bookings.clearanceGetNotification],
});
});
});

View File

@@ -247,20 +247,27 @@ export class BookingLifecycleNotifierService {
/**
* Operations returned the operation request for changes.
*
* A customs (Path B) booking was created BY GL Ethiopia on the customer's
* behalf — the customer cannot edit or resubmit it, so telling them to "update
* from the portal" is a dead end. Those go to the GL who created it, linking
* the contract clearance page they work from. Everything else (customer-made
* bookings) keeps the portal message.
* A customs (Path B) booking is completed by GL Ethiopia on the customer's
* behalf regardless of who opened the shipment instance — the customer-opened
* ONE_TIME case (see contract-booking.service assertGate) still stamps
* createdByRole 'CUSTOMER', so gate on customsClearingEnabled, not on who
* created it. The customer cannot edit or resubmit a customs booking, so
* telling them to "update from the portal" is a dead end. Those go to the GL
* who created it when known, else the clearance desk, linking the contract
* clearance page they work from. Everything else (customer-made bookings)
* keeps the portal message.
*/
operationChangesRequested(b: Booking, note: string): void {
if (b.createdByRole === 'GL_ET' && b.createdByUserId) {
if (b.customsClearingEnabled) {
const msg =
`Operations returned booking ${b.reference} for changes: ${note}. ` +
`Address it on the contract clearance page and resubmit to Operations.`;
this.logger.log(`OPERATION CHANGES REQUESTED (to GL) — ${this.ref(b)}`);
void this.inbox.notify({
recipients: { userIds: [b.createdByUserId] },
recipients:
b.createdByRole === 'GL_ET' && b.createdByUserId
? { userIds: [b.createdByUserId] }
: CLEARANCE_DESK,
audience: NotificationAudience.BACKOFFICE,
type: NotificationType.BOOKING_STATUS,
title: `Booking ${b.reference} needs changes`,