mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-27 00:52:50 +00:00
- Added functionality to cancel contracts, allowing users to provide a reason for cancellation. - Updated contract statuses to include SUSPENDED and changed CLOSED to COMPLETED. - Enhanced the UI to reflect the new cancellation option and updated messaging for contract statuses. - Refactored contract booking actions to accommodate changes in booking logic for ONE_TIME and GENERAL contracts. - Removed clearance document management from the contract detail page, as it is now handled per booking. - Introduced a SQL script to reset bookings and train schedules for development purposes.
80 lines
2.6 KiB
TypeScript
80 lines
2.6 KiB
TypeScript
import { ConflictException } from '@nestjs/common';
|
|
|
|
import { ContractsService } from './contracts.service';
|
|
import type { CreateContractDto } from './dto/create-contract.dto';
|
|
|
|
/**
|
|
* The duplicate guard blocks a new request only when EVERY commercial
|
|
* dimension matches a live contract — service type, operation type, contract
|
|
* kind, cargo scope and route. Any one differing must let the request through.
|
|
*/
|
|
describe('ContractsService duplicate guard', () => {
|
|
const LANE = { originYardId: 'yard-dj', destinationYardId: 'yard-mj' };
|
|
|
|
const existing = {
|
|
id: 'c-1',
|
|
reference: 'CTR-2026-00001',
|
|
status: 'PENDING_APPROVAL',
|
|
contractValidUntil: null,
|
|
tradeDirection: 'IMPORT',
|
|
contractKind: 'ONE_TIME',
|
|
freightType: 'CONTAINER',
|
|
routes: [LANE],
|
|
cargoScope: [{ containerSize: '20ft' }, { containerSize: '40ft' }],
|
|
};
|
|
|
|
const dto = (overrides: Partial<CreateContractDto> = {}) =>
|
|
({
|
|
serviceTypeId: 'svc-1',
|
|
tradeDirection: 'IMPORT',
|
|
contractKind: 'ONE_TIME',
|
|
freightType: 'CONTAINER',
|
|
routes: [LANE],
|
|
cargoScope: [{ containerSize: '20ft' }, { containerSize: '40ft' }],
|
|
...overrides,
|
|
}) as CreateContractDto;
|
|
|
|
const guard = (input: CreateContractDto) => {
|
|
const service = new ContractsService(
|
|
{} as never,
|
|
{ findDuplicateCandidates: async () => [existing] } as never,
|
|
{} as never,
|
|
{} as never,
|
|
{} as never,
|
|
{} as never,
|
|
);
|
|
return (
|
|
service as unknown as {
|
|
assertNoDuplicateContract(companyId: string, dto: CreateContractDto): Promise<void>;
|
|
}
|
|
).assertNoDuplicateContract('company-1', input);
|
|
};
|
|
|
|
it('blocks an identical request', async () => {
|
|
await expect(guard(dto())).rejects.toBeInstanceOf(ConflictException);
|
|
});
|
|
|
|
it.each([
|
|
['operation type', { tradeDirection: 'EXPORT' }],
|
|
['contract kind', { contractKind: 'GENERAL' }],
|
|
['freight type', { freightType: 'BULK' }],
|
|
['cargo scope', { cargoScope: [{ containerSize: '20ft' }] }],
|
|
['route', { routes: [{ originYardId: 'yard-dj', destinationYardId: 'yard-aa' }] }],
|
|
])('allows a request with a different %s', async (_label, overrides) => {
|
|
await expect(guard(dto(overrides as Partial<CreateContractDto>))).resolves.toBeUndefined();
|
|
});
|
|
|
|
it('ignores quantity caps when comparing cargo scope', async () => {
|
|
await expect(
|
|
guard(
|
|
dto({
|
|
cargoScope: [
|
|
{ containerSize: '20ft', quantityCap: 10 },
|
|
{ containerSize: '40ft', quantityCap: 5 },
|
|
],
|
|
}),
|
|
),
|
|
).rejects.toBeInstanceOf(ConflictException);
|
|
});
|
|
});
|