mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-27 17:50:54 +00:00
- Added functionality to move containers between wagons in the train scheduling system. - Introduced API endpoint and service method to handle container movement. - Updated component to support drag-and-drop for rearranging containers. - Enhanced to allow moving containers to other wagons via a context menu. - Implemented UI feedback for container movement actions, including loading states and success/error notifications. - Updated relevant types and constants to accommodate new container movement logic. - Added tests for the rule engine to ensure proper handling of hazardous bookings.
79 lines
2.7 KiB
TypeScript
79 lines
2.7 KiB
TypeScript
import { RuleEngineService } from './rule-engine.service';
|
|
import type { BookingEvaluationInput } from './rule-engine.service';
|
|
import type { Rate } from './entities/rate.entity';
|
|
|
|
describe('RuleEngineService — requested service without a configured surcharge rate', () => {
|
|
const hazardRate: Rate = {
|
|
id: 'rate-hazard',
|
|
rateType: 'HAZARD_SURCHARGE',
|
|
trigger: 'HAZARDOUS',
|
|
rateValue: 50,
|
|
rateUnit: 'PER_CONTAINER',
|
|
currency: 'USD',
|
|
status: 'LIVE',
|
|
containerTypeId: null,
|
|
cargoTypeId: null,
|
|
} as Rate;
|
|
|
|
let ratesRepo: { findLiveRates: jest.Mock };
|
|
let service: RuleEngineService;
|
|
|
|
beforeEach(() => {
|
|
ratesRepo = { findLiveRates: jest.fn().mockResolvedValue([]) };
|
|
service = new RuleEngineService(
|
|
{ findById: jest.fn().mockResolvedValue(null) } as never, // cargoTypes
|
|
{ findById: jest.fn().mockResolvedValue(null) } as never, // serviceTypes
|
|
{ findActiveByContainerTypeId: jest.fn().mockResolvedValue([]) } as never, // weightLimits
|
|
{ findAllActive: jest.fn().mockResolvedValue([]) } as never, // priorityConfigs
|
|
ratesRepo as never,
|
|
{ findById: jest.fn().mockResolvedValue(null) } as never, // shippingLines
|
|
{} as never, // dataSource (unused by evaluate)
|
|
);
|
|
});
|
|
|
|
const input = (overrides: Partial<BookingEvaluationInput>): BookingEvaluationInput => ({
|
|
serviceTypeId: 'svc-1',
|
|
paymentCurrency: 'USD',
|
|
tradeDirection: 'IMPORT',
|
|
isHazardous: false,
|
|
totalWagons: 1,
|
|
containers: [],
|
|
...overrides,
|
|
});
|
|
|
|
it('hard-blocks a hazardous booking when no HAZARDOUS surcharge rate is LIVE', async () => {
|
|
const result = await service.evaluate(input({ isHazardous: true }));
|
|
expect(result.hardBlocked).toHaveLength(1);
|
|
expect(result.hardBlocked[0]).toContain('hazardous');
|
|
});
|
|
|
|
it('passes a hazardous booking when a HAZARDOUS surcharge rate is LIVE', async () => {
|
|
ratesRepo.findLiveRates.mockResolvedValue([hazardRate]);
|
|
const result = await service.evaluate(input({ isHazardous: true }));
|
|
expect(result.hardBlocked).toHaveLength(0);
|
|
});
|
|
|
|
it('does not block a non-hazardous booking when no surcharge rates exist', async () => {
|
|
const result = await service.evaluate(input({}));
|
|
expect(result.hardBlocked).toHaveLength(0);
|
|
});
|
|
|
|
it('hard-blocks on per-container opt-in counts even without the booking-level flag', async () => {
|
|
const result = await service.evaluate(
|
|
input({
|
|
containers: [
|
|
{
|
|
containerTypeId: 'ct-20',
|
|
quantity: 2,
|
|
vgmPerUnitTons: 10,
|
|
totalVgmTons: 20,
|
|
reeferQuantity: 1,
|
|
},
|
|
],
|
|
}),
|
|
);
|
|
expect(result.hardBlocked).toHaveLength(1);
|
|
expect(result.hardBlocked[0]).toContain('reefer');
|
|
});
|
|
});
|