contrat,booking,global logestic

This commit is contained in:
Marshal
2026-06-26 23:24:48 +00:00
parent f931342f31
commit 01d53c218c
105 changed files with 19573 additions and 909 deletions

View File

@@ -0,0 +1,512 @@
import type { BaseEntity } from "../common";
import type { IYard } from "./index";
// ── Contract classification ─────────────────────────────────────────────────
/**
* A contract is the legal/commercial agreement (scope + unit rates, no
* quantities). ONE_TIME allows a single active shipment booking at a time;
* GENERAL allows many shipment cycles over the validity window.
*/
export enum ContractKind {
OneTime = "ONE_TIME",
General = "GENERAL",
}
export type ContractTradeDirection = "IMPORT" | "EXPORT" | "DOMESTIC";
export enum ContractFreightType {
Container = "CONTAINER",
Bulk = "BULK",
}
/** Who created a shipment booking under a contract. */
export type BookingCreatedByRole = "CUSTOMER" | "GL_ET" | "STAFF";
/** GL region that owns a clearance step / milestone. */
export type OwnerRegion = "ET" | "DJ" | "OPS" | "CUST";
// ── Contract status machine (doc Appendix A) ────────────────────────────────
export const CONTRACT_STATUSES = [
"DRAFT",
"SUBMITTED",
"PRICE_CHANGED_PENDING_CONFIRM",
"CHANGES_REQUESTED",
"PENDING_APPROVAL",
"APPROVED",
"APPROVED_PENDING_SIGNATURE",
"CONTRACT_READY",
"SIGNED_CUSTOMER",
// transport-only execution (Path A)
"FULLY_EXECUTED", // ONE_TIME
"CONTRACT_ACTIVE", // GENERAL
// customs clearance execution (Path B, pre-booking)
"AWAITING_CLEARANCE_DOCUMENTS",
"CLEARANCE_UNDER_REVIEW",
"CLEARANCE_READY_FOR_BOOKING",
"ACTIVE_SHIPMENT_IN_PROGRESS",
// terminal
"CONTRACT_CLOSED",
"EXPIRED",
"REJECTED",
"CANCELLED",
// renewal branch
"RENEWAL_DRAFT",
"RENEWAL_SUBMITTED",
"RENEWAL_PENDING_APPROVAL",
"AMENDMENTS_PROPOSED",
"ARCHIVED",
] as const;
export type ContractStatus = (typeof CONTRACT_STATUSES)[number];
/**
* Pre-booking clearance gate carried on the contract (Path B only). Separate
* from the contract status so transport-only contracts stay NOT_APPLICABLE.
*/
export const CONTRACT_CLEARANCE_STATUSES = [
"NOT_APPLICABLE",
"AWAITING_DOCUMENTS",
"DOCUMENTS_UNDER_REVIEW",
"CLEARANCE_READY_FOR_BOOKING",
"ACTIVE_SHIPMENT_IN_PROGRESS",
] as const;
export type ContractClearanceStatus =
(typeof CONTRACT_CLEARANCE_STATUSES)[number];
/** Statuses where the customer may edit contract fields. */
export const CONTRACT_CUSTOMER_EDITABLE_STATUSES: ContractStatus[] = [
"DRAFT",
"CHANGES_REQUESTED",
];
// ── Pricing (unit-rate display at contract phase, doc §9.1) ─────────────────
export type ContractRateUnit =
| "per_container"
| "per_ton"
| "per_item"
| "per_km"
| "flat";
export interface ContractUnitRateLineItem {
code: string;
label: string;
unit: ContractRateUnit;
unitPrice: number;
/** "20ft" | "40ft" when the rate is container-size specific. */
containerSize?: string | null;
/** "is_hazardous" | "is_reefer" when this is a conditional surcharge. */
conditionalOn?: string | null;
cargoTypeCode?: string | null;
}
/** Contract `pricing_breakdown` shape — unit rates, no totals. */
export interface ContractPricingBreakdown {
displayMode: "UNIT_RATES";
currency: string;
lineItems: ContractUnitRateLineItem[];
generatedAt: string;
}
// ── Contract child collections ──────────────────────────────────────────────
export interface IContractRoute {
id: string;
contractId: string;
originYardId: string;
originYard?: IYard | null;
destinationYardId: string;
destinationYard?: IYard | null;
/** Road billing distance; null for rail-only. */
km?: number | null;
sortOrder: number;
}
export interface IContractCargoScope {
id: string;
contractId: string;
/** "20ft" | "40ft"; null for bulk. */
containerSize?: string | null;
cargoTypeId?: string | null;
cargoFreeText?: string | null;
}
export interface IContractRateSnapshot {
id: string;
contractId: string;
rateId?: string | null;
rateCode: string;
description?: string | null;
unitPrice: number;
unitOfMeasure: ContractRateUnit;
currency: string;
containerSize?: string | null;
isSurcharge: boolean;
conditionalOn?: string | null;
}
export type ContractSignatureRole = "CUSTOMER" | "STAFF" | "DIRECTOR" | "CEO";
export interface IContractSignature {
id: string;
contractId: string;
role: ContractSignatureRole;
signerDisplayName: string;
signatureFileId?: string | null;
consentText?: string | null;
signedAt: string;
}
export type ContractApprovalStepStatus =
| "PENDING"
| "APPROVED"
| "REJECTED"
| "SKIPPED";
export interface IContractApprovalStep {
id: string;
contractId: string;
stepOrder: number;
requiredRole: string;
blocksRole?: string | null;
status: ContractApprovalStepStatus;
actedByStaffId?: string | null;
actedAt?: string | null;
note?: string | null;
}
// ── Pre-booking clearance (Path B, doc §5.16) ───────────────────────────────
export type ContractDocReviewStatus = "PENDING" | "APPROVED" | "QUERIED";
export interface IContractDocumentReview {
id: string;
contractId: string;
clearanceCycleId?: string | null;
settingCode: string;
fileKey: string;
fileRecordId?: string | null;
status: ContractDocReviewStatus;
note?: string | null;
uploadedByRole: "CUSTOMER" | "GL_ET" | "GL_DJ";
reviewedByStaffId?: string | null;
reviewedAt?: string | null;
}
export interface IContractClearanceCycle {
id: string;
contractId: string;
cycleNumber: number;
status: string;
bookingId?: string | null;
startedAt: string;
clearanceReadyAt?: string | null;
completedAt?: string | null;
}
/**
* The pre-booking clearance view for a contract (Path B). Mirrors
* {@link ClearanceView} for bookings but keyed on the contract.
*/
export interface ContractClearanceDocument {
fileKey: string;
label: string;
required: boolean;
uploadedBy: "customer" | "gl_et" | "gl_dj";
phase: ContractDocPhase;
settingCode: string;
file: { id: string; name: string; url: string } | null;
reviewStatus: ContractDocReviewStatus | null;
note: string | null;
}
export interface ContractClearanceView {
contractId: string;
clearanceStatus: ContractClearanceStatus;
cycleNumber: number;
documents: ContractClearanceDocument[];
/** True once every required customer document is APPROVED. */
allApproved: boolean;
}
/** Phased clearance document upload slots (doc §5.13). */
export enum ContractDocPhase {
CustomerIntake = "CUSTOMER_INTAKE",
GlEtReview = "GL_ET_REVIEW",
GlDjCollection = "GL_DJ_COLLECTION",
GlEtOutput = "GL_ET_OUTPUT",
CustomerDuty = "CUSTOMER_DUTY",
GlEtPostClearance = "GL_ET_POST_CLEARANCE",
GlDjLoading = "GL_DJ_LOADING",
PostTransit = "POST_TRANSIT",
}
// ── Clearance milestones (doc §5.12, Appendix B/C) ──────────────────────────
export type MilestoneStatus = "PENDING" | "COMPLETED" | "SKIPPED";
export interface IClearanceMilestone {
id: string;
bookingId?: string | null;
contractId?: string | null;
clearanceCycleId?: string | null;
milestoneCode: string;
milestoneLabel: string;
status: MilestoneStatus;
ownerRegion?: OwnerRegion | null;
triggeredByDoc: boolean;
triggeredAt?: string | null;
triggeredByUserId?: string | null;
note?: string | null;
sortOrder: number;
}
export const IMPORT_MILESTONES = [
"IMPORT_DOCS_UPLOADED",
"PENDING_DOCUMENT_REVIEW",
"DOCUMENTS_APPROVED",
"UNDER_CUSTOMS_CLEARANCE",
"DECLARED",
"DUTY_TAXES_ADVISED",
"DUTY_TAX_PAID",
"DO_COLLECTED",
"WAGON_REQUESTED",
"FREIGHT_PAYMENT_SETTLED",
"WAGON_ALLOCATED",
"GATEPASS_GRANTED",
"READY_FOR_LOADING",
"LOADED",
"DEPARTED_FROM_DJIBOUTI",
"ARRIVED_ETHIOPIA",
"OFFLOADED",
"T1_CLOSED",
"RISK_ASSIGNED",
"IMPORT_RELEASE_GRANTED",
"IMPORT_PROCESS_COMPLETED",
"STORAGE_INVOICE_RAISED",
"EXIT_NOTE_GENERATED",
] as const;
export type ImportMilestoneCode = (typeof IMPORT_MILESTONES)[number];
export const EXPORT_MILESTONES = [
"EXPORT_DOCS_UPLOADED",
"PENDING_DOCUMENT_REVIEW",
"DOCUMENTS_APPROVED",
"RELEASE_ORDER_SECURED",
"UNDER_CUSTOMS_CLEARANCE",
"DECLARED",
"EXPORT_RELEASED",
"WAGON_REQUESTED",
"FREIGHT_PAYMENT_PENDING",
"FREIGHT_PAYMENT_SETTLED",
"WAGON_ALLOCATED",
"CARGO_ARRIVED",
"READY_FOR_LOADING",
"LOADED",
"DEPARTED_TO_DJIBOUTI",
"ARRIVED_AT_DJIBOUTI",
"GATEPASS_GRANTED",
"OFFLOADED",
] as const;
export type ExportMilestoneCode = (typeof EXPORT_MILESTONES)[number];
// ── Booking container units (per-unit detail at booking, doc §5.10) ─────────
export interface IBookingContainerUnit {
id: string;
bookingContainerId: string;
containerNumber: string;
sealNumber?: string | null;
vgmTons: number;
isHazardous: boolean;
isReefer: boolean;
sortOrder: number;
}
// ── Contract aggregate ──────────────────────────────────────────────────────
export interface IContract extends BaseEntity {
reference: string;
companyId?: string | null;
companyProfileId?: string | null;
isGovernment: boolean;
governmentInstitution?: string | null;
contractKind: ContractKind;
renewalOfId?: string | null;
tradeDirection: ContractTradeDirection;
freightType: ContractFreightType;
serviceTypeId: string;
paymentCurrency: string;
customsClearingEnabled: boolean;
customsClearingAgent?: string | null;
equipmentReturn?: string | null;
firstMilePickupAddress?: string | null;
firstMilePickupLat?: number | null;
firstMilePickupLng?: number | null;
lastMileDeliveryAddress?: string | null;
lastMileDeliveryLat?: number | null;
lastMileDeliveryLng?: number | null;
isHazardous: boolean;
isReefer: boolean;
estimatedShipmentDate?: string | null;
contractValidityDays?: number | null;
contractValidFrom?: string | null;
contractValidUntil?: string | null;
expiresAt?: string | null;
status: ContractStatus;
clearanceStatus: ContractClearanceStatus;
clearanceCycleNumber: number;
pricingBreakdown?: ContractPricingBreakdown | null;
pricingDisplayMode?: "UNIT_RATES";
contractType?: string | null;
contractTemplateKey?: string | null;
contractGeneratedAt?: string | null;
contractSummary?: string | null;
versionNumber: number;
financialTerms?: string | null;
approvedByStaffId?: string | null;
approvedByStaffAt?: string | null;
signedByDirectorId?: string | null;
signedByDirectorAt?: string | null;
signedByCeoId?: string | null;
signedByCeoAt?: string | null;
customerSignedAt?: string | null;
fullyExecutedAt?: string | null;
lockedAt?: string | null;
routes?: IContractRoute[];
cargoScope?: IContractCargoScope[];
rateSnapshots?: IContractRateSnapshot[];
signatures?: IContractSignature[];
approvalSteps?: IContractApprovalStep[];
clearanceCycles?: IContractClearanceCycle[];
files?: Array<{
id: string;
code: string;
name: string;
url: string;
mimeType: string;
size: number;
resourceId: string;
resource: string;
signedUrl?: string | null;
}>;
}
// ── DTOs ─────────────────────────────────────────────────────────────────────
export interface CreateContractCargoScopeDto {
/** "20ft" | "40ft"; omit for bulk. */
containerSize?: string | null;
cargoTypeId?: string | null;
cargoFreeText?: string | null;
}
export interface CreateContractRouteInputDto {
originYardId: string;
destinationYardId: string;
km?: number;
sortOrder?: number;
}
export interface CreateContractDto {
reference?: string;
isGovernment?: boolean;
governmentInstitution?: string;
companyId?: string;
contractKind: ContractKind;
renewalOfId?: string;
tradeDirection: ContractTradeDirection;
freightType: ContractFreightType;
serviceTypeId: string;
paymentCurrency: string;
customsClearingEnabled?: boolean;
customsClearingAgent?: string;
equipmentReturn?: string;
firstMilePickupAddress?: string;
firstMilePickupLat?: number;
firstMilePickupLng?: number;
lastMileDeliveryAddress?: string;
lastMileDeliveryLat?: number;
lastMileDeliveryLng?: number;
isHazardous?: boolean;
isReefer?: boolean;
estimatedShipmentDate?: string;
contractType?: string;
cargoScope: CreateContractCargoScopeDto[];
routes: CreateContractRouteInputDto[];
}
export type UpdateContractDto = Partial<CreateContractDto>;
// ── Booking-under-contract DTOs (doc §8) ────────────────────────────────────
export interface CreateContainerUnitDto {
containerNumber: string;
sealNumber?: string;
vgmTons: number;
isHazardous?: boolean;
isReefer?: boolean;
}
export interface CreateBookingContainerLineDto {
/** "20ft" | "40ft" — must be in the contract's cargo scope. */
containerSize: string;
quantity: number;
hazardousQuantity?: number;
reeferQuantity?: number;
units: CreateContainerUnitDto[];
}
export interface CreateBulkLineDto {
cargoTypeId?: string | null;
cargoWeightTons?: number;
itemCount?: number;
hazardousQuantity?: number;
}
/** Shipment booking created under a contract (Path A customer, Path B GL ET). */
export interface CreateBookingUnderContractDto {
/** Required for GENERAL multi-route contracts; ONE_TIME auto-selected. */
contractRouteId?: string;
/** Binding shipment day. */
scheduledDate: string;
containers?: CreateBookingContainerLineDto[];
bulkLines?: CreateBulkLineDto[];
notes?: string;
}
// ── Clearance review / finalize DTOs (Path B) ───────────────────────────────
export interface ReviewContractClearanceDocumentDto {
fileKey: string;
status: Extract<ContractDocReviewStatus, "APPROVED" | "QUERIED">;
note?: string;
}
export interface RenewContractDto {
/** Reference of the prior contract being renewed. */
previousContractReference?: string;
}

View File

@@ -4,6 +4,7 @@ export * from "./dropdown_settings";
export * from "./file_upload_settings";
export * from "./overview";
export * from "./etrade";
export * from "./contracts";
export enum TradeDirection {
IMPORT = "IMPORT",