mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-09-08 17:08:18 +00:00
Extends the warehouse hierarchy below zone with ground stacks and vertical slots, so a container's exact position is recorded rather than only its zone. - freight.warehouse_zone_stacks / warehouse_zone_slots, plus nullable stack_id / slot_id on warehouse_inventory (existing rows stay valid) - slot occupancy is derived from inventory status, guarded by a partial unique index, so no exit path has to remember to free a slot - placement service: hierarchy validation, bottom-up stacking rules, accessibility/blocking-container reads, capacity vs slot summaries - stack CRUD with auto-generated slots; reuses warehouse-zone permissions - slot support folded into the existing move()/store() paths - fix: validateLocation now rejects a mismatched warehouse/yard/zone triple - seed:warehouse-layout builds the layout from a JSON config
82 lines
2.9 KiB
TypeScript
82 lines
2.9 KiB
TypeScript
import { Body, Controller, Delete, Get, Param, ParseUUIDPipe, Patch } from '@nestjs/common';
|
|
import { ApiBearerAuth, ApiOperation, ApiTags } from '@nestjs/swagger';
|
|
|
|
import { BookingStaff } from '../../common/booking-guards';
|
|
import { FREIGHT_PERMS } from '../../seed/freight-permissions.registry';
|
|
import { UpdateWarehouseZoneDto } from './dto/update-warehouse-zone.dto';
|
|
import { WarehouseZonesService } from './warehouse-zones.service';
|
|
|
|
@ApiTags('warehouse-zones')
|
|
@ApiBearerAuth()
|
|
// Baseline read: zone reference data also serves inventory flows (allocation,
|
|
// receive/move pickers) — either view permission grants reads; writes stack
|
|
// their specific permission per route.
|
|
@Controller('warehouse-zones')
|
|
// Class gate lists every key its routes use: Nest runs class AND method
|
|
// guards, so a key missing here would deny before the route's own key runs.
|
|
@BookingStaff([
|
|
FREIGHT_PERMS.warehouseZones.view,
|
|
FREIGHT_PERMS.warehouseInventory.view,
|
|
FREIGHT_PERMS.warehouseZones.update,
|
|
FREIGHT_PERMS.warehouseZones.delete,
|
|
])
|
|
export class WarehouseZonesController {
|
|
constructor(private readonly zonesService: WarehouseZonesService) {}
|
|
|
|
@Get()
|
|
@ApiOperation({ summary: 'List all warehouse zones' })
|
|
findAll() {
|
|
return this.zonesService.findAll();
|
|
}
|
|
|
|
@Get(':id')
|
|
@ApiOperation({ summary: 'Get warehouse zone by ID' })
|
|
findOne(@Param('id', ParseUUIDPipe) id: string) {
|
|
return this.zonesService.findById(id);
|
|
}
|
|
|
|
@Patch(':id')
|
|
@BookingStaff(FREIGHT_PERMS.warehouseZones.update)
|
|
@ApiOperation({ summary: 'Update warehouse zone' })
|
|
update(@Param('id', ParseUUIDPipe) id: string, @Body() dto: UpdateWarehouseZoneDto) {
|
|
return this.zonesService.update(id, dto);
|
|
}
|
|
|
|
@Get(':id/contents')
|
|
@ApiOperation({
|
|
summary: 'What is currently stored in a zone',
|
|
description: 'A row per container — booked units and backlog-registered containers alike.',
|
|
})
|
|
contents(@Param('id', ParseUUIDPipe) id: string) {
|
|
return this.zonesService.contents(id);
|
|
}
|
|
|
|
@Get(':id/layout')
|
|
@ApiOperation({
|
|
summary: 'Physical layout of a zone',
|
|
description: 'Every ground stack with its levels, what stands on each, and the slot summary.',
|
|
})
|
|
layout(@Param('id', ParseUUIDPipe) id: string) {
|
|
return this.zonesService.layout(id);
|
|
}
|
|
|
|
@Get(':id/slot-summary')
|
|
@ApiOperation({
|
|
summary: 'Configured capacity vs physical slots vs occupancy',
|
|
description: 'Flags a zone whose built slots exceed its configured container capacity.',
|
|
})
|
|
slotSummary(@Param('id', ParseUUIDPipe) id: string) {
|
|
return this.zonesService.slotSummary(id);
|
|
}
|
|
|
|
@Delete(':id')
|
|
@BookingStaff(FREIGHT_PERMS.warehouseZones.delete)
|
|
@ApiOperation({
|
|
summary: 'Delete warehouse zone',
|
|
description: 'Soft-deletes the zone. Refused while inventory still sits in it.',
|
|
})
|
|
remove(@Param('id', ParseUUIDPipe) id: string) {
|
|
return this.zonesService.remove(id);
|
|
}
|
|
}
|