mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-29 22:18:12 +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.
109 lines
3.8 KiB
TypeScript
109 lines
3.8 KiB
TypeScript
import { BadRequestException } from '@nestjs/common';
|
|
import { BookingTransitionService } from './booking-transition.service';
|
|
|
|
/**
|
|
* Focused tests for the contract validity window set at the accept step.
|
|
* The backoffice must supply a number of days; the window runs from the accept
|
|
* moment through accept + N days.
|
|
*/
|
|
describe('BookingTransitionService — acceptIntake validity window', () => {
|
|
const booking = {
|
|
id: 'b-1',
|
|
status: 'SUBMITTED',
|
|
freightType: 'CONTAINER',
|
|
cargoTypeId: null,
|
|
};
|
|
|
|
function makeService() {
|
|
const bookingsRepository = {
|
|
update: jest.fn().mockResolvedValue({ id: 'b-1' }),
|
|
};
|
|
const bookingsService = {
|
|
findById: jest.fn().mockResolvedValue(booking),
|
|
};
|
|
const ruleEngineService = {
|
|
assertNoHardBlocks: jest.fn(),
|
|
};
|
|
const contractService = {
|
|
generateContract: jest.fn().mockResolvedValue({ id: 'b-1' }),
|
|
};
|
|
|
|
const service = new BookingTransitionService(
|
|
bookingsRepository as never,
|
|
ruleEngineService as never,
|
|
{} as never, // pricingService
|
|
contractService as never,
|
|
{} as never, // filesService
|
|
{} as never, // fileUploadSettingsService
|
|
{} as never, // bookingBatchService
|
|
bookingsService as never,
|
|
{ isPhasedCustomsBooking: () => false } as never,
|
|
{} as never, // workflowService
|
|
{} as never, // invoiceService
|
|
{ validate20ftPairing: jest.fn().mockResolvedValue([]) } as never,
|
|
{
|
|
accepted: jest.fn(),
|
|
approved: jest.fn(),
|
|
rejected: jest.fn(),
|
|
changesRequested: jest.fn(),
|
|
documentQueried: jest.fn(),
|
|
clearanceReady: jest.fn(),
|
|
operationChangesRequested: jest.fn(),
|
|
operationAccepted: jest.fn(),
|
|
inTransit: jest.fn(),
|
|
completed: jest.fn(),
|
|
cancelled: jest.fn(),
|
|
submittedToStaff: jest.fn(),
|
|
customerSignedToStaff: jest.fn(),
|
|
operationRequestedToStaff: jest.fn(),
|
|
clearanceDocsUploadedToStaff: jest.fn(),
|
|
dutySlipUploadedToStaff: jest.fn(),
|
|
} as never, // notifier
|
|
{ emit: jest.fn() } as never, // events
|
|
);
|
|
return { service, bookingsRepository, ruleEngineService, contractService };
|
|
}
|
|
|
|
it('rejects accept when validity days is missing or non-positive', async () => {
|
|
const { service } = makeService();
|
|
await expect(
|
|
service.acceptIntake('b-1', 'staff-1', 0),
|
|
).rejects.toBeInstanceOf(BadRequestException);
|
|
await expect(
|
|
service.acceptIntake('b-1', 'staff-1', -5),
|
|
).rejects.toBeInstanceOf(BadRequestException);
|
|
await expect(
|
|
service.acceptIntake('b-1', 'staff-1', 1.5),
|
|
).rejects.toBeInstanceOf(BadRequestException);
|
|
});
|
|
|
|
it('sets a validity window of validFrom..validFrom + N days', async () => {
|
|
const { service, bookingsRepository } = makeService();
|
|
await service.acceptIntake('b-1', 'staff-1', 10);
|
|
|
|
expect(bookingsRepository.update).toHaveBeenCalledTimes(1);
|
|
const [id, updates] = bookingsRepository.update.mock.calls[0];
|
|
expect(id).toBe('b-1');
|
|
expect(updates).toMatchObject({
|
|
status: 'APPROVED',
|
|
approvedByStaffId: 'staff-1',
|
|
contractValidityDays: 10,
|
|
});
|
|
|
|
const from = updates.contractValidFrom as Date;
|
|
const until = updates.contractValidUntil as Date;
|
|
const diffDays = Math.round(
|
|
(until.getTime() - from.getTime()) / (1000 * 60 * 60 * 24),
|
|
);
|
|
expect(diffDays).toBe(10);
|
|
// The accept timestamp and the validity start are the same moment.
|
|
expect((updates.approvedByStaffAt as Date).getTime()).toBe(from.getTime());
|
|
});
|
|
|
|
it('approves outright and generates the contract (no approval chain)', async () => {
|
|
const { service, contractService } = makeService();
|
|
await service.acceptIntake('b-1', 'staff-1', 30);
|
|
expect(contractService.generateContract).toHaveBeenCalledWith('b-1');
|
|
});
|
|
});
|