feat(rates): last-mile rate rules with bulk per-ton-km and container distance bands

- rates: min_km/max_km columns, PER_TON_KM unit, ETB|USD currency for last mile
- extend UQ_rates_pattern with band start; overlap + shape validation
- shared last-mile charge resolver; approve-dialog price estimate endpoint
- delivery-fee invoice prices via rules, falls back to vehicle price/km
- backoffice: last-mile rate form (mode, container type, band, currency)
This commit is contained in:
Hagernesh
2026-08-05 22:12:40 +00:00
parent 6125f644b1
commit 5c8c68e990
25 changed files with 880 additions and 20 deletions

View File

@@ -39,6 +39,8 @@ export const RATE_UNITS = [
'PER_ITEM',
'PER_CONTAINER',
'PER_KM',
// Last-mile bulk: price = tons × km × rateValue.
'PER_TON_KM',
'PER_INVOICE',
'FLAT',
] as const;
@@ -156,6 +158,17 @@ export class Rate extends BaseEntity {
@Column({ name: 'rate_unit', type: 'varchar', length: 30 })
rateUnit!: RateUnit;
/**
* Distance band for container last-mile rates (rateUnit = PER_KM, scoped by
* containerTypeId): the rate applies when minKm <= km < maxKm (maxKm NULL =
* open-ended). NULL on every other rate shape.
*/
@Column({ name: 'min_km', type: 'numeric', precision: 10, scale: 2, nullable: true })
minKm?: number | null;
@Column({ name: 'max_km', type: 'numeric', precision: 10, scale: 2, nullable: true })
maxKm?: number | null;
@Column({ name: 'status', type: 'varchar', length: 20, default: 'DRAFT' })
status!: RateStatus;