mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-30 02:58:11 +00:00
Marshaling document Receive Export and import handover to customer
This commit is contained in:
@@ -26,7 +26,8 @@ const DEMO_STAFF_USERS = [
|
||||
{ email: 'operations@edr.local', username: 'operations', roleKey: 'edr_operations_officer' },
|
||||
{ email: 'director@edr.local', username: 'director', roleKey: 'edr_director' },
|
||||
{ email: 'ceo@edr.local', username: 'ceo', roleKey: 'edr_ceo' },
|
||||
{ email: 'gl@edr.local', username: 'gl', roleKey: 'edr_global_logistics' },
|
||||
{ email: 'gl-et@edr.local', username: 'gl_et', roleKey: 'edr_gl_ethiopia' },
|
||||
{ email: 'gl-dj@edr.local', username: 'gl_dj', roleKey: 'edr_gl_djibouti' },
|
||||
] as const;
|
||||
|
||||
/**
|
||||
|
||||
@@ -238,9 +238,14 @@ export const EDR_FREIGHT_ROLES: FreightSeedRole[] = [
|
||||
permissionKeys: [...ROLE_PERMISSION_PRESETS.marketing],
|
||||
},
|
||||
{
|
||||
key: "edr_global_logistics",
|
||||
name: { en: "EDR Global Logistics" },
|
||||
permissionKeys: [...ROLE_PERMISSION_PRESETS.globalLogistics],
|
||||
key: "edr_gl_ethiopia",
|
||||
name: { en: "EDR Global Logistics — Ethiopia" },
|
||||
permissionKeys: [...ROLE_PERMISSION_PRESETS.glEthiopia],
|
||||
},
|
||||
{
|
||||
key: "edr_gl_djibouti",
|
||||
name: { en: "EDR Global Logistics — Djibouti" },
|
||||
permissionKeys: [...ROLE_PERMISSION_PRESETS.glDjibouti],
|
||||
},
|
||||
{
|
||||
key: "edr_org_manager",
|
||||
|
||||
@@ -352,6 +352,135 @@ const CLEARANCE_DOCUMENT_SETTINGS: OnboardingDocumentSetting[] = [
|
||||
},
|
||||
];
|
||||
|
||||
// ── Contract pre-booking clearance settings (Path B) ────────────────────────
|
||||
// For customs-clearance contracts the customer uploads clearance documents on
|
||||
// the CONTRACT (before any booking exists). Same customer doc sets as the legacy
|
||||
// booking clearance, plus the GL output sets, keyed on the contract. Resolved by
|
||||
// contract-clearance.util.ts (codes: contract_clearance_{op}_{freight} and
|
||||
// contract_clearance_output_{op}_container).
|
||||
const CONTRACT_CLEARANCE_ENTITY = "contract_clearance";
|
||||
|
||||
const CONTRACT_CLEARANCE_SETTINGS: OnboardingDocumentSetting[] = [
|
||||
{
|
||||
code: "contract_clearance_import_container",
|
||||
label: "Contract clearance documents (import container)",
|
||||
entity: CONTRACT_CLEARANCE_ENTITY,
|
||||
fields: IMPORT_CONTAINER_FIELDS,
|
||||
},
|
||||
{
|
||||
code: "contract_clearance_export_container",
|
||||
label: "Contract clearance documents (export container)",
|
||||
entity: CONTRACT_CLEARANCE_ENTITY,
|
||||
fields: EXPORT_CONTAINER_FIELDS,
|
||||
},
|
||||
{
|
||||
code: "contract_clearance_import_bulk",
|
||||
label: "Contract clearance documents (import bulk)",
|
||||
entity: CONTRACT_CLEARANCE_ENTITY,
|
||||
fields: IMPORT_BULK_FIELDS,
|
||||
},
|
||||
{
|
||||
code: "contract_clearance_export_bulk",
|
||||
label: "Contract clearance documents (export bulk)",
|
||||
entity: CONTRACT_CLEARANCE_ENTITY,
|
||||
fields: EXPORT_BULK_FIELDS,
|
||||
},
|
||||
// GL ET output sets uploaded during pre-booking clearance.
|
||||
{
|
||||
code: "contract_clearance_output_import_container",
|
||||
label: "Contract customs output documents (import container)",
|
||||
entity: CONTRACT_CLEARANCE_ENTITY,
|
||||
fields: IMPORT_CONTAINER_OUTPUT_FIELDS,
|
||||
},
|
||||
{
|
||||
code: "contract_clearance_output_export_container",
|
||||
label: "Contract customs output documents (export container)",
|
||||
entity: CONTRACT_CLEARANCE_ENTITY,
|
||||
fields: EXPORT_CONTAINER_OUTPUT_FIELDS,
|
||||
},
|
||||
];
|
||||
|
||||
// ── Path A self-clearance settings (no EDR customs service) ──────────────────
|
||||
// When the contract does NOT bundle customs clearance, the customer clears the
|
||||
// cargo himself and uploads his OWN clearance proof on the contract. Operations
|
||||
// (not GL) reviews this smaller set before the customer may create the booking.
|
||||
// Resolved by contract-clearance.util.ts as contract_clearance_selfclear_{op}_{freight}.
|
||||
const SELF_CLEARANCE_IMPORT_FIELDS: OnboardingField[] = [
|
||||
clearanceField("customs_declaration", "Customs Declaration (IM4/IM5)", 1),
|
||||
clearanceField("import_release", "Import Release Permit", 2),
|
||||
clearanceField("duty_tax_receipt", "Duty & Tax Payment Receipt", 3, {
|
||||
required: false,
|
||||
}),
|
||||
clearanceField("delivery_order", "Delivery Order", 4, { required: false }),
|
||||
clearanceField("supporting_document", "Other Clearance Document", 5, {
|
||||
required: false,
|
||||
}),
|
||||
];
|
||||
|
||||
const SELF_CLEARANCE_EXPORT_FIELDS: OnboardingField[] = [
|
||||
clearanceField("customs_declaration", "Customs Declaration (EX3/EX8)", 1),
|
||||
clearanceField("export_release", "Export Release", 2),
|
||||
clearanceField("transit_document", "Transit Document (T1)", 3, {
|
||||
required: false,
|
||||
}),
|
||||
clearanceField("supporting_document", "Other Clearance Document", 4, {
|
||||
required: false,
|
||||
}),
|
||||
];
|
||||
|
||||
const SELF_CLEARANCE_SETTINGS: OnboardingDocumentSetting[] = [
|
||||
{
|
||||
code: "contract_clearance_selfclear_import_container",
|
||||
label: "Self-clearance documents (import container)",
|
||||
entity: CONTRACT_CLEARANCE_ENTITY,
|
||||
fields: SELF_CLEARANCE_IMPORT_FIELDS,
|
||||
},
|
||||
{
|
||||
code: "contract_clearance_selfclear_export_container",
|
||||
label: "Self-clearance documents (export container)",
|
||||
entity: CONTRACT_CLEARANCE_ENTITY,
|
||||
fields: SELF_CLEARANCE_EXPORT_FIELDS,
|
||||
},
|
||||
{
|
||||
code: "contract_clearance_selfclear_import_bulk",
|
||||
label: "Self-clearance documents (import bulk)",
|
||||
entity: CONTRACT_CLEARANCE_ENTITY,
|
||||
fields: SELF_CLEARANCE_IMPORT_FIELDS,
|
||||
},
|
||||
{
|
||||
code: "contract_clearance_selfclear_export_bulk",
|
||||
label: "Self-clearance documents (export bulk)",
|
||||
entity: CONTRACT_CLEARANCE_ENTITY,
|
||||
fields: SELF_CLEARANCE_EXPORT_FIELDS,
|
||||
},
|
||||
];
|
||||
|
||||
// ── Contract intake settings ────────────────────────────────────────────────
|
||||
// Commercial/framework documents attached at contract submission (wizard step 5),
|
||||
// distinct from the post-sign clearance docs above.
|
||||
const CONTRACT_INTAKE_ENTITY = "contract_intake";
|
||||
|
||||
const CONTRACT_INTAKE_FIELDS: OnboardingField[] = [
|
||||
clearanceField("commercial_framework", "Commercial Framework / Agreement", 1, {
|
||||
required: false,
|
||||
}),
|
||||
clearanceField("onboarding_attachment", "Onboarding Attachment", 2, {
|
||||
required: false,
|
||||
}),
|
||||
clearanceField("supporting_document", "Supporting Document", 3, {
|
||||
required: false,
|
||||
}),
|
||||
];
|
||||
|
||||
const CONTRACT_INTAKE_SETTINGS: OnboardingDocumentSetting[] = [
|
||||
{
|
||||
code: "contract_intake_documents",
|
||||
label: "Contract intake documents",
|
||||
entity: CONTRACT_INTAKE_ENTITY,
|
||||
fields: CONTRACT_INTAKE_FIELDS,
|
||||
},
|
||||
];
|
||||
|
||||
const CLEARANCE_DESCRIPTION =
|
||||
"Operation/clearance documents collected after contract execution, by operation, freight type and customs.";
|
||||
|
||||
@@ -377,6 +506,21 @@ export class FileUploadSettingsSeeder {
|
||||
...s,
|
||||
description: CLEARANCE_DESCRIPTION,
|
||||
})),
|
||||
...CONTRACT_CLEARANCE_SETTINGS.map((s) => ({
|
||||
...s,
|
||||
description:
|
||||
"Pre-booking clearance documents collected on the contract (Path B), by operation and freight type.",
|
||||
})),
|
||||
...SELF_CLEARANCE_SETTINGS.map((s) => ({
|
||||
...s,
|
||||
description:
|
||||
"Customer self-clearance documents (Path A, no EDR customs service), reviewed by Operations.",
|
||||
})),
|
||||
...CONTRACT_INTAKE_SETTINGS.map((s) => ({
|
||||
...s,
|
||||
description:
|
||||
"Commercial/framework documents attached at contract submission.",
|
||||
})),
|
||||
];
|
||||
|
||||
for (const documentSetting of allSettings) {
|
||||
|
||||
@@ -62,6 +62,26 @@ export const BOOKING_PERMISSIONS: FreightPermissionSeed[] = [
|
||||
perm('a1000001-0001-4000-8000-000000000013', 'edr_freight_app:admin', 'Freight administration'),
|
||||
];
|
||||
|
||||
/**
|
||||
* Contract-phase permissions (contract–booking separation). Mirror the booking
|
||||
* approval/sign/clearance permissions but scoped to the new contracts module.
|
||||
*/
|
||||
export const CONTRACT_PERMISSIONS: FreightPermissionSeed[] = [
|
||||
perm('a3000001-0001-4000-8000-000000000001', 'edr_freight_app:contracts:view', 'View contracts'),
|
||||
perm('a3000001-0001-4000-8000-000000000002', 'edr_freight_app:contracts:staff_accept', 'Accept contract intake'),
|
||||
perm('a3000001-0001-4000-8000-000000000003', 'edr_freight_app:contracts:request_changes', 'Request contract changes'),
|
||||
perm('a3000001-0001-4000-8000-000000000004', 'edr_freight_app:contracts:reject', 'Reject contract'),
|
||||
perm('a3000001-0001-4000-8000-000000000005', 'edr_freight_app:contracts:approve_line_staff', 'Approve contract as line staff'),
|
||||
perm('a3000001-0001-4000-8000-000000000006', 'edr_freight_app:contracts:approve_director', 'Approve contract as director'),
|
||||
perm('a3000001-0001-4000-8000-000000000007', 'edr_freight_app:contracts:approve_ceo', 'Approve contract as CEO'),
|
||||
perm('a3000001-0001-4000-8000-000000000008', 'edr_freight_app:contracts:generate_contract', 'Generate contract document'),
|
||||
perm('a3000001-0001-4000-8000-000000000009', 'edr_freight_app:contracts:sign_staff', 'Staff contract signature'),
|
||||
perm('a3000001-0001-4000-8000-00000000000a', 'edr_freight_app:contracts:clearance_review', 'Review pre-booking clearance docs'),
|
||||
perm('a3000001-0001-4000-8000-00000000000b', 'edr_freight_app:contracts:finalize_clearance', 'Finalize pre-booking clearance'),
|
||||
perm('a3000001-0001-4000-8000-00000000000c', 'edr_freight_app:contracts:create_booking', 'GL ET create booking under contract'),
|
||||
perm('a3000001-0001-4000-8000-00000000000d', 'edr_freight_app:contracts:ops_clearance_review', 'Operations review of self-clearance docs (Path A)'),
|
||||
];
|
||||
|
||||
const RULE_ENGINE_PERMISSION_IDS: Record<RuleEngineResourceSlug, { view: string; manage: string }> = {
|
||||
'cargo-types': { view: 'b2000001-0001-4000-8000-000000000001', manage: 'b2000001-0001-4000-8000-000000000002' },
|
||||
'container-types': { view: 'b2000001-0001-4000-8000-000000000003', manage: 'b2000001-0001-4000-8000-000000000004' },
|
||||
@@ -88,6 +108,7 @@ export const RULE_ENGINE_PERMISSIONS: FreightPermissionSeed[] = RULE_ENGINE_RESO
|
||||
|
||||
export const BOOKING_RULE_ENGINE_PERMISSIONS = [
|
||||
...BOOKING_PERMISSIONS,
|
||||
...CONTRACT_PERMISSIONS,
|
||||
...RULE_ENGINE_PERMISSIONS,
|
||||
];
|
||||
|
||||
@@ -114,6 +135,21 @@ export const FREIGHT_PERMS = {
|
||||
uploadClearanceOutput: 'edr_freight_app:bookings:upload_clearance_output',
|
||||
finalizeClearance: 'edr_freight_app:bookings:finalize_clearance',
|
||||
},
|
||||
contracts: {
|
||||
view: 'edr_freight_app:contracts:view',
|
||||
staffAccept: 'edr_freight_app:contracts:staff_accept',
|
||||
requestChanges: 'edr_freight_app:contracts:request_changes',
|
||||
reject: 'edr_freight_app:contracts:reject',
|
||||
approveLineStaff: 'edr_freight_app:contracts:approve_line_staff',
|
||||
approveDirector: 'edr_freight_app:contracts:approve_director',
|
||||
approveCeo: 'edr_freight_app:contracts:approve_ceo',
|
||||
generateContract: 'edr_freight_app:contracts:generate_contract',
|
||||
signStaff: 'edr_freight_app:contracts:sign_staff',
|
||||
clearanceReview: 'edr_freight_app:contracts:clearance_review',
|
||||
finalizeClearance: 'edr_freight_app:contracts:finalize_clearance',
|
||||
createBooking: 'edr_freight_app:contracts:create_booking',
|
||||
opsClearanceReview: 'edr_freight_app:contracts:ops_clearance_review',
|
||||
},
|
||||
trainScheduling: {
|
||||
view: 'edr_freight_app:train_scheduling:view',
|
||||
manage: 'edr_freight_app:train_scheduling:manage',
|
||||
@@ -146,6 +182,11 @@ export const ROLE_PERMISSION_PRESETS = {
|
||||
FREIGHT_PERMS.bookings.approveLineStaff,
|
||||
FREIGHT_PERMS.bookings.rejectApproval,
|
||||
FREIGHT_PERMS.bookings.cancel,
|
||||
FREIGHT_PERMS.contracts.view,
|
||||
FREIGHT_PERMS.contracts.staffAccept,
|
||||
FREIGHT_PERMS.contracts.requestChanges,
|
||||
FREIGHT_PERMS.contracts.reject,
|
||||
FREIGHT_PERMS.contracts.approveLineStaff,
|
||||
...allRuleEngineViewKeys(),
|
||||
],
|
||||
// Operations Officer: train scheduling + wagon allocation + transit/complete
|
||||
@@ -157,6 +198,10 @@ export const ROLE_PERMISSION_PRESETS = {
|
||||
FREIGHT_PERMS.trainScheduling.manage,
|
||||
FREIGHT_PERMS.fleet.view,
|
||||
FREIGHT_PERMS.fleet.manage,
|
||||
// Path A (no customs): Operations reviews the customer's self-clearance docs
|
||||
// on the contract before the customer may create a shipment booking.
|
||||
FREIGHT_PERMS.contracts.view,
|
||||
FREIGHT_PERMS.contracts.opsClearanceReview,
|
||||
...allRuleEngineViewKeys(),
|
||||
],
|
||||
director: [
|
||||
@@ -164,12 +209,17 @@ export const ROLE_PERMISSION_PRESETS = {
|
||||
FREIGHT_PERMS.bookings.approveDirector,
|
||||
FREIGHT_PERMS.bookings.rejectApproval,
|
||||
FREIGHT_PERMS.bookings.generateContract,
|
||||
FREIGHT_PERMS.contracts.view,
|
||||
FREIGHT_PERMS.contracts.approveDirector,
|
||||
FREIGHT_PERMS.contracts.generateContract,
|
||||
...allRuleEngineViewKeys(),
|
||||
],
|
||||
ceo: [
|
||||
FREIGHT_PERMS.bookings.view,
|
||||
FREIGHT_PERMS.bookings.approveCeo,
|
||||
FREIGHT_PERMS.bookings.rejectApproval,
|
||||
FREIGHT_PERMS.contracts.view,
|
||||
FREIGHT_PERMS.contracts.approveCeo,
|
||||
...allRuleEngineViewKeys(),
|
||||
],
|
||||
finance: [FREIGHT_PERMS.bookings.view],
|
||||
@@ -178,11 +228,28 @@ export const ROLE_PERMISSION_PRESETS = {
|
||||
// clearance:view permission lists the clearance bookings. Reviews customer
|
||||
// clearance documents, uploads customs output documents, and finalizes the
|
||||
// clearance gate.
|
||||
globalLogistics: [
|
||||
// GL Ethiopia (edr_gl_ethiopia): reviews pre-booking clearance docs on the
|
||||
// contract, uploads ET output docs, finalizes clearance, and EXCLUSIVELY creates
|
||||
// the booking under a customs contract (Path B). Also runs post-booking ET
|
||||
// milestones + the legacy booking-clearance permissions during migration.
|
||||
glEthiopia: [
|
||||
FREIGHT_PERMS.contracts.view,
|
||||
FREIGHT_PERMS.contracts.clearanceReview,
|
||||
FREIGHT_PERMS.contracts.finalizeClearance,
|
||||
FREIGHT_PERMS.contracts.createBooking,
|
||||
FREIGHT_PERMS.bookings.clearanceView,
|
||||
FREIGHT_PERMS.bookings.reviewDocuments,
|
||||
FREIGHT_PERMS.bookings.uploadClearanceOutput,
|
||||
FREIGHT_PERMS.bookings.finalizeClearance,
|
||||
FREIGHT_PERMS.bookings.operations,
|
||||
],
|
||||
// GL Djibouti (edr_gl_djibouti): DO/RO collection, gatepass, loading milestones,
|
||||
// damage reports. Read-only on the contract; no booking creation.
|
||||
glDjibouti: [
|
||||
FREIGHT_PERMS.contracts.view,
|
||||
FREIGHT_PERMS.bookings.clearanceView,
|
||||
FREIGHT_PERMS.bookings.uploadClearanceOutput,
|
||||
FREIGHT_PERMS.bookings.operations,
|
||||
],
|
||||
// Marketing handles intake through contract (same as line staff here) and,
|
||||
// for non-customs bookings, reviews/finalizes the customer's clearance
|
||||
@@ -199,6 +266,13 @@ export const ROLE_PERMISSION_PRESETS = {
|
||||
FREIGHT_PERMS.bookings.signStaff,
|
||||
FREIGHT_PERMS.bookings.reviewDocuments,
|
||||
FREIGHT_PERMS.bookings.finalizeClearance,
|
||||
FREIGHT_PERMS.contracts.view,
|
||||
FREIGHT_PERMS.contracts.staffAccept,
|
||||
FREIGHT_PERMS.contracts.requestChanges,
|
||||
FREIGHT_PERMS.contracts.reject,
|
||||
FREIGHT_PERMS.contracts.approveLineStaff,
|
||||
FREIGHT_PERMS.contracts.generateContract,
|
||||
FREIGHT_PERMS.contracts.signStaff,
|
||||
],
|
||||
orgManager: [...BOOKING_RULE_ENGINE_PERMISSION_KEYS],
|
||||
} as const;
|
||||
@@ -206,5 +280,9 @@ export const ROLE_PERMISSION_PRESETS = {
|
||||
export const PERMISSIONS_CATALOG = BOOKING_RULE_ENGINE_PERMISSIONS.map((p) => ({
|
||||
key: p.key,
|
||||
label: p.name.en,
|
||||
module: p.key.includes(':bookings:') ? 'bookings' : 'rule_engine',
|
||||
module: p.key.includes(':bookings:')
|
||||
? 'bookings'
|
||||
: p.key.includes(':contracts:')
|
||||
? 'contracts'
|
||||
: 'rule_engine',
|
||||
}));
|
||||
|
||||
@@ -18,7 +18,8 @@ const STAFF_USERS = [
|
||||
{ email: 'linestaff@edr.local', username: 'linestaff', roleKey: 'edr_line_staff' },
|
||||
{ email: 'director@edr.local', username: 'director', roleKey: 'edr_director' },
|
||||
{ email: 'ceo@edr.local', username: 'ceo', roleKey: 'edr_ceo' },
|
||||
{ email: 'gl@edr.local', username: 'gl', roleKey: 'edr_global_logistics' },
|
||||
{ email: 'gl-et@edr.local', username: 'gl_et', roleKey: 'edr_gl_ethiopia' },
|
||||
{ email: 'gl-dj@edr.local', username: 'gl_dj', roleKey: 'edr_gl_djibouti' },
|
||||
] as const;
|
||||
|
||||
@Injectable()
|
||||
|
||||
Reference in New Issue
Block a user