mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-09-08 14:48:18 +00:00
feat: implement shipping line bookings management
- Add ShippingLineBookingsPage for listing and managing shipping line bookings. - Create ShippingLineDocumentsModal for document uploads related to bookings. - Introduce ShippingLineInitiateModal for initiating new shipping line bookings. - Implement booking document state management with booking-doc-state utility. - Add shipping line bookings service for API interactions. - Update index to export new components and services. - Enhance types for freight to include shipping line credits.
This commit is contained in:
@@ -74,6 +74,16 @@ export interface BookingEvaluationInput {
|
||||
isGovernment?: boolean;
|
||||
allowConsolidation?: boolean;
|
||||
shippingLineId?: string | null;
|
||||
/**
|
||||
* The shipping line that OWNS this booking (`bookings.shipping_line_company_id`),
|
||||
* when it is a shipping-line booking rather than a customer one. Such a booking
|
||||
* prices exclusively off that line's own rates — see {@link ratesForOwner}.
|
||||
*
|
||||
* Not to be confused with `shippingLineId` above, which is cargo metadata
|
||||
* naming the carrier that physically moves the goods and only feeds the
|
||||
* SHIPPING_LINE double-handling trigger.
|
||||
*/
|
||||
shippingLineCompanyId?: string | null;
|
||||
/**
|
||||
* The booking's rail leg. Import overweight derives its per-ton price from
|
||||
* this route's own container freight rate, so the engine needs the yards.
|
||||
@@ -282,7 +292,10 @@ export class RuleEngineService {
|
||||
// scope) must contribute exactly ONE line. Duplicate LIVE rate rows — e.g.
|
||||
// from a non-idempotent seeder — would otherwise repeat the same surcharge
|
||||
// many times and inflate the total, so we collapse them to one row each.
|
||||
const liveRates = await this.ratesRepo.findLiveRates();
|
||||
const liveRates = this.ratesForOwner(
|
||||
await this.ratesRepo.findLiveRates(),
|
||||
input.shippingLineCompanyId,
|
||||
);
|
||||
const surchargeRates = this.dedupeRatesBySignature(
|
||||
liveRates.filter((r) => r.trigger && r.trigger !== 'ALWAYS'),
|
||||
);
|
||||
@@ -812,6 +825,28 @@ export class RuleEngineService {
|
||||
return rate.rateType ?? rate.trigger;
|
||||
}
|
||||
|
||||
/**
|
||||
* Narrow the LIVE rate pool to the ones this booking's owner may price off.
|
||||
*
|
||||
* A customer booking sees only standard rates (no owner) — a shipping line's
|
||||
* negotiated price must never leak into a customer quote. A shipping-line
|
||||
* booking sees only that line's own rates: line rates OVERRIDE the standard
|
||||
* ones rather than stacking on them, and the standard rate is deliberately
|
||||
* NOT a fallback, so a lane the line has no rate for hard-blocks downstream
|
||||
* (base freight already blocks on "no rate for this route") instead of
|
||||
* quietly billing the line at the customer price.
|
||||
*
|
||||
* Filtering once, here, is what makes the override apply uniformly: every
|
||||
* downstream lookup (base freight, derived overweight, empty return, lashing,
|
||||
* fuel, and the additive surcharges) reads from this same pool, so none of
|
||||
* them needs its own owner check.
|
||||
*/
|
||||
private ratesForOwner(rates: Rate[], shippingLineCompanyId?: string | null): Rate[] {
|
||||
return shippingLineCompanyId
|
||||
? rates.filter((r) => r.shippingLineCompanyId === shippingLineCompanyId)
|
||||
: rates.filter((r) => !r.shippingLineCompanyId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Collapse rates that describe the same charge to a single representative.
|
||||
*
|
||||
|
||||
Reference in New Issue
Block a user