mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-28 04:20:55 +00:00
enhance gate pass and freight payment handling in train scheduling
- Updated the logic in to ensure that a booking only earns its gate pass once the freight charges are settled. - Added logging for bookings that have not settled freight payment when securing gate passes. - Modified seeders to ensure that bookings have associated company profiles to prevent data inconsistencies. - Updated freight permissions to include new clearance actions for bookings. - Enhanced the UI to reflect changes in the clearance process, including new shipment request pages and improved status handling in the clearance action panel. - Adjusted the contract clearance list to accommodate both customs contracts and shipment bookings. - Improved the handling of GENERAL contracts in various components to ensure proper booking flow and visibility.
This commit is contained in:
@@ -2,6 +2,7 @@ import { Injectable, Logger } from '@nestjs/common';
|
||||
import { DataSource } from 'typeorm';
|
||||
|
||||
import { Booking } from '../modules/bookings/entities/booking.entity';
|
||||
import { CompanyProfile } from '../modules/companies/entities/company-profile.entity';
|
||||
import { ServiceType } from '../modules/rule-engine/entities/service-type.entity';
|
||||
import { Yard } from '../modules/rule-engine/entities/yard.entity';
|
||||
import { Warehouse } from '../modules/warehouses/entities/warehouse.entity';
|
||||
@@ -91,12 +92,26 @@ export class Batch5TestDataSeeder {
|
||||
return;
|
||||
}
|
||||
|
||||
// bookings.company_id AND bookings.company_profile_id are both NOT NULL, so a
|
||||
// seed booking needs an owning company profile. Resolve the profile and take
|
||||
// its company from it, so the two columns can never disagree. Without this the
|
||||
// seeder aborted on its first insert.
|
||||
const companyProfile = await this.dataSource
|
||||
.getRepository(CompanyProfile)
|
||||
.findOne({ where: {} });
|
||||
if (!companyProfile) {
|
||||
this.logger.warn('No company profile found; skipping Batch 5 seed');
|
||||
return;
|
||||
}
|
||||
|
||||
const now = new Date();
|
||||
|
||||
for (const seed of SEEDS) {
|
||||
const booking = await bookingRepo.save(
|
||||
bookingRepo.create({
|
||||
reference: seed.ref,
|
||||
companyId: companyProfile.companyId,
|
||||
companyProfileId: companyProfile.id,
|
||||
originYardId: originYard.id,
|
||||
destinationYardId: destYard.id,
|
||||
serviceTypeId: serviceType.id,
|
||||
|
||||
@@ -662,9 +662,13 @@ export const ROLE_PERMISSION_PRESETS = {
|
||||
FREIGHT_PERMS.fleet.view,
|
||||
FREIGHT_PERMS.fleet.manage,
|
||||
// Path A (no customs): Operations reviews the customer's self-clearance docs
|
||||
// on the contract before the customer may create a shipment booking.
|
||||
// — on the contract for ONE_TIME contracts, and PER BOOKING for GENERAL
|
||||
// contracts (booking-level document review → finalize → CLEARANCE_READY).
|
||||
FREIGHT_PERMS.contracts.view,
|
||||
FREIGHT_PERMS.contracts.opsClearanceReview,
|
||||
FREIGHT_PERMS.bookings.clearanceView,
|
||||
FREIGHT_PERMS.bookings.reviewDocuments,
|
||||
FREIGHT_PERMS.bookings.finalizeClearance,
|
||||
...allRuleEngineViewKeys(),
|
||||
],
|
||||
director: [
|
||||
|
||||
@@ -3,6 +3,7 @@ import { DataSource } from 'typeorm';
|
||||
|
||||
import { Booking } from '../modules/bookings/entities/booking.entity';
|
||||
import { CargoType } from '../modules/rule-engine/entities/cargo-type.entity';
|
||||
import { CompanyProfile } from '../modules/companies/entities/company-profile.entity';
|
||||
import { Locomotive } from '../modules/locomotives/entities/locomotive.entity';
|
||||
import { ServiceType } from '../modules/rule-engine/entities/service-type.entity';
|
||||
import { Yard } from '../modules/rule-engine/entities/yard.entity';
|
||||
@@ -60,10 +61,16 @@ export class WarehouseDemoSeeder {
|
||||
(await serviceTypeRepo.findOne({ where: { code: 'RAIL_CONTAINER' } })) ??
|
||||
(await serviceTypeRepo.findOne({ where: { isActive: true } }));
|
||||
const cargoType = await cargoTypeRepo.findOne({ where: { isActive: true } });
|
||||
// bookings.company_id AND company_profile_id are both NOT NULL — a demo booking
|
||||
// still needs an owner. Take the company from the profile so they always agree.
|
||||
const companyProfile = await this.dataSource
|
||||
.getRepository(CompanyProfile)
|
||||
.findOne({ where: {} });
|
||||
|
||||
if (!djibYard || !ethYard || !serviceType) {
|
||||
if (!djibYard || !ethYard || !serviceType || !companyProfile) {
|
||||
this.logger.warn(
|
||||
`Missing yards/service type (djib=${djibYard?.code}, eth=${ethYard?.code}, svc=${serviceType?.code}); skipping`,
|
||||
`Missing yards/service type/company profile (djib=${djibYard?.code}, eth=${ethYard?.code}, ` +
|
||||
`svc=${serviceType?.code}, companyProfile=${companyProfile?.id ?? 'none'}); skipping`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -89,7 +96,7 @@ export class WarehouseDemoSeeder {
|
||||
): Promise<Booking> =>
|
||||
bookingRepo.save(
|
||||
bookingRepo.create({
|
||||
...this.demoBookingDefaults(),
|
||||
...this.demoBookingDefaults(companyProfile),
|
||||
reference,
|
||||
originYardId: direction === 'EXPORT' ? ethYard.id : djibYard.id,
|
||||
destinationYardId: direction === 'EXPORT' ? djibYard.id : ethYard.id,
|
||||
@@ -182,7 +189,15 @@ export class WarehouseDemoSeeder {
|
||||
}
|
||||
|
||||
// 6) Import Arrive Queue — an ARRIVED import train with IN_TRANSIT bookings, no inventory yet.
|
||||
await this.seedArrivedImportTrain(djibYard, ethYard, serviceType, cargoType, ago(60), ago(360));
|
||||
await this.seedArrivedImportTrain(
|
||||
djibYard,
|
||||
ethYard,
|
||||
serviceType,
|
||||
cargoType,
|
||||
companyProfile,
|
||||
ago(60),
|
||||
ago(360),
|
||||
);
|
||||
created += 1;
|
||||
|
||||
this.logger.log(`✅ Warehouse demo seeded: ${created} buckets populated across every queue`);
|
||||
@@ -199,6 +214,7 @@ export class WarehouseDemoSeeder {
|
||||
ethYard: Yard,
|
||||
serviceType: ServiceType,
|
||||
cargoType: CargoType | null,
|
||||
owner: CompanyProfile,
|
||||
arrival: Date,
|
||||
departure: Date,
|
||||
): Promise<void> {
|
||||
@@ -238,7 +254,7 @@ export class WarehouseDemoSeeder {
|
||||
for (let i = 1; i <= 3; i++) {
|
||||
const b = await bookingRepo.save(
|
||||
bookingRepo.create({
|
||||
...this.demoBookingDefaults(),
|
||||
...this.demoBookingDefaults(owner),
|
||||
reference: `WH-DEMO-ARR-${i}`,
|
||||
originYardId: djibYard.id,
|
||||
destinationYardId: ethYard.id,
|
||||
@@ -258,8 +274,10 @@ export class WarehouseDemoSeeder {
|
||||
}
|
||||
}
|
||||
|
||||
private demoBookingDefaults(): Partial<Booking> {
|
||||
private demoBookingDefaults(owner: CompanyProfile): Partial<Booking> {
|
||||
return {
|
||||
companyId: owner.companyId,
|
||||
companyProfileId: owner.id,
|
||||
scheduledDate: new Date(),
|
||||
contractType: 'SPOT',
|
||||
equipmentReturn: 'TERMINAL',
|
||||
|
||||
Reference in New Issue
Block a user