feat(warehouses): delete yards/zones and inspect zone contents

Yard and zone soft-delete, refused with 409 while a yard still has
zones or a zone still holds inventory. warehouse_zones:delete was
missing from the catalog — the role presets spread every zone key, so
its absence crashes FreightPositionsSeeder at boot; a migration seeds
it everywhere.

Clicking a zone opens its contents as a datatable. Container identity
comes from booking_container_units for booked cargo and from
containers for backlog registrations; bulk cargo keeps its row with no
container number rather than disappearing from the zone.
This commit is contained in:
Hagernesh
2026-08-28 14:54:17 +00:00
parent 8ef50f9aff
commit d4373dfbe4
14 changed files with 533 additions and 27 deletions

View File

@@ -153,6 +153,7 @@ import type {
WarehouseLoading,
WarehouseYard,
WarehouseZone,
ZoneContentItem,
} from "@/types/warehouse";
import { endpoint } from "@/utils/endpoint";
import {
@@ -1211,6 +1212,14 @@ export const api = {
() => [["warehouses"], ["warehouse-yards"]],
),
deleteYard: endpoint<{ id: string }, unknown>(
"warehouses",
"deleteYard",
({ id }) => warehouseService.removeYard(id).then((r) => r.data),
undefined,
() => [["warehouses"], ["warehouse-yards"]],
),
// ── Zones ──────────────────────────────────────────────────────────────
listZones: endpoint<{ yardId: string }, WarehouseZone[]>(
"warehouses",
@@ -1243,6 +1252,21 @@ export const api = {
() => [["warehouse-yards"]],
),
zoneContents: endpoint<{ zoneId: string }, ZoneContentItem[]>(
"warehouse-zones",
"contents",
({ zoneId }) => warehouseService.zoneContents(zoneId).then((r) => r.data),
({ zoneId }) => ["warehouse-zones", zoneId, "contents"],
),
deleteZone: endpoint<{ id: string }, unknown>(
"warehouses",
"deleteZone",
({ id }) => warehouseService.removeZone(id).then((r) => r.data),
undefined,
() => [["warehouses"], ["warehouse-yards"]],
),
// ── Inventory (queries) ────────────────────────────────────────────────
listInventory: endpoint<
{ filter?: InventoryFilter },

View File

@@ -72,6 +72,7 @@ import type {
WarehouseLoading,
WarehouseYard,
WarehouseZone,
ZoneContentItem,
} from '@/types/warehouse';
export type ContainerItemStage = 'PENDING' | 'RECEIVED' | 'GRN' | 'ASSIGNED' | 'LOADED' | 'LEFT' | 'DELIVERED';
@@ -274,6 +275,7 @@ export const warehouseService = {
getYard: (id: string) => apiClient.get<WarehouseYard>(URL_CONSTANTS.WAREHOUSE_YARDS.BY_ID(id)),
updateYard: (id: string, payload: Partial<SaveYardPayload>) =>
apiClient.patch<WarehouseYard>(URL_CONSTANTS.WAREHOUSE_YARDS.BY_ID(id), payload),
removeYard: (id: string) => apiClient.delete(URL_CONSTANTS.WAREHOUSE_YARDS.BY_ID(id)),
// ── Zones ──────────────────────────────────────────────────────────────
listZones: (yardId: string) =>
@@ -284,6 +286,9 @@ export const warehouseService = {
getZone: (id: string) => apiClient.get<WarehouseZone>(URL_CONSTANTS.WAREHOUSE_ZONES.BY_ID(id)),
updateZone: (id: string, payload: Partial<SaveZonePayload>) =>
apiClient.patch<WarehouseZone>(URL_CONSTANTS.WAREHOUSE_ZONES.BY_ID(id), payload),
removeZone: (id: string) => apiClient.delete(URL_CONSTANTS.WAREHOUSE_ZONES.BY_ID(id)),
zoneContents: (zoneId: string) =>
apiClient.get<ZoneContentItem[]>(`${URL_CONSTANTS.WAREHOUSE_ZONES.BY_ID(zoneId)}/contents`),
// ── Inventory ──────────────────────────────────────────────────────────
listInventory: (filter?: InventoryFilter) =>