mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-08-27 00:52:50 +00:00
Warehouse receiving for export and GRN generation
This commit is contained in:
@@ -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. */
|
||||
|
||||
@@ -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');
|
||||
|
||||
@@ -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 (
|
||||
<Stack gap="sm">
|
||||
<Text size="sm" fw={600}>Customer and cargo ownership</Text>
|
||||
<Group grow>
|
||||
<TextInput
|
||||
label="Owner's name"
|
||||
value={value.ownerName}
|
||||
onChange={(e) => onChange({ ...value, ownerName: e.currentTarget.value })}
|
||||
/>
|
||||
<TextInput
|
||||
label="Consignee details"
|
||||
value={value.consigneeDetails}
|
||||
onChange={(e) => onChange({ ...value, consigneeDetails: e.currentTarget.value })}
|
||||
/>
|
||||
</Group>
|
||||
<Group grow>
|
||||
<TextInput
|
||||
label="EDR digital booking ID"
|
||||
value={value.edrDigitalBookingId}
|
||||
onChange={(e) => onChange({ ...value, edrDigitalBookingId: e.currentTarget.value })}
|
||||
/>
|
||||
<TextInput
|
||||
label="TIN"
|
||||
value={value.tin}
|
||||
onChange={(e) => onChange({ ...value, tin: e.currentTarget.value })}
|
||||
/>
|
||||
</Group>
|
||||
|
||||
<Text size="sm" fw={600} mt="xs">Transport and equipment tracking</Text>
|
||||
<Group grow>
|
||||
<TextInput
|
||||
label="Truck plate number"
|
||||
@@ -108,6 +198,18 @@ function TruckEntranceFields({
|
||||
onChange={(e) => onChange({ ...value, trailerPlateNumber: e.currentTarget.value })}
|
||||
/>
|
||||
</Group>
|
||||
<Group grow>
|
||||
<TextInput
|
||||
label="Assigned wagon / container number"
|
||||
value={value.assignedEquipmentNumber}
|
||||
onChange={(e) => onChange({ ...value, assignedEquipmentNumber: e.currentTarget.value })}
|
||||
/>
|
||||
<TextInput
|
||||
label="Customs seal number"
|
||||
value={value.customsSealNumber}
|
||||
onChange={(e) => onChange({ ...value, customsSealNumber: e.currentTarget.value })}
|
||||
/>
|
||||
</Group>
|
||||
<Group grow>
|
||||
<TextInput
|
||||
label="Driver name"
|
||||
@@ -149,6 +251,103 @@ function TruckEntranceFields({
|
||||
onChange={(v) => onChange({ ...value, exitTareWeightKg: v === '' ? '' : Number(v) })}
|
||||
/>
|
||||
</Group>
|
||||
|
||||
<Text size="sm" fw={600} mt="xs">Customs and compliance</Text>
|
||||
<Group grow>
|
||||
<TextInput
|
||||
label="Declaration / Bill of Entry number"
|
||||
value={value.declarationNumber}
|
||||
onChange={(e) => onChange({ ...value, declarationNumber: e.currentTarget.value })}
|
||||
/>
|
||||
<TextInput
|
||||
label="Incoterms"
|
||||
value={value.incoterms}
|
||||
onChange={(e) => onChange({ ...value, incoterms: e.currentTarget.value })}
|
||||
/>
|
||||
</Group>
|
||||
<TextInput
|
||||
label="HS codes"
|
||||
value={value.hsCodes}
|
||||
onChange={(e) => onChange({ ...value, hsCodes: e.currentTarget.value })}
|
||||
/>
|
||||
|
||||
<Text size="sm" fw={600} mt="xs">Physical cargo specifications</Text>
|
||||
<Group grow>
|
||||
<TextInput
|
||||
label="Item code"
|
||||
value={value.itemCode}
|
||||
onChange={(e) => onChange({ ...value, itemCode: e.currentTarget.value })}
|
||||
/>
|
||||
<TextInput
|
||||
label="Item description"
|
||||
value={value.itemDescription}
|
||||
onChange={(e) => onChange({ ...value, itemDescription: e.currentTarget.value })}
|
||||
/>
|
||||
</Group>
|
||||
<Group grow>
|
||||
<TextInput
|
||||
label="Packaging type"
|
||||
value={value.packagingType}
|
||||
onChange={(e) => onChange({ ...value, packagingType: e.currentTarget.value })}
|
||||
/>
|
||||
<NumberInput
|
||||
label="Unit count"
|
||||
min={0}
|
||||
value={value.unitCount}
|
||||
onChange={(v) => onChange({ ...value, unitCount: v === '' ? '' : Number(v) })}
|
||||
/>
|
||||
</Group>
|
||||
<Group grow>
|
||||
<NumberInput
|
||||
label="Gross weight (kg)"
|
||||
min={0}
|
||||
value={value.grossWeightKg}
|
||||
onChange={(v) => onChange({ ...value, grossWeightKg: v === '' ? '' : Number(v) })}
|
||||
/>
|
||||
<NumberInput
|
||||
label="Net weight (kg)"
|
||||
min={0}
|
||||
value={value.netWeightKg}
|
||||
onChange={(v) => onChange({ ...value, netWeightKg: v === '' ? '' : Number(v) })}
|
||||
/>
|
||||
</Group>
|
||||
<TextInput
|
||||
label="Volume / dimensions"
|
||||
value={value.volumeDimensions}
|
||||
onChange={(e) => onChange({ ...value, volumeDimensions: e.currentTarget.value })}
|
||||
/>
|
||||
|
||||
<Text size="sm" fw={600} mt="xs">Quality and inspection</Text>
|
||||
<Group grow>
|
||||
<TextInput
|
||||
label="Condition at receipt"
|
||||
value={value.conditionAtReceipt}
|
||||
onChange={(e) => onChange({ ...value, conditionAtReceipt: e.currentTarget.value })}
|
||||
/>
|
||||
<NumberInput
|
||||
label="Damaged / rejected quantity"
|
||||
min={0}
|
||||
value={value.damagedRejectedQuantity}
|
||||
onChange={(v) => onChange({ ...value, damagedRejectedQuantity: v === '' ? '' : Number(v) })}
|
||||
/>
|
||||
</Group>
|
||||
<TextInput
|
||||
label="Warehouse code and location"
|
||||
value={value.warehouseCodeLocation}
|
||||
onChange={(e) => onChange({ ...value, warehouseCodeLocation: e.currentTarget.value })}
|
||||
/>
|
||||
<Group grow>
|
||||
<TextInput
|
||||
label="Driver signatory"
|
||||
value={value.driverSignatoryName}
|
||||
onChange={(e) => onChange({ ...value, driverSignatoryName: e.currentTarget.value })}
|
||||
/>
|
||||
<TextInput
|
||||
label="EDR warehouse manager"
|
||||
value={value.warehouseManagerName}
|
||||
onChange={(e) => onChange({ ...value, warehouseManagerName: e.currentTarget.value })}
|
||||
/>
|
||||
</Group>
|
||||
</Stack>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user