feat(warehouses): allow deleting a warehouse

Soft-delete route guarded by warehouses:delete, refused with 409 while
yards remain — zones and inventory hang off a yard, so cascading would
orphan stock. Backoffice list gets a delete action in both views,
omitted when the user lacks the permission.
This commit is contained in:
Hagernesh
2026-08-28 14:39:34 +00:00
parent 224d46402d
commit 8ef50f9aff
21 changed files with 1264 additions and 7 deletions

View File

@@ -0,0 +1,114 @@
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { Type } from 'class-transformer';
import {
ArrayMaxSize,
ArrayMinSize,
IsArray,
IsDateString,
IsNumber,
IsOptional,
IsString,
IsUUID,
MaxLength,
Min,
ValidateNested,
} from 'class-validator';
/**
* A loaded container that was already sitting in a yard before the system knew
* about it. It has no booking, so the owner is carried as a company reference
* or free text, and `arrivedAt` is the true historical arrival rather than now.
*/
export class RegisterBacklogContainerDto {
@ApiProperty({ description: 'ISO 6346 container number' })
@IsString()
@MaxLength(20)
containerNumber!: string;
@ApiProperty({ format: 'uuid' })
@IsUUID()
containerTypeId!: string;
@ApiProperty({ format: 'uuid' })
@IsUUID()
warehouseId!: string;
@ApiProperty({ format: 'uuid' })
@IsUUID()
yardId!: string;
@ApiProperty({ format: 'uuid' })
@IsUUID()
zoneId!: string;
@ApiProperty({ description: 'True historical arrival date — drives nothing billable.' })
@IsDateString()
arrivedAt!: string;
@ApiPropertyOptional({ format: 'uuid', description: 'Registered customer, when the owner is one.' })
@IsOptional()
@IsUUID()
companyId?: string;
@ApiPropertyOptional({ description: 'Owner name — free text when the company is not a customer yet.' })
@IsOptional()
@IsString()
@MaxLength(200)
companyName?: string;
@ApiPropertyOptional()
@IsOptional()
@IsString()
@MaxLength(100)
sealNumber?: string;
@ApiPropertyOptional({ description: 'Net weight in the unit the warehouse records (tonnes).' })
@IsOptional()
@IsNumber()
@Min(0)
weight?: number;
@ApiPropertyOptional()
@IsOptional()
@IsNumber()
@Min(0)
volume?: number;
/**
* ponytail: defaults to 0 when unknown, which is the honest value for a box
* nobody weighed. `containers.max_gross_weight` is a ceiling in
* cargoes.service, so set real figures here before this box is ever used for
* a new cargo assignment.
*/
@ApiPropertyOptional()
@IsOptional()
@IsNumber()
@Min(0)
tareWeight?: number;
@ApiPropertyOptional()
@IsOptional()
@IsNumber()
@Min(0)
maxGrossWeight?: number;
@ApiPropertyOptional()
@IsOptional()
@IsString()
notes?: string;
@ApiPropertyOptional()
@IsOptional()
@IsString()
performedBy?: string;
}
export class BulkRegisterBacklogDto {
@ApiProperty({ type: [RegisterBacklogContainerDto] })
@IsArray()
@ArrayMinSize(1)
@ArrayMaxSize(1000)
@ValidateNested({ each: true })
@Type(() => RegisterBacklogContainerDto)
containers!: RegisterBacklogContainerDto[];
}