add dispute functionality for contract duty and implement collection dates

This commit is contained in:
Marshal
2026-07-26 16:58:51 +00:00
parent 9b13fa2ac6
commit 5e10c97294
74 changed files with 3684 additions and 342 deletions

View File

@@ -43,6 +43,14 @@ export class BookingRequest extends BaseEntity {
@Column({ name: 'requested_lines', type: 'jsonb', default: () => "'{}'::jsonb" })
requestedLines!: Freight.RequestedShipmentLines;
/**
* Billing currency the customer chose for this shipment. The contract quotes
* in USD; on a customs contract GL creates the booking, so this is where the
* customer states which currency to be invoiced in.
*/
@Column({ name: 'payment_currency', type: 'varchar', length: 5, nullable: true })
paymentCurrency?: string | null;
@Column({ name: 'notes', type: 'text', nullable: true })
notes?: string | null;

View File

@@ -43,6 +43,41 @@ export class ContractClearanceCycle extends BaseEntity {
@Column({ name: 'vessel_departure_date', type: 'date', nullable: true })
vesselDepartureDate?: string | null;
/** Import DO: when the vessel arrived in Djibouti. Required on DO upload. */
@Column({ name: 'vessel_arrival_date', type: 'date', nullable: true })
vesselArrivalDate?: string | null;
/** Import DO: when GL Djibouti collected the DO. Required on DO upload. */
@Column({ name: 'do_collected_date', type: 'date', nullable: true })
doCollectedDate?: string | null;
/**
* Transit-assignee handshake that runs BEFORE the customs declaration: GL
* Ethiopia asks Djibouti for the officer who will handle the shipment in
* transit, and Djibouti answers with a name. The declaration step stays shut
* until `transitAssigneeName` is set; Djibouti may overwrite it later
* (reassignment) and the newer name simply wins.
*/
@Column({ name: 'transit_assignee_requested_at', type: 'timestamptz', nullable: true })
transitAssigneeRequestedAt?: Date | null;
@Column({ name: 'transit_assignee_requested_by_user_id', type: 'uuid', nullable: true })
transitAssigneeRequestedByUserId?: string | null;
/** What GL Ethiopia asked for — shown on the Djibouti queue. */
@Column({ name: 'transit_assignee_request_note', type: 'text', nullable: true })
transitAssigneeRequestNote?: string | null;
/** The officer Djibouti named — free text, no user directory to bind to. */
@Column({ name: 'transit_assignee_name', type: 'text', nullable: true })
transitAssigneeName?: string | null;
@Column({ name: 'transit_assignee_assigned_at', type: 'timestamptz', nullable: true })
transitAssigneeAssignedAt?: Date | null;
@Column({ name: 'transit_assignee_assigned_by_user_id', type: 'uuid', nullable: true })
transitAssigneeAssignedByUserId?: string | null;
@Column({ name: 'ro_amendment_requested_at', type: 'timestamptz', nullable: true })
roAmendmentRequestedAt?: Date | null;

View File

@@ -21,6 +21,13 @@ export class ContractDocumentRevision extends BaseEntity {
@Column({ name: 'actor_id', type: 'uuid', nullable: true })
actorId?: string | null;
/**
* Who made the edit, captured at the time. Denormalised so the trail still
* names them after a rename or a deactivated account.
*/
@Column({ name: 'actor_name', type: 'varchar', length: 200, nullable: true })
actorName?: string | null;
/** The approval step's required role at the time of the edit. */
@Column({ name: 'actor_role', type: 'varchar', length: 64, nullable: true })
actorRole?: string | null;

View File

@@ -8,6 +8,11 @@ export const CONTRACT_REVIEW_NOTE_TYPES = [
'STAFF_NOTE',
'CUSTOMER_NOTE',
'AMENDMENT',
/**
* The customer disputed the advised duty & tax and asked GL Ethiopia to
* correct it. One row per round — the advice/dispute loop can repeat.
*/
'DUTY_DISPUTE',
] as const;
export type ContractReviewNoteType =
(typeof CONTRACT_REVIEW_NOTE_TYPES)[number];