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

@@ -74,6 +74,7 @@ export class RatesRepository implements IRatesRepository {
tradeDirection?: string | null;
originYardId?: string | null;
destinationYardId?: string | null;
minKm?: number | null;
}): Promise<Rate | null> {
const qb = this.repo
.createQueryBuilder('rate')
@@ -111,6 +112,13 @@ export class RatesRepository implements IRatesRepository {
} else {
qb.andWhere('rate.destination_yard_id IS NULL');
}
// Band start distinguishes sibling last-mile bands, mirroring the
// COALESCE(min_km, -1) column of UQ_rates_pattern.
if (pattern.minKm !== null && pattern.minKm !== undefined) {
qb.andWhere('rate.min_km = :minKm', { minKm: pattern.minKm });
} else {
qb.andWhere('rate.min_km IS NULL');
}
return qb.getOne();
}