diff --git a/apps/edr-freight-api/src/modules/warehouses/dto/bulk-receive.dto.ts b/apps/edr-freight-api/src/modules/warehouses/dto/bulk-receive.dto.ts index 460201639..2feadaccd 100644 --- a/apps/edr-freight-api/src/modules/warehouses/dto/bulk-receive.dto.ts +++ b/apps/edr-freight-api/src/modules/warehouses/dto/bulk-receive.dto.ts @@ -2,6 +2,26 @@ import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger'; import { ArrayNotEmpty, IsArray, IsIn, IsNumber, IsOptional, IsString, IsUUID, Min } from 'class-validator'; export class TruckEntranceDto { + @ApiPropertyOptional() + @IsOptional() + @IsString() + ownerName?: string; + + @ApiPropertyOptional() + @IsOptional() + @IsString() + consigneeDetails?: string; + + @ApiPropertyOptional() + @IsOptional() + @IsString() + edrDigitalBookingId?: string; + + @ApiPropertyOptional() + @IsOptional() + @IsString() + tin?: string; + @ApiProperty() @IsString() truckPlateNumber!: string; @@ -11,6 +31,85 @@ export class TruckEntranceDto { @IsString() trailerPlateNumber?: string; + @ApiPropertyOptional() + @IsOptional() + @IsString() + assignedEquipmentNumber?: string; + + @ApiPropertyOptional() + @IsOptional() + @IsString() + customsSealNumber?: string; + + @ApiPropertyOptional() + @IsOptional() + @IsString() + declarationNumber?: string; + + @ApiPropertyOptional() + @IsOptional() + @IsString() + incoterms?: string; + + @ApiPropertyOptional() + @IsOptional() + @IsString() + hsCodes?: string; + + @ApiPropertyOptional() + @IsOptional() + @IsString() + itemCode?: string; + + @ApiPropertyOptional() + @IsOptional() + @IsString() + itemDescription?: string; + + @ApiPropertyOptional() + @IsOptional() + @IsString() + packagingType?: string; + + @ApiPropertyOptional() + @IsOptional() + @IsNumber() + @Min(0) + unitCount?: number; + + @ApiPropertyOptional() + @IsOptional() + @IsNumber() + @Min(0) + grossWeightKg?: number; + + @ApiPropertyOptional() + @IsOptional() + @IsNumber() + @Min(0) + netWeightKg?: number; + + @ApiPropertyOptional() + @IsOptional() + @IsString() + volumeDimensions?: string; + + @ApiPropertyOptional() + @IsOptional() + @IsString() + conditionAtReceipt?: string; + + @ApiPropertyOptional() + @IsOptional() + @IsNumber() + @Min(0) + damagedRejectedQuantity?: number; + + @ApiPropertyOptional() + @IsOptional() + @IsString() + warehouseCodeLocation?: string; + @ApiProperty() @IsString() driverName!: string; @@ -39,6 +138,16 @@ export class TruckEntranceDto { @IsNumber() @Min(0) exitTareWeightKg?: number; + + @ApiPropertyOptional() + @IsOptional() + @IsString() + driverSignatoryName?: string; + + @ApiPropertyOptional() + @IsOptional() + @IsString() + warehouseManagerName?: string; } /** Bulk-receive eligible PAID bookings into a warehouse location, by trade direction. */ diff --git a/apps/edr-freight-api/src/modules/warehouses/warehouse-inventory.service.ts b/apps/edr-freight-api/src/modules/warehouses/warehouse-inventory.service.ts index 006efdb9c..ab3adb64a 100644 --- a/apps/edr-freight-api/src/modules/warehouses/warehouse-inventory.service.ts +++ b/apps/edr-freight-api/src/modules/warehouses/warehouse-inventory.service.ts @@ -2538,14 +2538,35 @@ export class WarehouseInventoryService { const rows = [ `GRN Number: ${input.grnNumber}`, input.direction ? `Direction: ${input.direction}` : null, + truck.ownerName ? `Owner / Shipper: ${truck.ownerName}` : null, + truck.consigneeDetails ? `Consignee: ${truck.consigneeDetails}` : null, + truck.edrDigitalBookingId ? `EDR Digital Booking ID: ${truck.edrDigitalBookingId}` : null, + truck.tin ? `TIN: ${truck.tin}` : null, `Truck Plate: ${truck.truckPlateNumber}`, truck.trailerPlateNumber ? `Trailer Plate: ${truck.trailerPlateNumber}` : null, + truck.assignedEquipmentNumber ? `Assigned Wagon / Container: ${truck.assignedEquipmentNumber}` : null, + truck.customsSealNumber ? `Customs Seal Number: ${truck.customsSealNumber}` : null, truck.truckType ? `Truck Type: ${truck.truckType}` : null, `Driver: ${truck.driverName}`, `Driver Phone: ${truck.driverPhone}`, truck.driverLicenseNumber ? `Driver License: ${truck.driverLicenseNumber}` : null, `Entrance Tare Weight: ${Number(truck.entranceTareWeightKg)} kg`, truck.exitTareWeightKg !== undefined ? `Exit Tare Weight: ${Number(truck.exitTareWeightKg)} kg` : null, + truck.declarationNumber ? `Declaration / Bill of Entry: ${truck.declarationNumber}` : null, + truck.incoterms ? `Incoterms: ${truck.incoterms}` : null, + truck.hsCodes ? `HS Codes: ${truck.hsCodes}` : null, + truck.itemCode ? `Item Code: ${truck.itemCode}` : null, + truck.itemDescription ? `Item Description: ${truck.itemDescription}` : null, + truck.packagingType ? `Packaging Type: ${truck.packagingType}` : null, + truck.unitCount !== undefined ? `Unit Count: ${Number(truck.unitCount)}` : null, + truck.grossWeightKg !== undefined ? `Gross Weight: ${Number(truck.grossWeightKg)} kg` : null, + truck.netWeightKg !== undefined ? `Net Weight: ${Number(truck.netWeightKg)} kg` : null, + truck.volumeDimensions ? `Volume / Dimensions: ${truck.volumeDimensions}` : null, + truck.conditionAtReceipt ? `Condition at Receipt: ${truck.conditionAtReceipt}` : null, + truck.damagedRejectedQuantity !== undefined ? `Damaged / Rejected Quantity: ${Number(truck.damagedRejectedQuantity)}` : null, + truck.warehouseCodeLocation ? `Warehouse Code / Location: ${truck.warehouseCodeLocation}` : null, + truck.driverSignatoryName ? `Driver Signatory: ${truck.driverSignatoryName}` : null, + truck.warehouseManagerName ? `EDR Warehouse Manager: ${truck.warehouseManagerName}` : null, input.notes?.trim() ? `Remarks: ${input.notes.trim()}` : null, ]; return rows.filter(Boolean).join('\n'); diff --git a/apps/edr-freight-web/backoffice/src/components/warehouses/ReceiveInventoryModal.tsx b/apps/edr-freight-web/backoffice/src/components/warehouses/ReceiveInventoryModal.tsx index 293b38dd7..a2437fe8f 100644 --- a/apps/edr-freight-web/backoffice/src/components/warehouses/ReceiveInventoryModal.tsx +++ b/apps/edr-freight-web/backoffice/src/components/warehouses/ReceiveInventoryModal.tsx @@ -54,36 +54,99 @@ interface Location { } interface TruckEntranceFormState { + ownerName: string; + consigneeDetails: string; + edrDigitalBookingId: string; + tin: string; truckPlateNumber: string; trailerPlateNumber: string; + assignedEquipmentNumber: string; + customsSealNumber: string; + declarationNumber: string; + incoterms: string; + hsCodes: string; + itemCode: string; + itemDescription: string; + packagingType: string; + unitCount: number | ''; + grossWeightKg: number | ''; + netWeightKg: number | ''; + volumeDimensions: string; + conditionAtReceipt: string; + damagedRejectedQuantity: number | ''; + warehouseCodeLocation: string; driverName: string; driverPhone: string; driverLicenseNumber: string; truckType: string; entranceTareWeightKg: number | ''; exitTareWeightKg: number | ''; + driverSignatoryName: string; + warehouseManagerName: string; } const emptyTruckEntrance = (): TruckEntranceFormState => ({ + ownerName: '', + consigneeDetails: '', + edrDigitalBookingId: '', + tin: '', truckPlateNumber: '', trailerPlateNumber: '', + assignedEquipmentNumber: '', + customsSealNumber: '', + declarationNumber: '', + incoterms: '', + hsCodes: '', + itemCode: '', + itemDescription: '', + packagingType: '', + unitCount: '', + grossWeightKg: '', + netWeightKg: '', + volumeDimensions: '', + conditionAtReceipt: '', + damagedRejectedQuantity: '', + warehouseCodeLocation: '', driverName: '', driverPhone: '', driverLicenseNumber: '', truckType: '', entranceTareWeightKg: '', exitTareWeightKg: '', + driverSignatoryName: '', + warehouseManagerName: '', }); const toTruckEntrancePayload = (form: TruckEntranceFormState): TruckEntrancePayload => ({ + ownerName: form.ownerName.trim() || undefined, + consigneeDetails: form.consigneeDetails.trim() || undefined, + edrDigitalBookingId: form.edrDigitalBookingId.trim() || undefined, + tin: form.tin.trim() || undefined, truckPlateNumber: form.truckPlateNumber.trim(), trailerPlateNumber: form.trailerPlateNumber.trim() || undefined, + assignedEquipmentNumber: form.assignedEquipmentNumber.trim() || undefined, + customsSealNumber: form.customsSealNumber.trim() || undefined, + declarationNumber: form.declarationNumber.trim() || undefined, + incoterms: form.incoterms.trim() || undefined, + hsCodes: form.hsCodes.trim() || undefined, + itemCode: form.itemCode.trim() || undefined, + itemDescription: form.itemDescription.trim() || undefined, + packagingType: form.packagingType.trim() || undefined, + unitCount: form.unitCount === '' ? undefined : Number(form.unitCount), + grossWeightKg: form.grossWeightKg === '' ? undefined : Number(form.grossWeightKg), + netWeightKg: form.netWeightKg === '' ? undefined : Number(form.netWeightKg), + volumeDimensions: form.volumeDimensions.trim() || undefined, + conditionAtReceipt: form.conditionAtReceipt.trim() || undefined, + damagedRejectedQuantity: form.damagedRejectedQuantity === '' ? undefined : Number(form.damagedRejectedQuantity), + warehouseCodeLocation: form.warehouseCodeLocation.trim() || undefined, driverName: form.driverName.trim(), driverPhone: form.driverPhone.trim(), driverLicenseNumber: form.driverLicenseNumber.trim() || undefined, truckType: form.truckType.trim() || undefined, entranceTareWeightKg: Number(form.entranceTareWeightKg), exitTareWeightKg: form.exitTareWeightKg === '' ? undefined : Number(form.exitTareWeightKg), + driverSignatoryName: form.driverSignatoryName.trim() || undefined, + warehouseManagerName: form.warehouseManagerName.trim() || undefined, }); function TruckEntranceFields({ @@ -95,6 +158,33 @@ function TruckEntranceFields({ }) { return ( + Customer and cargo ownership + + onChange({ ...value, ownerName: e.currentTarget.value })} + /> + onChange({ ...value, consigneeDetails: e.currentTarget.value })} + /> + + + onChange({ ...value, edrDigitalBookingId: e.currentTarget.value })} + /> + onChange({ ...value, tin: e.currentTarget.value })} + /> + + + Transport and equipment tracking onChange({ ...value, trailerPlateNumber: e.currentTarget.value })} /> + + onChange({ ...value, assignedEquipmentNumber: e.currentTarget.value })} + /> + onChange({ ...value, customsSealNumber: e.currentTarget.value })} + /> + onChange({ ...value, exitTareWeightKg: v === '' ? '' : Number(v) })} /> + + Customs and compliance + + onChange({ ...value, declarationNumber: e.currentTarget.value })} + /> + onChange({ ...value, incoterms: e.currentTarget.value })} + /> + + onChange({ ...value, hsCodes: e.currentTarget.value })} + /> + + Physical cargo specifications + + onChange({ ...value, itemCode: e.currentTarget.value })} + /> + onChange({ ...value, itemDescription: e.currentTarget.value })} + /> + + + onChange({ ...value, packagingType: e.currentTarget.value })} + /> + onChange({ ...value, unitCount: v === '' ? '' : Number(v) })} + /> + + + onChange({ ...value, grossWeightKg: v === '' ? '' : Number(v) })} + /> + onChange({ ...value, netWeightKg: v === '' ? '' : Number(v) })} + /> + + onChange({ ...value, volumeDimensions: e.currentTarget.value })} + /> + + Quality and inspection + + onChange({ ...value, conditionAtReceipt: e.currentTarget.value })} + /> + onChange({ ...value, damagedRejectedQuantity: v === '' ? '' : Number(v) })} + /> + + onChange({ ...value, warehouseCodeLocation: e.currentTarget.value })} + /> + + onChange({ ...value, driverSignatoryName: e.currentTarget.value })} + /> + onChange({ ...value, warehouseManagerName: e.currentTarget.value })} + /> + ); } diff --git a/apps/edr-freight-web/backoffice/src/types/warehouse.ts b/apps/edr-freight-web/backoffice/src/types/warehouse.ts index 8e516027b..c63d8c5da 100644 --- a/apps/edr-freight-web/backoffice/src/types/warehouse.ts +++ b/apps/edr-freight-web/backoffice/src/types/warehouse.ts @@ -388,14 +388,35 @@ export interface BulkReceiveResult { } export interface TruckEntrancePayload { + ownerName?: string; + consigneeDetails?: string; + edrDigitalBookingId?: string; + tin?: string; truckPlateNumber: string; trailerPlateNumber?: string; + assignedEquipmentNumber?: string; + customsSealNumber?: string; + declarationNumber?: string; + incoterms?: string; + hsCodes?: string; + itemCode?: string; + itemDescription?: string; + packagingType?: string; + unitCount?: number; + grossWeightKg?: number; + netWeightKg?: number; + volumeDimensions?: string; + conditionAtReceipt?: string; + damagedRejectedQuantity?: number; + warehouseCodeLocation?: string; driverName: string; driverPhone: string; driverLicenseNumber?: string; truckType?: string; entranceTareWeightKg: number; exitTareWeightKg?: number; + driverSignatoryName?: string; + warehouseManagerName?: string; } export interface LoadPassedExportResult {