mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-09-09 04:48:18 +00:00
Merge branch 'freight_feature/profile' of github.com:Tria-plc/edr-platform into freight_feature/profile
This commit is contained in:
@@ -8,7 +8,6 @@ import { PriorityConfig } from "../modules/rule-engine/entities/priority-config.
|
||||
import { Rate } from "../modules/rule-engine/entities/rate.entity";
|
||||
import { ServiceType } from "../modules/rule-engine/entities/service-type.entity";
|
||||
import { ShippingLine } from "../modules/rule-engine/entities/shipping-line.entity";
|
||||
import { SurchargeType } from "../modules/rule-engine/entities/surcharge-type.entity";
|
||||
import { WeightLimitRule } from "../modules/rule-engine/entities/weight-limit-rule.entity";
|
||||
import { Route } from "../modules/routes/entities/route.entity";
|
||||
import { RouteMilestone } from "../modules/routes/entities/route-milestone.entity";
|
||||
@@ -40,15 +39,13 @@ export class PricingDataSeeder {
|
||||
const containerTypes = await ctRepo.find();
|
||||
const ctByCode = new Map(containerTypes.map((ct) => [ct.code, ct]));
|
||||
|
||||
const rates = await this.seedRates(rRepo, ctByCode);
|
||||
const ratesByType = new Map<string, Rate[]>();
|
||||
for (const r of rates) {
|
||||
const key = `${r.rateType}|${r.currency}|${r.containerTypeId ?? ""}`;
|
||||
if (!ratesByType.has(key)) ratesByType.set(key, []);
|
||||
ratesByType.get(key)!.push(r);
|
||||
}
|
||||
// Clear booking cargo modifiers up front — they reference rate snapshots
|
||||
// that get recomputed when bookings are repriced.
|
||||
await manager.getRepository(BookingCargoModifier).createQueryBuilder().delete().execute();
|
||||
|
||||
await this.seedSurchargeTypes(manager, ratesByType);
|
||||
const cargoTypesForRates = await manager.getRepository(CargoType).find();
|
||||
const cargoForRatesByCode = new Map(cargoTypesForRates.map((c) => [c.code, c]));
|
||||
await this.seedRates(rRepo, ctByCode, cargoForRatesByCode);
|
||||
|
||||
const yards = await yRepo.find();
|
||||
const yardByCode = new Map(yards.map((y) => [y.code, y]));
|
||||
@@ -422,135 +419,43 @@ private async seedWeightLimits(wlRepo: any, ctRepo: any): Promise<void> {
|
||||
private async seedRates(
|
||||
rRepo: any,
|
||||
ctByCode: Map<string, any>,
|
||||
cargoByCode: Map<string, any>,
|
||||
): Promise<Rate[]> {
|
||||
const effectiveFrom = new Date("2026-01-01");
|
||||
const now = new Date();
|
||||
// await rRepo.createQueryBuilder().delete().execute();
|
||||
|
||||
// Each rate is self-describing: `appliesTo` + `trigger` decide how the
|
||||
// engine uses it. trigger=ALWAYS → base freight; anything else → a
|
||||
// surcharge that stacks additively when the booking matches.
|
||||
const rateData = [
|
||||
{
|
||||
rateType: "CONTAINER_IMPORT",
|
||||
containerTypeId: ctByCode.get("20FT")!.id,
|
||||
currency: "USD",
|
||||
rateValue: 800,
|
||||
rateUnit: "PER_CONTAINER",
|
||||
},
|
||||
{
|
||||
rateType: "CONTAINER_IMPORT",
|
||||
containerTypeId: ctByCode.get("40FT")!.id,
|
||||
currency: "USD",
|
||||
rateValue: 1200,
|
||||
rateUnit: "PER_CONTAINER",
|
||||
},
|
||||
{
|
||||
rateType: "CONTAINER_EXPORT",
|
||||
containerTypeId: ctByCode.get("20FT")!.id,
|
||||
currency: "USD",
|
||||
rateValue: 600,
|
||||
rateUnit: "PER_CONTAINER",
|
||||
},
|
||||
{
|
||||
rateType: "CONTAINER_EXPORT",
|
||||
containerTypeId: ctByCode.get("40FT")!.id,
|
||||
currency: "USD",
|
||||
rateValue: 900,
|
||||
rateUnit: "PER_CONTAINER",
|
||||
},
|
||||
{
|
||||
rateType: "CONTAINER_IMPORT",
|
||||
containerTypeId: null,
|
||||
currency: "USD",
|
||||
rateValue: 1000,
|
||||
rateUnit: "PER_CONTAINER",
|
||||
},
|
||||
{
|
||||
rateType: "CONTAINER_EXPORT",
|
||||
containerTypeId: null,
|
||||
currency: "USD",
|
||||
rateValue: 750,
|
||||
rateUnit: "PER_CONTAINER",
|
||||
},
|
||||
{
|
||||
rateType: "INTERCITY_CONTAINER",
|
||||
containerTypeId: ctByCode.get("20FT")!.id,
|
||||
currency: "USD",
|
||||
rateValue: 350,
|
||||
rateUnit: "PER_CONTAINER",
|
||||
},
|
||||
{
|
||||
rateType: "INTERCITY_CONTAINER",
|
||||
containerTypeId: ctByCode.get("40FT")!.id,
|
||||
currency: "USD",
|
||||
rateValue: 550,
|
||||
rateUnit: "PER_CONTAINER",
|
||||
},
|
||||
{
|
||||
rateType: "INTERCITY_CONTAINER",
|
||||
containerTypeId: null,
|
||||
currency: "USD",
|
||||
rateValue: 400,
|
||||
rateUnit: "PER_CONTAINER",
|
||||
},
|
||||
{
|
||||
rateType: "INTERCITY_BULK",
|
||||
containerTypeId: null,
|
||||
currency: "USD",
|
||||
rateValue: 35,
|
||||
rateUnit: "PER_TON",
|
||||
},
|
||||
{
|
||||
rateType: "BULK_IMPORT",
|
||||
containerTypeId: null,
|
||||
currency: "USD",
|
||||
rateValue: 50,
|
||||
rateUnit: "PER_TON",
|
||||
},
|
||||
{
|
||||
rateType: "BULK_EXPORT",
|
||||
containerTypeId: null,
|
||||
currency: "USD",
|
||||
rateValue: 40,
|
||||
rateUnit: "PER_TON",
|
||||
},
|
||||
{
|
||||
rateType: "OVERWEIGHT_PER_TON",
|
||||
containerTypeId: null,
|
||||
currency: "USD",
|
||||
rateValue: 25,
|
||||
rateUnit: "PER_TON",
|
||||
},
|
||||
{
|
||||
rateType: "HAZARD_SURCHARGE",
|
||||
containerTypeId: null,
|
||||
currency: "USD",
|
||||
rateValue: 150,
|
||||
rateUnit: "FLAT",
|
||||
},
|
||||
{
|
||||
rateType: "REEFER_SURCHARGE",
|
||||
containerTypeId: null,
|
||||
currency: "USD",
|
||||
rateValue: 200,
|
||||
rateUnit: "FLAT",
|
||||
},
|
||||
{
|
||||
rateType: "DOUBLE_HANDLING",
|
||||
containerTypeId: null,
|
||||
currency: "USD",
|
||||
rateValue: 100,
|
||||
rateUnit: "PER_CONTAINER",
|
||||
},
|
||||
{
|
||||
rateType: "LASHING",
|
||||
containerTypeId: null,
|
||||
currency: "USD",
|
||||
rateValue: 50,
|
||||
rateUnit: "PER_CONTAINER",
|
||||
},
|
||||
// ── Container base freight ──────────────────────────────────────────
|
||||
{ appliesTo: "CONTAINER", trigger: "ALWAYS", rateType: "CONTAINER_IMPORT", tradeDirection: "IMPORT", containerTypeId: ctByCode.get("20FT")!.id, rateValue: 800, rateUnit: "PER_CONTAINER" },
|
||||
{ appliesTo: "CONTAINER", trigger: "ALWAYS", rateType: "CONTAINER_IMPORT", tradeDirection: "IMPORT", containerTypeId: ctByCode.get("40FT")!.id, rateValue: 1200, rateUnit: "PER_CONTAINER" },
|
||||
{ appliesTo: "CONTAINER", trigger: "ALWAYS", rateType: "CONTAINER_EXPORT", tradeDirection: "EXPORT", containerTypeId: ctByCode.get("20FT")!.id, rateValue: 600, rateUnit: "PER_CONTAINER" },
|
||||
{ appliesTo: "CONTAINER", trigger: "ALWAYS", rateType: "CONTAINER_EXPORT", tradeDirection: "EXPORT", containerTypeId: ctByCode.get("40FT")!.id, rateValue: 900, rateUnit: "PER_CONTAINER" },
|
||||
{ appliesTo: "CONTAINER", trigger: "ALWAYS", rateType: "CONTAINER_IMPORT", tradeDirection: "IMPORT", containerTypeId: null, rateValue: 1000, rateUnit: "PER_CONTAINER" },
|
||||
{ appliesTo: "CONTAINER", trigger: "ALWAYS", rateType: "CONTAINER_EXPORT", tradeDirection: "EXPORT", containerTypeId: null, rateValue: 750, rateUnit: "PER_CONTAINER" },
|
||||
// ── Intercity base freight ──────────────────────────────────────────
|
||||
{ appliesTo: "INTERCITY", trigger: "ALWAYS", rateType: "INTERCITY_CONTAINER", containerTypeId: ctByCode.get("20FT")!.id, rateValue: 350, rateUnit: "PER_CONTAINER" },
|
||||
{ appliesTo: "INTERCITY", trigger: "ALWAYS", rateType: "INTERCITY_CONTAINER", containerTypeId: ctByCode.get("40FT")!.id, rateValue: 550, rateUnit: "PER_CONTAINER" },
|
||||
{ appliesTo: "INTERCITY", trigger: "ALWAYS", rateType: "INTERCITY_CONTAINER", containerTypeId: null, rateValue: 400, rateUnit: "PER_CONTAINER" },
|
||||
{ appliesTo: "INTERCITY", trigger: "ALWAYS", rateType: "INTERCITY_BULK", rateValue: 35, rateUnit: "PER_TON" },
|
||||
// ── Bulk base freight (by leaf cargo type where known) ──────────────
|
||||
{ appliesTo: "BULK", trigger: "ALWAYS", rateType: "BULK_IMPORT", tradeDirection: "IMPORT", cargoTypeId: cargoByCode.get("GRAIN")?.id ?? null, rateValue: 50, rateUnit: "PER_TON" },
|
||||
{ appliesTo: "BULK", trigger: "ALWAYS", rateType: "BULK_EXPORT", tradeDirection: "EXPORT", cargoTypeId: cargoByCode.get("GRAIN")?.id ?? null, rateValue: 40, rateUnit: "PER_TON" },
|
||||
{ appliesTo: "BULK", trigger: "ALWAYS", rateType: "BULK_IMPORT", tradeDirection: "IMPORT", cargoTypeId: null, rateValue: 50, rateUnit: "PER_TON" },
|
||||
{ appliesTo: "BULK", trigger: "ALWAYS", rateType: "BULK_EXPORT", tradeDirection: "EXPORT", cargoTypeId: null, rateValue: 40, rateUnit: "PER_TON" },
|
||||
// ── Surcharges (trigger-based) ──────────────────────────────────────
|
||||
{ appliesTo: "OTHER", trigger: "OVERWEIGHT", rateType: "OVERWEIGHT_PER_TON", rateValue: 25, rateUnit: "PER_TON" },
|
||||
{ appliesTo: "OTHER", trigger: "HAZARDOUS", rateType: "HAZARD_SURCHARGE", rateValue: 150, rateUnit: "FLAT" },
|
||||
{ appliesTo: "OTHER", trigger: "REEFER", rateType: "REEFER_SURCHARGE", rateValue: 200, rateUnit: "FLAT" },
|
||||
{ appliesTo: "OTHER", trigger: "SHIPPING_LINE", rateType: "DOUBLE_HANDLING", rateValue: 100, rateUnit: "PER_CONTAINER" },
|
||||
{ appliesTo: "OTHER", trigger: "CONSOLIDATION", rateType: "LASHING", rateValue: 50, rateUnit: "PER_CONTAINER" },
|
||||
];
|
||||
|
||||
const entities = rateData.map((d) =>
|
||||
rRepo.create({
|
||||
currency: "USD",
|
||||
...d,
|
||||
status: "LIVE",
|
||||
proposedByStaffId: STAFF_USER_ID,
|
||||
@@ -562,66 +467,6 @@ private async seedWeightLimits(wlRepo: any, ctRepo: any): Promise<void> {
|
||||
return rRepo.save(entities);
|
||||
}
|
||||
|
||||
private async seedSurchargeTypes(
|
||||
manager: any,
|
||||
ratesByType: Map<string, Rate[]>,
|
||||
): Promise<void> {
|
||||
const surRepo = manager.getRepository(SurchargeType);
|
||||
const bcmRepo = manager.getRepository(BookingCargoModifier);
|
||||
await bcmRepo.createQueryBuilder().delete().execute();
|
||||
const findRate = (rateType: string, currency: string) => {
|
||||
const key = `${rateType}|${currency}|`;
|
||||
const rates = ratesByType.get(key);
|
||||
return rates?.[0];
|
||||
};
|
||||
|
||||
const hazardRateUsd = findRate("HAZARD_SURCHARGE", "USD");
|
||||
const reeferRateUsd = findRate("REEFER_SURCHARGE", "USD");
|
||||
const overweightRateUsd = findRate("OVERWEIGHT_PER_TON", "USD");
|
||||
const shipLineRateUsd = findRate("DOUBLE_HANDLING", "USD");
|
||||
const consolidRateUsd = findRate("LASHING", "USD");
|
||||
|
||||
await surRepo.createQueryBuilder().delete().execute();
|
||||
await surRepo.save([
|
||||
surRepo.create({
|
||||
code: "HAZARDOUS_CARGO",
|
||||
label: "Hazardous Cargo",
|
||||
triggerCondition: "CARGO_FLAG_HAZARDOUS",
|
||||
rateId: hazardRateUsd?.id,
|
||||
isActive: true,
|
||||
}),
|
||||
surRepo.create({
|
||||
code: "REEFER_CARGO",
|
||||
label: "Reefer Cargo",
|
||||
triggerCondition: "CARGO_FLAG_REEFER",
|
||||
rateId: reeferRateUsd?.id,
|
||||
isActive: true,
|
||||
}),
|
||||
surRepo.create({
|
||||
code: "OVERWEIGHT_CARGO",
|
||||
label: "Overweight Cargo",
|
||||
triggerCondition: "VGM_EXCEEDS_LIMIT",
|
||||
rateId: overweightRateUsd?.id,
|
||||
isActive: true,
|
||||
}),
|
||||
surRepo.create({
|
||||
code: "SHIPPING_LINE_FEE",
|
||||
label: "Shipping Line Fee",
|
||||
triggerCondition: "SHIPPING_LINE_MAPPED",
|
||||
rateId: shipLineRateUsd?.id,
|
||||
isActive: true,
|
||||
}),
|
||||
surRepo.create({
|
||||
code: "CONSOLIDATION_FEE",
|
||||
label: "Consolidation Fee",
|
||||
triggerCondition: "CONSOLIDATION_ENABLED",
|
||||
rateId: consolidRateUsd?.id,
|
||||
isActive: true,
|
||||
}),
|
||||
]);
|
||||
this.logger.log("Seeded surcharge types");
|
||||
}
|
||||
|
||||
private async seedDraftBookings(
|
||||
ctByCode: Map<string, any>,
|
||||
yardByCode: Map<string, any>,
|
||||
|
||||
Reference in New Issue
Block a user