This commit is contained in:
marshal
2026-07-01 20:55:17 +03:00
parent 612df8daff
commit 9c18d086d7
112 changed files with 5654 additions and 1370 deletions

View File

@@ -5,6 +5,7 @@ import { ClearanceWorkflowService } from './clearance-workflow.service';
import type { ClearanceMilestone } from './entities/clearance-milestone.entity';
import type { Contract } from './entities/contract.entity';
import type { ContractClearanceCycle } from './entities/contract-clearance-cycle.entity';
import type { Booking } from '../bookings/entities/booking.entity';
function ms(
code: string,
@@ -37,15 +38,18 @@ function makeService(milestones: ClearanceMilestone[]) {
};
const milestoneService = {
listForContract: jest.fn().mockResolvedValue(milestones),
listForBooking: jest.fn().mockResolvedValue(milestones),
skipForContract: jest.fn(),
completeForContract: jest.fn(),
completeWithMetadataForContract: jest.fn(),
};
const bookingsRepository = { update: jest.fn() };
const service = new ClearanceWorkflowService(
contractsRepository as never,
milestoneService as never,
bookingsRepository as never,
);
return { service, milestoneService, contractsRepository };
return { service, milestoneService, contractsRepository, bookingsRepository };
}
const importContract = {
@@ -199,7 +203,7 @@ describe('ClearanceWorkflowService', () => {
expect(next?.milestoneCode).toBe('TRANSIT_PERMIT_UPLOADED');
});
it('prompts DJ for DO then ET booking when pre-booking complete', () => {
it('prompts ET to finalize pre-clearance after transit permit', () => {
const milestones = [
ms('IMPORT_DOCS_UPLOADED', 'COMPLETED', 'CUST'),
ms('DOCUMENTS_APPROVED', 'COMPLETED', 'ET'),
@@ -211,6 +215,26 @@ describe('ClearanceWorkflowService', () => {
];
const cycle = { dutyRequired: false } as ContractClearanceCycle;
const { service } = makeService(milestones);
const next = service.computeNextAction(importContract, cycle, milestones);
expect(next?.actor).toBe('GL_ET');
expect(next?.action).toMatch(/finalize pre-clearance/i);
});
it('prompts DJ for DO then ET booking when pre-booking complete', () => {
const milestones = [
ms('IMPORT_DOCS_UPLOADED', 'COMPLETED', 'CUST'),
ms('DOCUMENTS_APPROVED', 'COMPLETED', 'ET'),
ms('DECLARED', 'COMPLETED', 'ET'),
ms('DUTY_TAXES_ADVISED', 'SKIPPED', 'ET'),
ms('DUTY_TAX_PAID', 'SKIPPED', 'CUST'),
ms('TRANSIT_PERMIT_UPLOADED', 'COMPLETED', 'ET'),
ms('DO_COLLECTED', 'PENDING', 'DJ'),
];
const cycle = {
dutyRequired: false,
preClearanceFinalizedAt: new Date(),
} as ContractClearanceCycle;
const { service } = makeService(milestones);
const djNext = service.computeNextAction(importContract, cycle, milestones);
expect(djNext?.actor).toBe('GL_DJ');
@@ -281,4 +305,27 @@ describe('ClearanceWorkflowService', () => {
).toBe('DO_COLLECTED');
});
});
describe('computeNextActionForBooking', () => {
it('prompts customer to proceed after import boundary on booking', () => {
const booking = {
tradeDirection: 'IMPORT',
dutyRequired: false,
preClearanceFinalizedAt: new Date(),
} as Booking;
const milestones = [
ms('IMPORT_DOCS_UPLOADED', 'COMPLETED', 'CUST'),
ms('DOCUMENTS_APPROVED', 'COMPLETED', 'ET'),
ms('DECLARED', 'COMPLETED', 'ET'),
ms('DUTY_TAXES_ADVISED', 'SKIPPED', 'ET'),
ms('DUTY_TAX_PAID', 'SKIPPED', 'CUST'),
ms('TRANSIT_PERMIT_UPLOADED', 'COMPLETED', 'ET'),
ms('DO_COLLECTED', 'COMPLETED', 'DJ'),
];
const { service } = makeService(milestones);
const next = service.computeNextActionForBooking(booking, milestones);
expect(next?.actor).toBe('CUSTOMER');
expect(next?.action).toMatch(/operation/i);
});
});
});