mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-29 22:18:12 +00:00
feat(wagons): enforce wagon availability limits in transfer requests
This commit is contained in:
@@ -14,7 +14,8 @@ import {
|
||||
* A count-only wagon-transfer request. The requester picks source yard, wagon
|
||||
* type, destination yard and HOW MANY — never the specific wagons; OCC hand-picks
|
||||
* those at fulfilment. The quantity may not exceed the AVAILABLE wagons of that
|
||||
* type currently in the source yard, and a reason is mandatory.
|
||||
* type currently in the source yard (enforced in the service, which is the only
|
||||
* layer that can count them), and a reason is mandatory.
|
||||
*/
|
||||
export class CreateTransferRequestDto {
|
||||
@IsUUID()
|
||||
|
||||
@@ -199,7 +199,7 @@ describe('WagonTransferRequestsService — partial fulfilment', () => {
|
||||
});
|
||||
|
||||
describe('createRequest', () => {
|
||||
it('accepts a count larger than what the yard holds today', async () => {
|
||||
it('accepts a count up to what the yard holds today', async () => {
|
||||
wagonRepo.count.mockResolvedValue(20);
|
||||
|
||||
await service.createRequest(
|
||||
@@ -207,14 +207,50 @@ describe('WagonTransferRequestsService — partial fulfilment', () => {
|
||||
fromYardId: 'yard-a',
|
||||
toYardId: 'yard-b',
|
||||
wagonTypeId: 'type-1',
|
||||
quantity: 50,
|
||||
quantity: 20,
|
||||
reason: 'Grain campaign',
|
||||
},
|
||||
'user-1',
|
||||
);
|
||||
|
||||
expect(requestRepo.save).toHaveBeenCalled();
|
||||
expect(stored.quantity).toBe(50);
|
||||
expect(stored.quantity).toBe(20);
|
||||
});
|
||||
|
||||
it('refuses a count larger than what the yard holds today', async () => {
|
||||
wagonRepo.count.mockResolvedValue(20);
|
||||
|
||||
await expect(
|
||||
service.createRequest(
|
||||
{
|
||||
fromYardId: 'yard-a',
|
||||
toYardId: 'yard-b',
|
||||
wagonTypeId: 'type-1',
|
||||
quantity: 50,
|
||||
reason: 'Grain campaign',
|
||||
},
|
||||
'user-1',
|
||||
),
|
||||
).rejects.toThrow(/only 20 wagon\(s\).*available/i);
|
||||
expect(requestRepo.save).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('refuses when the yard has nothing of that type available', async () => {
|
||||
wagonRepo.count.mockResolvedValue(0);
|
||||
|
||||
await expect(
|
||||
service.createRequest(
|
||||
{
|
||||
fromYardId: 'yard-a',
|
||||
toYardId: 'yard-b',
|
||||
wagonTypeId: 'type-1',
|
||||
quantity: 1,
|
||||
reason: 'Grain campaign',
|
||||
},
|
||||
'user-1',
|
||||
),
|
||||
).rejects.toThrow(/no available wagons/i);
|
||||
expect(requestRepo.save).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('still refuses a same-yard move', async () => {
|
||||
|
||||
@@ -75,10 +75,11 @@ export class WagonTransferRequestsService {
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Record a PENDING request. Count-only — no wagons are picked here, and the
|
||||
* count is NOT capped by what the source yard holds today: OCC fulfils in
|
||||
* instalments, so asking for 50 while only 20 sit there is a normal, useful
|
||||
* request. A reason is mandatory and is shown on the OCC queue.
|
||||
* Record a PENDING request. Count-only — no wagons are picked here, but the
|
||||
* count IS capped by what the source yard can hand over right now: a request
|
||||
* may not exceed the AVAILABLE, uncoupled wagons of that type in the source
|
||||
* yard (the same number the yard desk shows). A reason is mandatory and is
|
||||
* shown on the OCC queue.
|
||||
*/
|
||||
async createRequest(
|
||||
dto: CreateTransferRequestDto,
|
||||
@@ -89,6 +90,20 @@ export class WagonTransferRequestsService {
|
||||
'Source and destination yard must be different',
|
||||
);
|
||||
}
|
||||
const available = await this.countAvailable(
|
||||
dto.fromYardId,
|
||||
dto.wagonTypeId,
|
||||
);
|
||||
if (available === 0) {
|
||||
throw new BadRequestException(
|
||||
'No available wagons of this type in the source yard',
|
||||
);
|
||||
}
|
||||
if (dto.quantity > available) {
|
||||
throw new BadRequestException(
|
||||
`Only ${available} wagon(s) of this type are available in the source yard — cannot request ${dto.quantity}`,
|
||||
);
|
||||
}
|
||||
const request = this.requestRepo.create({
|
||||
fromYardId: dto.fromYardId,
|
||||
toYardId: dto.toYardId,
|
||||
|
||||
Reference in New Issue
Block a user