Files
edr-platform/apps/edr-freight-api/src/modules/warehouses/warehouse-rules.controller.ts
Hagernesh 01aec12ee9 feat(warehouse): Batch 5 — config-driven allocation + storage/demurrage fee rules
- Allocation rules engine: cargo/container/trade criteria -> deterministic yard/warehouse/zone by code; wired into auto-unload (fallback to default)
- Storage/demurrage fee rules: configurable freeDays + ratePerDay; most-specific match; fee preview per inventory item
- Inventory demurrage timestamps: inspectionStartedAt, inspectionCompletedAt, readyForPickupAt, releaseDate, gateClearedAt
- Migration 1790000000000 (allocation_rules + fee_rules tables + inventory date columns)
- Frontend: Allocation & Fees config page, automatic Fee Preview modal, plumbing/hooks
- No invoice/payment (Batch 6)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-17 23:53:04 +00:00

86 lines
3.3 KiB
TypeScript

import { Body, Controller, Delete, Get, HttpCode, Param, ParseUUIDPipe, Patch, Post } from '@nestjs/common';
import { ApiBearerAuth, ApiOperation, ApiTags } from '@nestjs/swagger';
import {
AllocationPreviewDto,
CreateAllocationRuleDto,
UpdateAllocationRuleDto,
} from './dto/allocation-rule.dto';
import { CreateFeeRuleDto, UpdateFeeRuleDto } from './dto/fee-rule.dto';
import { WarehouseAllocationService } from './warehouse-allocation.service';
import { WarehouseFeeService } from './warehouse-fee.service';
@ApiTags('warehouse-rules')
@ApiBearerAuth()
@Controller()
export class WarehouseRulesController {
constructor(
private readonly allocationService: WarehouseAllocationService,
private readonly feeService: WarehouseFeeService,
) {}
// ── Allocation rules ───────────────────────────────────────────────────────
@Get('warehouse-allocation-rules')
@ApiOperation({ summary: 'List warehouse allocation rules' })
listAllocationRules() {
return this.allocationService.listRules();
}
@Post('warehouse-allocation-rules')
@ApiOperation({ summary: 'Create a warehouse allocation rule' })
createAllocationRule(@Body() dto: CreateAllocationRuleDto) {
return this.allocationService.createRule(dto);
}
@Patch('warehouse-allocation-rules/:id')
@ApiOperation({ summary: 'Update a warehouse allocation rule' })
updateAllocationRule(@Param('id', ParseUUIDPipe) id: string, @Body() dto: UpdateAllocationRuleDto) {
return this.allocationService.updateRule(id, dto);
}
@Delete('warehouse-allocation-rules/:id')
@HttpCode(204)
@ApiOperation({ summary: 'Delete a warehouse allocation rule' })
deleteAllocationRule(@Param('id', ParseUUIDPipe) id: string) {
return this.allocationService.deleteRule(id);
}
@Post('warehouse-allocation/preview')
@ApiOperation({ summary: 'Preview the yard/warehouse/zone a booking would be allocated to' })
previewAllocation(@Body() dto: AllocationPreviewDto) {
return this.allocationService.resolveLocation(dto);
}
// ── Fee rules ────────────────────────────────────────────────────────────────
@Get('warehouse-fee-rules')
@ApiOperation({ summary: 'List storage / demurrage fee rules' })
listFeeRules() {
return this.feeService.listRules();
}
@Post('warehouse-fee-rules')
@ApiOperation({ summary: 'Create a storage / demurrage fee rule' })
createFeeRule(@Body() dto: CreateFeeRuleDto) {
return this.feeService.createRule(dto);
}
@Patch('warehouse-fee-rules/:id')
@ApiOperation({ summary: 'Update a fee rule' })
updateFeeRule(@Param('id', ParseUUIDPipe) id: string, @Body() dto: UpdateFeeRuleDto) {
return this.feeService.updateRule(id, dto);
}
@Delete('warehouse-fee-rules/:id')
@HttpCode(204)
@ApiOperation({ summary: 'Delete a fee rule' })
deleteFeeRule(@Param('id', ParseUUIDPipe) id: string) {
return this.feeService.deleteRule(id);
}
@Get('warehouse-inventory/:id/fee-preview')
@ApiOperation({ summary: 'Preview demurrage + storage fees for an inventory item' })
feePreview(@Param('id', ParseUUIDPipe) id: string) {
return this.feeService.previewForInventory(id);
}
}