mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-30 08:48:11 +00:00
Merge branch 'dev' into freight/feat/invoice
This commit is contained in:
652
packages/types/src/freight/contracts.ts
Normal file
652
packages/types/src/freight/contracts.ts
Normal file
@@ -0,0 +1,652 @@
|
||||
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", // Path B — GL may create the booking
|
||||
"SELF_CLEARED", // Path A — Operations approved; customer may book
|
||||
"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;
|
||||
/**
|
||||
* GENERAL contracts: total quantity bookable across all shipments on this line
|
||||
* (containers per size, or tons/items for bulk). null = uncapped / ONE_TIME.
|
||||
*/
|
||||
quantityCap?: number | null;
|
||||
}
|
||||
|
||||
/** Remaining bookable quantity per cargo-scope line (GENERAL contracts). */
|
||||
export interface ContractCapacityLine {
|
||||
containerSize?: string | null;
|
||||
cargoTypeId?: string | null;
|
||||
cap: number | null;
|
||||
booked: number;
|
||||
remaining: number | 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" | "gl_et" | "gl_dj";
|
||||
phase: ContractDocPhase;
|
||||
settingCode: string;
|
||||
file: { id: string; name: string; url: string } | null;
|
||||
reviewStatus: ContractDocReviewStatus | null;
|
||||
note: string | null;
|
||||
/** When the review decision (approve/query) was recorded. */
|
||||
reviewedAt?: string | null;
|
||||
/** Staff id that recorded the decision (no user directory to resolve names). */
|
||||
reviewedByStaffId?: string | null;
|
||||
}
|
||||
|
||||
export interface ContractClearanceView {
|
||||
contractId: string;
|
||||
/** Overall contract status (e.g. CLEARANCE_UNDER_REVIEW). */
|
||||
status?: string;
|
||||
clearanceStatus: ContractClearanceStatus;
|
||||
cycleNumber: number;
|
||||
/**
|
||||
* True when the contract bundles EDR customs clearance (Path B, GL-reviewed).
|
||||
* False for Path A self-clearance, reviewed by the Operations team.
|
||||
*/
|
||||
includesCustoms?: boolean;
|
||||
/** Resolved customer-input / GL-output clearance setting codes. */
|
||||
inputCode?: string | null;
|
||||
outputCode?: string | null;
|
||||
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 const CUSTOMS_RISK_LEVELS = ["GREEN", "YELLOW", "RED"] as const;
|
||||
export type CustomsRiskLevel = (typeof CUSTOMS_RISK_LEVELS)[number];
|
||||
|
||||
/** Structured payload carried by RISK_ASSIGNED / DUTY_TAXES_ADVISED milestones. */
|
||||
export interface MilestoneMetadata {
|
||||
riskLevel?: CustomsRiskLevel;
|
||||
dutyAmount?: number;
|
||||
dutyCurrency?: string;
|
||||
declarationSerial?: string;
|
||||
}
|
||||
|
||||
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;
|
||||
metadata?: MilestoneMetadata | null;
|
||||
sortOrder: number;
|
||||
}
|
||||
|
||||
// ── GL cargo exception / damage reports (doc §11 GL Import US-07) ────────────
|
||||
|
||||
export const INCIDENT_TYPES = [
|
||||
"SEAL_BROKEN",
|
||||
"CONTAINER_OPENED",
|
||||
"CONTAINER_DAMAGED",
|
||||
"FLUID_LEAKING",
|
||||
] as const;
|
||||
export type IncidentType = (typeof INCIDENT_TYPES)[number];
|
||||
|
||||
export interface IClearanceIncident {
|
||||
id: string;
|
||||
bookingId: string;
|
||||
incidentType: IncidentType;
|
||||
description: string;
|
||||
photoFileIds: string[];
|
||||
reportedByUserId?: string | null;
|
||||
reportedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
|
||||
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;
|
||||
/** Loaded service-type relation (queue + detail responses include it). */
|
||||
serviceType?: {
|
||||
id: string;
|
||||
code: string;
|
||||
serviceName: string;
|
||||
canBeBookedAlone: boolean;
|
||||
includesCustoms: boolean;
|
||||
} | null;
|
||||
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;
|
||||
/** GENERAL only: total bookable quantity for this line. Omit for uncapped. */
|
||||
quantityCap?: number | 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;
|
||||
}
|
||||
|
||||
// ── Shipment / booking requests (GENERAL + customs, Path B) ─────────────────
|
||||
// On a GENERAL customs contract the customer cannot book directly. They submit a
|
||||
// shipment request (date + quantities); Global Logistics reviews it, then creates
|
||||
// the booking on their behalf and per-booking clearance begins.
|
||||
|
||||
export const BOOKING_REQUEST_STATUSES = [
|
||||
"PENDING",
|
||||
"ACCEPTED",
|
||||
"REJECTED",
|
||||
"CANCELLED",
|
||||
] as const;
|
||||
export type BookingRequestStatus = (typeof BOOKING_REQUEST_STATUSES)[number];
|
||||
|
||||
/** Requested quantities — container lines OR a single bulk line (no per-unit data). */
|
||||
export interface RequestedShipmentLines {
|
||||
containers?: Array<{
|
||||
containerSize: string;
|
||||
quantity: number;
|
||||
hazardousQuantity?: number;
|
||||
reeferQuantity?: number;
|
||||
}>;
|
||||
bulk?: {
|
||||
cargoTypeId?: string | null;
|
||||
cargoWeightTons?: number;
|
||||
itemCount?: number;
|
||||
hazardousQuantity?: number;
|
||||
};
|
||||
}
|
||||
|
||||
export interface IBookingRequest extends BaseEntity {
|
||||
reference: string;
|
||||
contractId: string;
|
||||
requestedByUserId?: string | null;
|
||||
contractRouteId?: string | null;
|
||||
/** Customer's preferred shipment day — informational; GL sets the binding date. */
|
||||
scheduledDate?: string | null;
|
||||
status: BookingRequestStatus;
|
||||
requestedLines: RequestedShipmentLines;
|
||||
notes?: string | null;
|
||||
/** Set when GL accepts and creates the booking. */
|
||||
createdBookingId?: string | null;
|
||||
reviewedByStaffId?: string | null;
|
||||
reviewedAt?: string | null;
|
||||
reviewNote?: string | null;
|
||||
}
|
||||
|
||||
export interface CreateBookingRequestDto {
|
||||
contractRouteId?: string;
|
||||
scheduledDate?: string;
|
||||
containers?: Array<{
|
||||
containerSize: string;
|
||||
quantity: number;
|
||||
hazardousQuantity?: number;
|
||||
reeferQuantity?: number;
|
||||
}>;
|
||||
bulk?: {
|
||||
cargoTypeId?: string | null;
|
||||
cargoWeightTons?: number;
|
||||
itemCount?: number;
|
||||
hazardousQuantity?: number;
|
||||
};
|
||||
notes?: string;
|
||||
}
|
||||
|
||||
export interface ReviewBookingRequestDto {
|
||||
note?: 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;
|
||||
}
|
||||
@@ -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",
|
||||
@@ -377,6 +378,8 @@ export interface IYard extends BaseEntity {
|
||||
export interface IBooking extends BaseEntity {
|
||||
reference: string;
|
||||
customerId: string;
|
||||
/** The contract this booking was created under (Path A / Path B). */
|
||||
contractId?: string | null;
|
||||
trainId?: string | null;
|
||||
status: BookingStatus;
|
||||
/** ONE_TIME for normal bookings; GENERAL_CONTRACT for umbrella contracts. */
|
||||
@@ -613,6 +616,23 @@ export interface AvailableDaysQuery {
|
||||
destinationYardId?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cargo-aware availability query: beyond the route yards it carries the cargo
|
||||
* sizing so the server only returns days where a train has remaining capacity
|
||||
* AND enough matching-type wagons. Response reuses {@link AvailableDaysResponse}.
|
||||
*/
|
||||
export interface AvailableDaysForCargoQuery {
|
||||
originYardId?: string;
|
||||
destinationYardId?: string;
|
||||
freightType: "CONTAINER" | "BULK";
|
||||
/** Bulk cargo type code (e.g. "COFFEE"); ignored for container freight. */
|
||||
cargoTypeCode?: string;
|
||||
/** Total bulk weight in tons. */
|
||||
totalWeightTons?: number;
|
||||
/** Container lines (size + quantity) for container freight. */
|
||||
containers?: { containerSize: string; quantity: number }[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Day-level booking pool: the EAT calendar days that have at least one OPEN
|
||||
* departure on a route. `days` are `yyyy-MM-dd` strings, e.g. `["2026-06-20"]`.
|
||||
|
||||
@@ -32,8 +32,17 @@ export interface IOverviewStaffKpis {
|
||||
activeUsers: number;
|
||||
}
|
||||
|
||||
export interface IOverviewContractKpis {
|
||||
totalActive: number;
|
||||
needsAction: number;
|
||||
inApproval: number;
|
||||
inClearance: number;
|
||||
createdToday: number;
|
||||
}
|
||||
|
||||
export interface IOverviewKpis {
|
||||
bookings: IOverviewBookingKpis;
|
||||
contracts: IOverviewContractKpis;
|
||||
operations: IOverviewOperationsKpis;
|
||||
customers: IOverviewCustomerKpis;
|
||||
billing: IOverviewBillingKpis;
|
||||
@@ -72,6 +81,18 @@ export interface IOverviewRecentBooking {
|
||||
createdAt: string;
|
||||
}
|
||||
|
||||
export interface IOverviewRecentContract {
|
||||
id: string;
|
||||
reference: string;
|
||||
customerLabel: string;
|
||||
status: string;
|
||||
contractKind: string;
|
||||
freightType: string;
|
||||
paymentCurrency: string | null;
|
||||
validUntil: string | null;
|
||||
createdAt: string;
|
||||
}
|
||||
|
||||
export interface IOverviewDashboard {
|
||||
kpis: IOverviewKpis;
|
||||
bookingTrend: IOverviewTrendPoint[];
|
||||
@@ -110,6 +131,17 @@ export interface IOverviewBookingsTab {
|
||||
generatedAt: string;
|
||||
}
|
||||
|
||||
export interface IOverviewContractsTab {
|
||||
kpis: IOverviewContractKpis;
|
||||
contractTrend: IOverviewTrendPoint[];
|
||||
contractsByStatus: IOverviewStatusCount[];
|
||||
contractsByPipeline: IOverviewPipelineCount[];
|
||||
contractsByKind: IOverviewLabelCount[];
|
||||
contractsByFreightType: IOverviewLabelCount[];
|
||||
recentContracts: IOverviewRecentContract[];
|
||||
generatedAt: string;
|
||||
}
|
||||
|
||||
export interface IOverviewBillingTab {
|
||||
kpis: IOverviewBillingKpis;
|
||||
paymentTrend: IOverviewPaymentTrendPoint[];
|
||||
@@ -146,6 +178,7 @@ export interface IOverviewStaffTab {
|
||||
|
||||
export type OverviewTabKey =
|
||||
| 'bookings'
|
||||
| 'contracts'
|
||||
| 'billing'
|
||||
| 'operations'
|
||||
| 'customers'
|
||||
|
||||
Reference in New Issue
Block a user