update body-parser implementation to use Nest's API and improve dependency handling

This commit is contained in:
Marshal
2026-07-28 07:21:04 +00:00
parent 7fcf3a7084
commit 653d5782ee
6 changed files with 128 additions and 35 deletions

View File

@@ -397,9 +397,11 @@ export class ContractBookingService {
*
* - Path A (self-clearance): the customer initiates, uploads his clearance
* proof, Operations reviews and finalizes.
* - Path B (customs): GL initiates on the customer's behalf, the customer
* uploads the GL-input documents on the instance, GL approves them and runs
* the phased ET/DJ workflow (pre-booking milestones are seeded here).
* - Path B (customs, ONE_TIME): the customer initiates too, then uploads the
* GL-input documents on the instance; GL approves them and runs the phased
* ET/DJ workflow (pre-booking milestones are seeded here). GL may still
* initiate on his behalf. GENERAL customs instances come from a shipment
* request ({@link initiateForShipmentRequest}), not from here.
*
* Only after the clearance is finalized is the booking completed (cargo +
* binding day + window check) via {@link completeUnderContract} — by the
@@ -432,9 +434,10 @@ export class ContractBookingService {
const isGlActor =
actorPermissions != null &&
hasFreightPermission(actorPermissions, FREIGHT_PERMS.contracts.createBooking);
// Customs (Path B): GL initiates on the customer's behalf — assertGate
// rejects anyone else. Self-clearance (Path A): the customer initiates.
const createdByRole = await this.assertGate(contract, isGlActor);
// The customer initiates his own shipment instance on ONE_TIME contracts
// (customs or self-clearance); GL may also initiate on a customs contract.
// GENERAL customs instances come from a shipment request, not from here.
const createdByRole = await this.assertGate(contract, isGlActor, true);
if (contract.contractValidUntil && contract.contractValidUntil.getTime() < Date.now()) {
throw new BadRequestException('Contract validity has expired — no new bookings.');
@@ -991,7 +994,11 @@ export class ContractBookingService {
* Returns the role to stamp on the booking, or throws if the caller is not
* allowed to create one for this contract's execution path.
*/
private async assertGate(contract: Contract, isGlActor: boolean): Promise<string> {
private async assertGate(
contract: Contract,
isGlActor: boolean,
isInitiate = false,
): Promise<string> {
// Suspended contracts are frozen for everyone, GL included — say so instead
// of letting the executed-status check below give a misleading reason.
if (contract.status === 'SUSPENDED') {
@@ -1000,10 +1007,13 @@ export class ContractBookingService {
);
}
if (contract.customsClearingEnabled) {
// Path B — Global Logistics initiates and completes the booking ON BEHALF
// OF the customer. The customer never books a customs contract himself;
// he only uploads documents on the instance GL opened for him.
if (!isGlActor) {
// Path B — the customer OPENS the shipment instance on a ONE_TIME customs
// contract (one click, no cargo) and uploads the GL-input documents on it;
// GL still runs the phased ET/DJ clearance and completes the booking with
// cargo, day and price. A GENERAL customs instance is opened by a shipment
// request instead, and completing any customs booking stays GL-only.
const customerMayInitiate = isInitiate && contract.contractKind === 'ONE_TIME';
if (!isGlActor && !customerMayInitiate) {
throw new ForbiddenException(
'Customs-clearance contracts are booked by Global Logistics on behalf of the customer.',
);
@@ -1015,7 +1025,7 @@ export class ContractBookingService {
'Contract must be fully executed before booking a shipment.',
);
}
return 'GL_ET';
return isGlActor ? 'GL_ET' : 'CUSTOMER';
}
// Path A — customer (or staff) once the contract is executed.
@@ -1028,11 +1038,11 @@ export class ContractBookingService {
}
/**
* GL worklist: executed ONE_TIME customs contracts with no live shipment
* instance yet. Customs contracts are initiated by GL on the customer's
* behalf, so without this list a signed contract would sit with nothing on any
* queue (clearance lives on the booking, and the booking does not exist yet).
* GENERAL customs is excluded — its instances are opened by shipment requests.
* GL fallback worklist: executed ONE_TIME customs contracts with no live
* shipment instance yet. The customer normally opens it himself from the
* portal; this list lets GL do it on his behalf, and shows the contracts that
* are on no other queue (clearance lives on the booking, which does not exist
* yet). GENERAL customs is excluded — opened by shipment requests.
*/
async awaitingShipmentContracts(): Promise<Contract[]> {
const { items } = await this.contractsRepository.findAllPaginated({