mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-09-07 14:15:44 +00:00
feat: Implement container hazardous-cargo surcharge logic
- Added support for container hazardous-cargo surcharge (HAZARDOUS billed PER_CONTAINER) in the rule engine. - Introduced new method in to calculate and apply container hazard charges based on booking details. - Updated to handle per-container hazard rates, ensuring they are scoped by trade direction and lane. - Enhanced tests to cover scenarios for container hazard rates, including validation for required fields and conflict checks. - Created a migration to update existing rates and enforce new constraints for container hazard rates in the database.
This commit is contained in:
@@ -88,6 +88,10 @@ export type RateAppliesTo = typeof RATE_APPLIES_TO[number];
|
||||
*/
|
||||
export const RATE_TRIGGERS = [
|
||||
'ALWAYS',
|
||||
// Hazardous cargo. Two shapes under one trigger, told apart by the unit:
|
||||
// PER_CONTAINER is the container surcharge, sold per direction + lane and
|
||||
// optionally per box size (20ft / 40ft) like the empty-return service;
|
||||
// PER_TON is the bulk surcharge, direction-agnostic and unscoped.
|
||||
'HAZARDOUS',
|
||||
'OVERWEIGHT',
|
||||
'REEFER',
|
||||
@@ -121,6 +125,16 @@ export type RateTrigger = typeof RATE_TRIGGERS[number];
|
||||
export const isCustomsClearanceTrigger = (trigger: string): boolean =>
|
||||
trigger === 'CUSTOMS_CLEARANCE' || trigger === 'ETHIOPIAN_CUSTOMS_CLEARANCE';
|
||||
|
||||
/**
|
||||
* The container hazardous-cargo surcharge: HAZARDOUS billed per container.
|
||||
* It is sold per trade direction + origin → destination lane, optionally
|
||||
* narrowed to one container type (20ft / 40ft), and priced by the
|
||||
* route-matched block in RuleEngineService — never by the additive loop.
|
||||
* The per-ton (bulk) hazard rate keeps the old global, unscoped shape.
|
||||
*/
|
||||
export const isContainerHazardRate = (trigger: string, rateUnit: string): boolean =>
|
||||
trigger === 'HAZARDOUS' && rateUnit === 'PER_CONTAINER';
|
||||
|
||||
@Entity({ schema: 'freight', name: 'rates' })
|
||||
@Index(['rateType'])
|
||||
@Index(['status'])
|
||||
@@ -159,8 +173,10 @@ export class Rate extends BaseEntity {
|
||||
/**
|
||||
* The leg this rate prices. Base freight (trigger = ALWAYS) is quoted per
|
||||
* route — "container import, Djibouti → Dire Dawa" — so both yards are
|
||||
* required for BULK/CONTAINER/INTERCITY and NULL for everything else. The
|
||||
* `CK_rates_yard_scope` DB constraint enforces both halves of that.
|
||||
* required for BULK/CONTAINER/EMPTY_CONTAINER/INTERCITY, for the lane-sold
|
||||
* surcharges (customs clearance, empty return, fuel, container hazard) and
|
||||
* NULL for everything else. The `CK_rates_yard_scope` DB constraint enforces
|
||||
* both halves of that.
|
||||
*/
|
||||
@Column({ name: 'origin_yard_id', type: 'uuid', nullable: true })
|
||||
originYardId?: string | null;
|
||||
|
||||
Reference in New Issue
Block a user