mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-29 18:48:11 +00:00
87 lines
3.0 KiB
TypeScript
87 lines
3.0 KiB
TypeScript
import { WarehouseInventoryService } from './warehouse-inventory.service';
|
|
import type { UnloadBookingDto } from './dto/unload-booking.dto';
|
|
|
|
/**
|
|
* A GRN is the receipt for cargo entering the warehouse, so unloadBooking must
|
|
* issue one for every direction — import as well as export. It used to mint only
|
|
* for export, leaving import cargo received with no GRN.
|
|
*/
|
|
function makeService(opts: {
|
|
tradeDirection: string | null;
|
|
existing?: { id: string; grnNumber: string | null };
|
|
}) {
|
|
const created: Record<string, unknown>[] = [];
|
|
const updated: Array<{ id: string; patch: Record<string, unknown> }> = [];
|
|
|
|
const inventoryRepository = {
|
|
findAll: jest.fn().mockResolvedValue(opts.existing ? [opts.existing] : []),
|
|
update: jest.fn((id: string, patch: Record<string, unknown>) => {
|
|
updated.push({ id, patch });
|
|
return Promise.resolve();
|
|
}),
|
|
create: jest.fn((row: Record<string, unknown>) => {
|
|
created.push(row);
|
|
return Promise.resolve({ id: 'new-inv', ...row });
|
|
}),
|
|
};
|
|
|
|
const service = Object.create(WarehouseInventoryService.prototype) as Record<string, unknown>;
|
|
service.inventoryRepository = inventoryRepository;
|
|
service.dataSource = {
|
|
query: jest.fn().mockResolvedValue([{ tradeDirection: opts.tradeDirection }]),
|
|
};
|
|
// Location comes straight from the dto in these cases, so pickDefaultLocation
|
|
// is never reached; findById just echoes what was written.
|
|
service.findById = jest.fn((id: string) =>
|
|
Promise.resolve(updated.find((u) => u.id === id)?.patch ?? created[0] ?? { id }),
|
|
);
|
|
|
|
const dto: UnloadBookingDto = {
|
|
warehouseId: 'w1',
|
|
yardId: 'y1',
|
|
zoneId: 'z1',
|
|
} as UnloadBookingDto;
|
|
|
|
return { service: service as unknown as WarehouseInventoryService, dto, created, updated };
|
|
}
|
|
|
|
describe('unloadBooking — GRN issuance', () => {
|
|
it('issues an IMPORT GRN when unloading a fresh import booking', async () => {
|
|
const { service, dto, created } = makeService({ tradeDirection: 'IMPORT' });
|
|
|
|
await service.unloadBooking('b-import', dto);
|
|
|
|
expect(created[0].grnNumber).toMatch(/^GRN-IMPORT-/);
|
|
});
|
|
|
|
it('still issues an EXPORT GRN', async () => {
|
|
const { service, dto, created } = makeService({ tradeDirection: 'EXPORT' });
|
|
|
|
await service.unloadBooking('b-export', dto);
|
|
|
|
expect(created[0].grnNumber).toMatch(/^GRN-EXPORT-/);
|
|
});
|
|
|
|
it('mints a GRN for an existing import row that has none', async () => {
|
|
const { service, dto, updated } = makeService({
|
|
tradeDirection: 'IMPORT',
|
|
existing: { id: 'inv-1', grnNumber: null },
|
|
});
|
|
|
|
await service.unloadBooking('b-import', dto);
|
|
|
|
expect(updated[0].patch.grnNumber).toMatch(/^GRN-IMPORT-/);
|
|
});
|
|
|
|
it('does not reissue when the row already has a GRN', async () => {
|
|
const { service, dto, updated } = makeService({
|
|
tradeDirection: 'IMPORT',
|
|
existing: { id: 'inv-1', grnNumber: 'GRN-IMPORT-EXISTING' },
|
|
});
|
|
|
|
await service.unloadBooking('b-import', dto);
|
|
|
|
expect(updated[0].patch).not.toHaveProperty('grnNumber');
|
|
});
|
|
});
|