mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-30 11:08:12 +00:00
contrat,booking,global logestic
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
import { BaseEntity } from '@edr/api-common';
|
||||
import { Column, Entity, Index, JoinColumn, ManyToOne } from 'typeorm';
|
||||
import { Booking } from '../../bookings/entities/booking.entity';
|
||||
import { Contract } from './contract.entity';
|
||||
|
||||
export const MILESTONE_STATUSES = ['PENDING', 'COMPLETED', 'SKIPPED'] as const;
|
||||
export type MilestoneStatus = (typeof MILESTONE_STATUSES)[number];
|
||||
|
||||
export const MILESTONE_OWNER_REGIONS = ['ET', 'DJ', 'OPS', 'CUST'] as const;
|
||||
export type MilestoneOwnerRegion = (typeof MILESTONE_OWNER_REGIONS)[number];
|
||||
|
||||
/**
|
||||
* A GL clearance milestone (18–23 per direction). Pre-booking milestones attach
|
||||
* to contract_id + clearance_cycle_id; post-booking milestones to booking_id.
|
||||
* See §5.12, §5.16, §11.3.
|
||||
*/
|
||||
@Entity({ schema: 'freight', name: 'clearance_milestones' })
|
||||
@Index(['bookingId'])
|
||||
@Index(['contractId'])
|
||||
@Index(['ownerRegion', 'status'])
|
||||
export class ClearanceMilestone extends BaseEntity {
|
||||
@Column({ name: 'booking_id', type: 'uuid', nullable: true })
|
||||
bookingId?: string | null;
|
||||
|
||||
@ManyToOne(() => Booking, { nullable: true, onDelete: 'CASCADE' })
|
||||
@JoinColumn({ name: 'booking_id' })
|
||||
booking?: Booking | null;
|
||||
|
||||
@Column({ name: 'contract_id', type: 'uuid', nullable: true })
|
||||
contractId?: string | null;
|
||||
|
||||
@ManyToOne(() => Contract, { nullable: true, onDelete: 'CASCADE' })
|
||||
@JoinColumn({ name: 'contract_id' })
|
||||
contract?: Contract | null;
|
||||
|
||||
@Column({ name: 'clearance_cycle_id', type: 'uuid', nullable: true })
|
||||
clearanceCycleId?: string | null;
|
||||
|
||||
@Column({ name: 'milestone_code', type: 'varchar', length: 64 })
|
||||
milestoneCode!: string;
|
||||
|
||||
@Column({ name: 'milestone_label', type: 'varchar', length: 255 })
|
||||
milestoneLabel!: string;
|
||||
|
||||
@Column({ name: 'status', type: 'varchar', length: 20, default: 'PENDING' })
|
||||
status!: MilestoneStatus;
|
||||
|
||||
@Column({ name: 'owner_region', type: 'varchar', length: 5, nullable: true })
|
||||
ownerRegion?: MilestoneOwnerRegion | null;
|
||||
|
||||
@Column({ name: 'triggered_by_doc', type: 'boolean', default: false })
|
||||
triggeredByDoc!: boolean;
|
||||
|
||||
@Column({ name: 'triggered_at', type: 'timestamptz', nullable: true })
|
||||
triggeredAt?: Date | null;
|
||||
|
||||
@Column({ name: 'triggered_by_user_id', type: 'uuid', nullable: true })
|
||||
triggeredByUserId?: string | null;
|
||||
|
||||
@Column({ name: 'note', type: 'text', nullable: true })
|
||||
note?: string | null;
|
||||
|
||||
@Column({ name: 'sort_order', type: 'smallint', default: 0 })
|
||||
sortOrder!: number;
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
import { BaseEntity } from '@edr/api-common';
|
||||
import { Column, Entity, Index, JoinColumn, ManyToOne } from 'typeorm';
|
||||
import { Contract } from './contract.entity';
|
||||
|
||||
export const CONTRACT_APPROVAL_STEP_STATUSES = [
|
||||
'PENDING',
|
||||
'APPROVED',
|
||||
'REJECTED',
|
||||
'SKIPPED',
|
||||
] as const;
|
||||
export type ContractApprovalStepStatus =
|
||||
(typeof CONTRACT_APPROVAL_STEP_STATUSES)[number];
|
||||
|
||||
@Entity({ schema: 'freight', name: 'contract_approval_steps' })
|
||||
@Index(['contractId'])
|
||||
@Index(['status'])
|
||||
@Index(['contractId', 'stepOrder'])
|
||||
export class ContractApprovalStep extends BaseEntity {
|
||||
@Column({ name: 'contract_id', type: 'uuid' })
|
||||
contractId!: string;
|
||||
|
||||
@ManyToOne(() => Contract, (c) => c.approvalSteps, { onDelete: 'CASCADE' })
|
||||
@JoinColumn({ name: 'contract_id' })
|
||||
contract?: Contract;
|
||||
|
||||
@Column({ name: 'step_order', type: 'smallint', default: 0 })
|
||||
stepOrder!: number;
|
||||
|
||||
@Column({ name: 'required_role', type: 'varchar', length: 40 })
|
||||
requiredRole!: string;
|
||||
|
||||
@Column({ name: 'blocks_role', type: 'varchar', length: 40, nullable: true })
|
||||
blocksRole?: string | null;
|
||||
|
||||
@Column({ name: 'status', type: 'varchar', length: 20, default: 'PENDING' })
|
||||
status!: ContractApprovalStepStatus;
|
||||
|
||||
@Column({ name: 'acted_by_staff_id', type: 'uuid', nullable: true })
|
||||
actedByStaffId?: string | null;
|
||||
|
||||
@Column({ name: 'acted_at', type: 'timestamptz', nullable: true })
|
||||
actedAt?: Date | null;
|
||||
|
||||
@Column({ name: 'note', type: 'text', nullable: true })
|
||||
note?: string | null;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
import { BaseEntity } from '@edr/api-common';
|
||||
import { Column, Entity, Index, JoinColumn, ManyToOne } from 'typeorm';
|
||||
import { CargoType } from '../../rule-engine/entities/cargo-type.entity';
|
||||
import { Contract } from './contract.entity';
|
||||
|
||||
/**
|
||||
* What cargo sizes/commodities are in scope for a contract — NO quantities.
|
||||
* Container: one row per enabled size (20ft/40ft). Bulk: one row with a cargo
|
||||
* type. See §5.4.
|
||||
*/
|
||||
@Entity({ schema: 'freight', name: 'contract_cargo_scope' })
|
||||
@Index(['contractId'])
|
||||
export class ContractCargoScope extends BaseEntity {
|
||||
@Column({ name: 'contract_id', type: 'uuid' })
|
||||
contractId!: string;
|
||||
|
||||
@ManyToOne(() => Contract, (c) => c.cargoScope, { onDelete: 'CASCADE' })
|
||||
@JoinColumn({ name: 'contract_id' })
|
||||
contract?: Contract;
|
||||
|
||||
/** '20ft' | '40ft'; null for bulk. */
|
||||
@Column({ name: 'container_size', type: 'varchar', length: 10, nullable: true })
|
||||
containerSize?: string | null;
|
||||
|
||||
@Column({ name: 'cargo_type_id', type: 'uuid', nullable: true })
|
||||
cargoTypeId?: string | null;
|
||||
|
||||
@ManyToOne(() => CargoType, { nullable: true })
|
||||
@JoinColumn({ name: 'cargo_type_id' })
|
||||
cargoType?: CargoType | null;
|
||||
|
||||
@Column({ name: 'cargo_free_text', type: 'varchar', length: 200, nullable: true })
|
||||
cargoFreeText?: string | null;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import { BaseEntity } from '@edr/api-common';
|
||||
import { Column, Entity, Index, JoinColumn, ManyToOne } from 'typeorm';
|
||||
import { Contract } from './contract.entity';
|
||||
|
||||
/**
|
||||
* One pre-booking clearance round on a contract (Path B). GENERAL contracts run
|
||||
* many cycles; ONE_TIME uses cycle_number = 1. The booking GL creates is linked
|
||||
* back via bookingId. See §5.16.
|
||||
*/
|
||||
@Entity({ schema: 'freight', name: 'contract_clearance_cycles' })
|
||||
@Index(['contractId'])
|
||||
export class ContractClearanceCycle extends BaseEntity {
|
||||
@Column({ name: 'contract_id', type: 'uuid' })
|
||||
contractId!: string;
|
||||
|
||||
@ManyToOne(() => Contract, (c) => c.clearanceCycles, { onDelete: 'CASCADE' })
|
||||
@JoinColumn({ name: 'contract_id' })
|
||||
contract?: Contract;
|
||||
|
||||
@Column({ name: 'cycle_number', type: 'int' })
|
||||
cycleNumber!: number;
|
||||
|
||||
@Column({ name: 'status', type: 'varchar', length: 40, default: 'AWAITING_DOCUMENTS' })
|
||||
status!: string;
|
||||
|
||||
@Column({ name: 'booking_id', type: 'uuid', nullable: true })
|
||||
bookingId?: string | null;
|
||||
|
||||
@Column({ name: 'started_at', type: 'timestamptz', default: () => 'now()' })
|
||||
startedAt!: Date;
|
||||
|
||||
@Column({ name: 'clearance_ready_at', type: 'timestamptz', nullable: true })
|
||||
clearanceReadyAt?: Date | null;
|
||||
|
||||
@Column({ name: 'completed_at', type: 'timestamptz', nullable: true })
|
||||
completedAt?: Date | null;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
import { BaseEntity } from '@edr/api-common';
|
||||
import { Column, Entity, Index, JoinColumn, ManyToOne } from 'typeorm';
|
||||
import { Contract } from './contract.entity';
|
||||
|
||||
export const CONTRACT_DOC_REVIEW_STATUSES = ['PENDING', 'APPROVED', 'QUERIED'] as const;
|
||||
export type ContractDocReviewStatus =
|
||||
(typeof CONTRACT_DOC_REVIEW_STATUSES)[number];
|
||||
|
||||
export const CONTRACT_DOC_UPLOADER_ROLES = ['CUSTOMER', 'GL_ET', 'GL_DJ'] as const;
|
||||
export type ContractDocUploaderRole =
|
||||
(typeof CONTRACT_DOC_UPLOADER_ROLES)[number];
|
||||
|
||||
/**
|
||||
* Per-document pre-booking clearance review on a contract (Path B). Mirrors
|
||||
* BookingDocumentReview but keyed on contract_id (+ optional clearance cycle).
|
||||
* See §5.16.
|
||||
*/
|
||||
@Entity({ schema: 'freight', name: 'contract_document_review' })
|
||||
@Index(['contractId'])
|
||||
@Index(['status'])
|
||||
export class ContractDocumentReview extends BaseEntity {
|
||||
@Column({ name: 'contract_id', type: 'uuid' })
|
||||
contractId!: string;
|
||||
|
||||
@ManyToOne(() => Contract, { onDelete: 'CASCADE' })
|
||||
@JoinColumn({ name: 'contract_id' })
|
||||
contract?: Contract;
|
||||
|
||||
@Column({ name: 'clearance_cycle_id', type: 'uuid', nullable: true })
|
||||
clearanceCycleId?: string | null;
|
||||
|
||||
@Column({ name: 'setting_code', type: 'varchar', length: 128 })
|
||||
settingCode!: string;
|
||||
|
||||
@Column({ name: 'file_key', type: 'varchar', length: 128 })
|
||||
fileKey!: string;
|
||||
|
||||
@Column({ name: 'file_record_id', type: 'uuid', nullable: true })
|
||||
fileRecordId?: string | null;
|
||||
|
||||
@Column({ name: 'status', type: 'varchar', length: 20, default: 'PENDING' })
|
||||
status!: ContractDocReviewStatus;
|
||||
|
||||
@Column({ name: 'note', type: 'text', nullable: true })
|
||||
note?: string | null;
|
||||
|
||||
@Column({ name: 'uploaded_by_role', type: 'varchar', length: 20, default: 'CUSTOMER' })
|
||||
uploadedByRole!: ContractDocUploaderRole;
|
||||
|
||||
@Column({ name: 'reviewed_by_staff_id', type: 'uuid', nullable: true })
|
||||
reviewedByStaffId?: string | null;
|
||||
|
||||
@Column({ name: 'reviewed_at', type: 'timestamptz', nullable: true })
|
||||
reviewedAt?: Date | null;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
import { BaseEntity } from '@edr/api-common';
|
||||
import { Column, Entity, Index, JoinColumn, ManyToOne } from 'typeorm';
|
||||
import { Contract } from './contract.entity';
|
||||
|
||||
/**
|
||||
* Frozen UNIT rates at contract submit time — one row per rate line. The booking
|
||||
* computes totals from these × entered quantities. See §5.7.
|
||||
*/
|
||||
@Entity({ schema: 'freight', name: 'contract_rate_snapshots' })
|
||||
@Index(['contractId'])
|
||||
export class ContractRateSnapshot extends BaseEntity {
|
||||
@Column({ name: 'contract_id', type: 'uuid' })
|
||||
contractId!: string;
|
||||
|
||||
@ManyToOne(() => Contract, (c) => c.rateSnapshots, { onDelete: 'CASCADE' })
|
||||
@JoinColumn({ name: 'contract_id' })
|
||||
contract?: Contract;
|
||||
|
||||
@Column({ name: 'rate_id', type: 'uuid', nullable: true })
|
||||
rateId?: string | null;
|
||||
|
||||
@Column({ name: 'rate_code', type: 'varchar', length: 64 })
|
||||
rateCode!: string;
|
||||
|
||||
@Column({ name: 'description', type: 'varchar', length: 255, nullable: true })
|
||||
description?: string | null;
|
||||
|
||||
@Column({ name: 'unit_price', type: 'numeric', precision: 14, scale: 2 })
|
||||
unitPrice!: number;
|
||||
|
||||
/** per_container | per_ton | per_item | per_km | flat */
|
||||
@Column({ name: 'unit_of_measure', type: 'varchar', length: 32 })
|
||||
unitOfMeasure!: string;
|
||||
|
||||
@Column({ name: 'currency', type: 'varchar', length: 5 })
|
||||
currency!: string;
|
||||
|
||||
@Column({ name: 'container_size', type: 'varchar', length: 10, nullable: true })
|
||||
containerSize?: string | null;
|
||||
|
||||
@Column({ name: 'is_surcharge', type: 'boolean', default: false })
|
||||
isSurcharge!: boolean;
|
||||
|
||||
/** is_hazardous | is_reefer when this is a conditional surcharge. */
|
||||
@Column({ name: 'conditional_on', type: 'varchar', length: 32, nullable: true })
|
||||
conditionalOn?: string | null;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import { BaseEntity } from '@edr/api-common';
|
||||
import { Column, Entity, Index, JoinColumn, ManyToOne } from 'typeorm';
|
||||
import { Contract } from './contract.entity';
|
||||
|
||||
export const CONTRACT_REVIEW_NOTE_TYPES = [
|
||||
'CHANGES_REQUESTED',
|
||||
'REJECTION',
|
||||
'STAFF_NOTE',
|
||||
'CUSTOMER_NOTE',
|
||||
'AMENDMENT',
|
||||
] as const;
|
||||
export type ContractReviewNoteType =
|
||||
(typeof CONTRACT_REVIEW_NOTE_TYPES)[number];
|
||||
|
||||
@Entity({ schema: 'freight', name: 'contract_review_notes' })
|
||||
@Index(['contractId'])
|
||||
export class ContractReviewNote extends BaseEntity {
|
||||
@Column({ name: 'contract_id', type: 'uuid' })
|
||||
contractId!: string;
|
||||
|
||||
@ManyToOne(() => Contract, (c) => c.reviewNotes, { onDelete: 'CASCADE' })
|
||||
@JoinColumn({ name: 'contract_id' })
|
||||
contract?: Contract;
|
||||
|
||||
@Column({ name: 'note_type', type: 'varchar', length: 40 })
|
||||
noteType!: ContractReviewNoteType;
|
||||
|
||||
@Column({ name: 'body', type: 'text' })
|
||||
body!: string;
|
||||
|
||||
@Column({ name: 'author_role', type: 'varchar', length: 20, nullable: true })
|
||||
authorRole?: string | null;
|
||||
|
||||
@Column({ name: 'author_user_id', type: 'uuid', nullable: true })
|
||||
authorUserId?: string | null;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
import { BaseEntity } from '@edr/api-common';
|
||||
import { Column, Entity, Index, JoinColumn, ManyToOne } from 'typeorm';
|
||||
import { Yard } from '../../rule-engine/entities/yard.entity';
|
||||
import { Contract } from './contract.entity';
|
||||
|
||||
/**
|
||||
* An allowed origin→destination lane of a contract. Routes carry NO quantity —
|
||||
* the contract scope just lists which lanes shipments may use. See §5.3.
|
||||
*/
|
||||
@Entity({ schema: 'freight', name: 'contract_routes' })
|
||||
@Index(['contractId'])
|
||||
export class ContractRoute extends BaseEntity {
|
||||
@Column({ name: 'contract_id', type: 'uuid' })
|
||||
contractId!: string;
|
||||
|
||||
@ManyToOne(() => Contract, (c) => c.routes, { onDelete: 'CASCADE' })
|
||||
@JoinColumn({ name: 'contract_id' })
|
||||
contract?: Contract;
|
||||
|
||||
@Column({ name: 'origin_yard_id', type: 'uuid' })
|
||||
originYardId!: string;
|
||||
|
||||
@ManyToOne(() => Yard)
|
||||
@JoinColumn({ name: 'origin_yard_id' })
|
||||
originYard?: Yard;
|
||||
|
||||
@Column({ name: 'destination_yard_id', type: 'uuid' })
|
||||
destinationYardId!: string;
|
||||
|
||||
@ManyToOne(() => Yard)
|
||||
@JoinColumn({ name: 'destination_yard_id' })
|
||||
destinationYard?: Yard;
|
||||
|
||||
/** Road billing distance; null for rail-only. */
|
||||
@Column({ name: 'km', type: 'numeric', precision: 10, scale: 2, nullable: true })
|
||||
km?: number | null;
|
||||
|
||||
@Column({ name: 'sort_order', type: 'smallint', default: 0 })
|
||||
sortOrder!: number;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
import { BaseEntity } from '@edr/api-common';
|
||||
import { Column, Entity, Index, JoinColumn, ManyToOne } from 'typeorm';
|
||||
import { FileRecord } from '../../files/entities/file.entity';
|
||||
import { Contract } from './contract.entity';
|
||||
|
||||
export const CONTRACT_SIGNER_ROLES = ['CUSTOMER', 'STAFF', 'DIRECTOR', 'CEO'] as const;
|
||||
export type ContractSignerRole = (typeof CONTRACT_SIGNER_ROLES)[number];
|
||||
|
||||
@Entity({ schema: 'freight', name: 'contract_signatures' })
|
||||
@Index(['contractId'])
|
||||
export class ContractSignature extends BaseEntity {
|
||||
@Column({ name: 'contract_id', type: 'uuid' })
|
||||
contractId!: string;
|
||||
|
||||
@ManyToOne(() => Contract, (c) => c.signatures, { onDelete: 'CASCADE' })
|
||||
@JoinColumn({ name: 'contract_id' })
|
||||
contract?: Contract;
|
||||
|
||||
@Column({ name: 'role', type: 'varchar', length: 20 })
|
||||
role!: ContractSignerRole;
|
||||
|
||||
@Column({ name: 'signer_display_name', type: 'varchar', length: 255 })
|
||||
signerDisplayName!: string;
|
||||
|
||||
@Column({ name: 'signature_file_id', type: 'uuid', nullable: true })
|
||||
signatureFileId?: string | null;
|
||||
|
||||
@ManyToOne(() => FileRecord, { nullable: true })
|
||||
@JoinColumn({ name: 'signature_file_id' })
|
||||
signatureFile?: FileRecord | null;
|
||||
|
||||
@Column({ name: 'consent_text', type: 'text', nullable: true })
|
||||
consentText?: string | null;
|
||||
|
||||
@Column({ name: 'signed_at', type: 'timestamptz', default: () => 'now()' })
|
||||
signedAt!: Date;
|
||||
}
|
||||
@@ -0,0 +1,256 @@
|
||||
import { BaseEntity } from '@edr/api-common';
|
||||
import { Column, Entity, Index, JoinColumn, ManyToOne, OneToMany } from 'typeorm';
|
||||
|
||||
import { Company } from '../../companies/entities/company.entity';
|
||||
import { CompanyProfile } from '../../companies/entities/company-profile.entity';
|
||||
import { ServiceType } from '../../rule-engine/entities/service-type.entity';
|
||||
import { FileRecord } from '../../files/entities/file.entity';
|
||||
import { ContractRoute } from './contract-route.entity';
|
||||
import { ContractCargoScope } from './contract-cargo-scope.entity';
|
||||
import { ContractRateSnapshot } from './contract-rate-snapshot.entity';
|
||||
import { ContractSignature } from './contract-signature.entity';
|
||||
import { ContractApprovalStep } from './contract-approval-step.entity';
|
||||
import { ContractReviewNote } from './contract-review-note.entity';
|
||||
import { ContractClearanceCycle } from './contract-clearance-cycle.entity';
|
||||
|
||||
export const CONTRACT_STATUSES = [
|
||||
'DRAFT',
|
||||
'SUBMITTED',
|
||||
'PRICE_CHANGED_PENDING_CONFIRM',
|
||||
'CHANGES_REQUESTED',
|
||||
'PENDING_APPROVAL',
|
||||
'APPROVED',
|
||||
'APPROVED_PENDING_SIGNATURE',
|
||||
'CONTRACT_READY',
|
||||
'SIGNED_CUSTOMER',
|
||||
'FULLY_EXECUTED',
|
||||
'CONTRACT_ACTIVE',
|
||||
'AWAITING_CLEARANCE_DOCUMENTS',
|
||||
'CLEARANCE_UNDER_REVIEW',
|
||||
'CLEARANCE_READY_FOR_BOOKING',
|
||||
'ACTIVE_SHIPMENT_IN_PROGRESS',
|
||||
'CONTRACT_CLOSED',
|
||||
'EXPIRED',
|
||||
'REJECTED',
|
||||
'CANCELLED',
|
||||
'RENEWAL_DRAFT',
|
||||
'RENEWAL_SUBMITTED',
|
||||
'RENEWAL_PENDING_APPROVAL',
|
||||
'AMENDMENTS_PROPOSED',
|
||||
'ARCHIVED',
|
||||
] as const;
|
||||
|
||||
export type ContractStatus = (typeof CONTRACT_STATUSES)[number];
|
||||
|
||||
export const CONTRACT_KINDS = ['ONE_TIME', 'GENERAL'] as const;
|
||||
export type ContractKindValue = (typeof CONTRACT_KINDS)[number];
|
||||
|
||||
export const CONTRACT_CLEARANCE_STATUSES = [
|
||||
'NOT_APPLICABLE',
|
||||
'AWAITING_DOCUMENTS',
|
||||
'DOCUMENTS_UNDER_REVIEW',
|
||||
'CLEARANCE_READY_FOR_BOOKING',
|
||||
'ACTIVE_SHIPMENT_IN_PROGRESS',
|
||||
] as const;
|
||||
export type ContractClearanceStatusValue =
|
||||
(typeof CONTRACT_CLEARANCE_STATUSES)[number];
|
||||
|
||||
/** Statuses where the customer may still edit contract fields. */
|
||||
export const CONTRACT_CUSTOMER_EDITABLE_STATUSES: ContractStatus[] = [
|
||||
'DRAFT',
|
||||
'CHANGES_REQUESTED',
|
||||
];
|
||||
|
||||
/**
|
||||
* The legal/commercial agreement. Defines what cargo sizes/commodities, routes,
|
||||
* and flags are in scope plus the frozen unit rates — but NO quantities. Spawns
|
||||
* shipment {@link Booking} rows via bookings.contract_id. See docs/new-doc.md §5.2.
|
||||
*/
|
||||
@Entity({ schema: 'freight', name: 'contracts' })
|
||||
@Index(['companyId'])
|
||||
@Index(['status'])
|
||||
@Index(['contractKind'])
|
||||
export class Contract extends BaseEntity {
|
||||
@Column({ name: 'reference', type: 'varchar', length: 64, unique: true })
|
||||
reference!: string;
|
||||
|
||||
@Column({ name: 'company_id', type: 'uuid', nullable: true })
|
||||
companyId?: string | null;
|
||||
|
||||
@ManyToOne(() => Company, { nullable: true })
|
||||
@JoinColumn({ name: 'company_id' })
|
||||
company?: Company | null;
|
||||
|
||||
@Column({ name: 'company_profile_id', type: 'uuid', nullable: true })
|
||||
companyProfileId?: string | null;
|
||||
|
||||
@ManyToOne(() => CompanyProfile, { nullable: true })
|
||||
@JoinColumn({ name: 'company_profile_id' })
|
||||
companyProfile?: CompanyProfile | null;
|
||||
|
||||
@Column({ name: 'is_government', type: 'boolean', default: false })
|
||||
isGovernment!: boolean;
|
||||
|
||||
@Column({ name: 'government_institution', type: 'varchar', length: 255, nullable: true })
|
||||
governmentInstitution?: string | null;
|
||||
|
||||
@Column({ name: 'contract_kind', type: 'varchar', length: 20 })
|
||||
contractKind!: ContractKindValue;
|
||||
|
||||
@Column({ name: 'renewal_of_id', type: 'uuid', nullable: true })
|
||||
renewalOfId?: string | null;
|
||||
|
||||
@ManyToOne(() => Contract, { nullable: true })
|
||||
@JoinColumn({ name: 'renewal_of_id' })
|
||||
renewalOf?: Contract | null;
|
||||
|
||||
@Column({ name: 'trade_direction', type: 'varchar', length: 10 })
|
||||
tradeDirection!: string;
|
||||
|
||||
@Column({ name: 'freight_type', type: 'varchar', length: 20 })
|
||||
freightType!: string;
|
||||
|
||||
@Column({ name: 'service_type_id', type: 'uuid' })
|
||||
serviceTypeId!: string;
|
||||
|
||||
@ManyToOne(() => ServiceType)
|
||||
@JoinColumn({ name: 'service_type_id' })
|
||||
serviceType?: ServiceType;
|
||||
|
||||
@Column({ name: 'payment_currency', type: 'varchar', length: 5 })
|
||||
paymentCurrency!: string;
|
||||
|
||||
@Column({ name: 'customs_clearing_enabled', type: 'boolean', default: false })
|
||||
customsClearingEnabled!: boolean;
|
||||
|
||||
@Column({ name: 'customs_clearing_agent', type: 'varchar', length: 200, nullable: true })
|
||||
customsClearingAgent?: string | null;
|
||||
|
||||
@Column({ name: 'equipment_return', type: 'varchar', length: 20, nullable: true })
|
||||
equipmentReturn?: string | null;
|
||||
|
||||
@Column({ name: 'first_mile_pickup_address', type: 'text', nullable: true })
|
||||
firstMilePickupAddress?: string | null;
|
||||
|
||||
@Column({ name: 'first_mile_pickup_lat', type: 'numeric', precision: 10, scale: 7, nullable: true })
|
||||
firstMilePickupLat?: number | null;
|
||||
|
||||
@Column({ name: 'first_mile_pickup_lng', type: 'numeric', precision: 10, scale: 7, nullable: true })
|
||||
firstMilePickupLng?: number | null;
|
||||
|
||||
@Column({ name: 'last_mile_delivery_address', type: 'text', nullable: true })
|
||||
lastMileDeliveryAddress?: string | null;
|
||||
|
||||
@Column({ name: 'last_mile_delivery_lat', type: 'numeric', precision: 10, scale: 7, nullable: true })
|
||||
lastMileDeliveryLat?: number | null;
|
||||
|
||||
@Column({ name: 'last_mile_delivery_lng', type: 'numeric', precision: 10, scale: 7, nullable: true })
|
||||
lastMileDeliveryLng?: number | null;
|
||||
|
||||
@Column({ name: 'is_hazardous', type: 'boolean', default: false })
|
||||
isHazardous!: boolean;
|
||||
|
||||
@Column({ name: 'is_reefer', type: 'boolean', default: false })
|
||||
isReefer!: boolean;
|
||||
|
||||
@Column({ name: 'estimated_shipment_date', type: 'timestamptz', nullable: true })
|
||||
estimatedShipmentDate?: Date | null;
|
||||
|
||||
@Column({ name: 'contract_validity_days', type: 'int', nullable: true })
|
||||
contractValidityDays?: number | null;
|
||||
|
||||
@Column({ name: 'contract_valid_from', type: 'timestamptz', nullable: true })
|
||||
contractValidFrom?: Date | null;
|
||||
|
||||
@Column({ name: 'contract_valid_until', type: 'timestamptz', nullable: true })
|
||||
contractValidUntil?: Date | null;
|
||||
|
||||
@Column({ name: 'expires_at', type: 'timestamptz', nullable: true })
|
||||
expiresAt?: Date | null;
|
||||
|
||||
@Column({ name: 'status', type: 'varchar', length: 40, default: 'DRAFT' })
|
||||
status!: string;
|
||||
|
||||
@Column({ name: 'clearance_status', type: 'varchar', length: 40, default: 'NOT_APPLICABLE' })
|
||||
clearanceStatus!: string;
|
||||
|
||||
@Column({ name: 'clearance_cycle_number', type: 'int', default: 0 })
|
||||
clearanceCycleNumber!: number;
|
||||
|
||||
@Column({ name: 'pricing_breakdown', type: 'jsonb', nullable: true })
|
||||
pricingBreakdown?: Record<string, unknown> | null;
|
||||
|
||||
@Column({ name: 'pricing_display_mode', type: 'varchar', length: 20, default: 'UNIT_RATES', nullable: true })
|
||||
pricingDisplayMode?: string | null;
|
||||
|
||||
@Column({ name: 'contract_type', type: 'varchar', length: 20, nullable: true })
|
||||
contractType?: string | null;
|
||||
|
||||
@Column({ name: 'contract_template_key', type: 'varchar', length: 128, nullable: true })
|
||||
contractTemplateKey?: string | null;
|
||||
|
||||
@Column({ name: 'contract_generated_at', type: 'timestamptz', nullable: true })
|
||||
contractGeneratedAt?: Date | null;
|
||||
|
||||
@Column({ name: 'contract_summary', type: 'text', nullable: true })
|
||||
contractSummary?: string | null;
|
||||
|
||||
@Column({ name: 'version_number', type: 'int', default: 1 })
|
||||
versionNumber!: number;
|
||||
|
||||
@Column({ name: 'financial_terms', type: 'jsonb', nullable: true })
|
||||
financialTerms?: Record<string, unknown> | null;
|
||||
|
||||
@Column({ name: 'approved_by_staff_id', type: 'uuid', nullable: true })
|
||||
approvedByStaffId?: string | null;
|
||||
|
||||
@Column({ name: 'approved_by_staff_at', type: 'timestamptz', nullable: true })
|
||||
approvedByStaffAt?: Date | null;
|
||||
|
||||
@Column({ name: 'signed_by_director_id', type: 'uuid', nullable: true })
|
||||
signedByDirectorId?: string | null;
|
||||
|
||||
@Column({ name: 'signed_by_director_at', type: 'timestamptz', nullable: true })
|
||||
signedByDirectorAt?: Date | null;
|
||||
|
||||
@Column({ name: 'signed_by_ceo_id', type: 'uuid', nullable: true })
|
||||
signedByCeoId?: string | null;
|
||||
|
||||
@Column({ name: 'signed_by_ceo_at', type: 'timestamptz', nullable: true })
|
||||
signedByCeoAt?: Date | null;
|
||||
|
||||
@Column({ name: 'customer_signed_at', type: 'timestamptz', nullable: true })
|
||||
customerSignedAt?: Date | null;
|
||||
|
||||
@Column({ name: 'fully_executed_at', type: 'timestamptz', nullable: true })
|
||||
fullyExecutedAt?: Date | null;
|
||||
|
||||
@Column({ name: 'locked_at', type: 'timestamptz', nullable: true })
|
||||
lockedAt?: Date | null;
|
||||
|
||||
@OneToMany(() => ContractRoute, (r) => r.contract)
|
||||
routes?: ContractRoute[];
|
||||
|
||||
@OneToMany(() => ContractCargoScope, (c) => c.contract)
|
||||
cargoScope?: ContractCargoScope[];
|
||||
|
||||
@OneToMany(() => ContractRateSnapshot, (s) => s.contract)
|
||||
rateSnapshots?: ContractRateSnapshot[];
|
||||
|
||||
@OneToMany(() => ContractSignature, (s) => s.contract)
|
||||
signatures?: ContractSignature[];
|
||||
|
||||
@OneToMany(() => ContractApprovalStep, (s) => s.contract)
|
||||
approvalSteps?: ContractApprovalStep[];
|
||||
|
||||
@OneToMany(() => ContractReviewNote, (n) => n.contract)
|
||||
reviewNotes?: ContractReviewNote[];
|
||||
|
||||
@OneToMany(() => ContractClearanceCycle, (c) => c.contract)
|
||||
clearanceCycles?: ContractClearanceCycle[];
|
||||
|
||||
@OneToMany(() => FileRecord, (file) => file.resourceId, {
|
||||
createForeignKeyConstraints: false,
|
||||
})
|
||||
files?: FileRecord[];
|
||||
}
|
||||
Reference in New Issue
Block a user