mirror of
https://github.com/Tria-plc/edr-platform.git
synced 2026-09-07 18:55:42 +00:00
Invoice and clearance seal approval
This commit is contained in:
@@ -24,6 +24,15 @@ function DetailRow({ label, value }: { label: string; value: React.ReactNode })
|
||||
}
|
||||
|
||||
export function InventoryDetailModal({ opened, onClose, item }: InventoryDetailModalProps) {
|
||||
const bookingReference = item?.booking?.reference ?? '-';
|
||||
const inventorySummary = [
|
||||
item?.status?.replace(/_/g, ' '),
|
||||
item?.releaseOrderReference ? `Release ${item.releaseOrderReference}` : null,
|
||||
item?.warehouse ? `${item.warehouse.name} (${item.warehouse.code})` : null,
|
||||
]
|
||||
.filter(Boolean)
|
||||
.join(' / ');
|
||||
|
||||
return (
|
||||
<Modal opened={opened} onClose={onClose} title="Inventory detail" centered size="xl">
|
||||
{!item ? (
|
||||
@@ -33,10 +42,10 @@ export function InventoryDetailModal({ opened, onClose, item }: InventoryDetailM
|
||||
<Group justify="space-between" align="flex-start">
|
||||
<Stack gap={2}>
|
||||
<Text size="lg" fw={800}>
|
||||
{item.booking?.reference ?? item.bookingId ?? item.id}
|
||||
{bookingReference}
|
||||
</Text>
|
||||
<Text size="sm" c="dimmed">
|
||||
Inventory ID: {item.id}
|
||||
{inventorySummary || 'Inventory information'}
|
||||
</Text>
|
||||
</Stack>
|
||||
<InventoryStatusBadge status={item.status} />
|
||||
@@ -51,12 +60,12 @@ export function InventoryDetailModal({ opened, onClose, item }: InventoryDetailM
|
||||
|
||||
<Divider label="Booking & item" labelPosition="left" />
|
||||
<SimpleGrid cols={{ base: 1, sm: 3 }}>
|
||||
<DetailRow label="Booking reference" value={bookingReference} />
|
||||
<DetailRow label="Booking status" value={item.booking?.status ?? '-'} />
|
||||
<DetailRow label="Payment status" value={item.booking?.paymentStatus ?? '-'} />
|
||||
<DetailRow label="Trade direction" value={item.booking?.tradeDirection ?? '-'} />
|
||||
<DetailRow label="Container ID" value={item.containerId ?? '-'} />
|
||||
<DetailRow label="Cargo ID" value={item.cargoId ?? '-'} />
|
||||
<DetailRow label="Goods ID" value={item.goodsId ?? '-'} />
|
||||
<DetailRow label="Inventory status" value={item.status.replace(/_/g, ' ')} />
|
||||
<DetailRow label="Release reference" value={item.releaseOrderReference ?? '-'} />
|
||||
<DetailRow label="Quantity" value={formatNumber(item.quantity)} />
|
||||
<DetailRow label="Weight" value={`${formatNumber(item.weight)} kg`} />
|
||||
<DetailRow label="Volume" value={item.volume == null ? '-' : formatNumber(item.volume)} />
|
||||
|
||||
@@ -130,12 +130,22 @@ function buildSimplePdf(lines: PdfLine[], rawOps: string[] = []): Blob {
|
||||
export function buildWarehouseInvoicePdf(invoice: WarehouseFeeInvoice, kind: 'INVOICE' | 'RECEIPT') {
|
||||
const paid = kind === 'RECEIPT' || invoice.status === 'PAID';
|
||||
const title = `Warehouse Fee ${kind === 'RECEIPT' ? 'Receipt' : 'Invoice'}`;
|
||||
const bookingReference = firstText(invoice.bookingReference);
|
||||
const customerName = firstText(invoice.customerName);
|
||||
const inventoryReference = firstText(invoice.inventoryReference);
|
||||
const inventoryInfo = firstText(invoice.inventoryInfo, invoice.containerNumber, invoice.cargoDescription);
|
||||
const clearanceStatus = firstText(
|
||||
invoice.clearanceStatus,
|
||||
paid ? 'FEE PAID - READY FOR RELEASE' : 'PENDING PAYMENT',
|
||||
);
|
||||
const lines: PdfLine[] = [
|
||||
{ text: 'Ethio-Djibouti Railway S.C.', size: 12, bold: true, yGap: 0, align: 'center' },
|
||||
{ text: title, size: 23, bold: true, yGap: 28, align: 'center' },
|
||||
{ text: `Document No: ${invoice.invoiceNumber}`, size: 12, bold: true, yGap: 32, align: 'center' },
|
||||
{ text: `Status: ${invoice.status.replace(/_/g, ' ')} Type: ${invoice.invoiceType.replace(/_/g, ' ')}`, align: 'center' },
|
||||
{ text: `Booking: ${invoice.bookingId ?? '-'} Inventory: ${invoice.inventoryId}`, align: 'center' },
|
||||
{ text: `Booking Reference: ${bookingReference} Customer: ${customerName}`, align: 'center' },
|
||||
{ text: `Inventory Reference: ${inventoryReference} Inventory Info: ${inventoryInfo}`, align: 'center' },
|
||||
{ text: `Clearance: ${clearanceStatus}`, align: 'center' },
|
||||
{ text: `Issued: ${fmtDate(invoice.issuedAt)} Paid At: ${fmtDate(invoice.paidAt)}`, align: 'center' },
|
||||
{ text: 'ITEMS', size: 13, bold: true, yGap: 30, align: 'center' },
|
||||
...(invoice.items ?? []).flatMap((item) => [
|
||||
@@ -201,15 +211,33 @@ export function buildWarehouseExitPaperPdf(input: WarehouseFeeInvoice | Warehous
|
||||
const releasedItem = context.releasedItem;
|
||||
const inventory = context.inventory ?? releasedItem;
|
||||
const releasedAt = context.releasedAt ?? new Date();
|
||||
const releaseReference = `REL-${invoice.inventoryId.slice(0, 8).toUpperCase()}`;
|
||||
const releaseReference = firstText(
|
||||
inventory?.releaseOrderReference,
|
||||
releasedItem?.releaseOrderReference,
|
||||
invoice.inventoryReference,
|
||||
booking?.reference ? `REL-${booking.reference.replace(/^BK-?/i, '')}` : null,
|
||||
);
|
||||
const customerName = firstText(
|
||||
booking?.company?.name,
|
||||
booking?.company?.companyName,
|
||||
booking?.company?.label,
|
||||
booking?.company?.contactPersonName,
|
||||
invoice.customerId,
|
||||
invoice.customerName,
|
||||
);
|
||||
const weightTons = firstText(tons(booking?.cargoTotalWeightVgm), tons(inventory?.weight));
|
||||
const inventoryInfo = firstText(
|
||||
invoice.inventoryInfo,
|
||||
invoice.containerNumber,
|
||||
invoice.cargoDescription,
|
||||
inventory?.status,
|
||||
releasedItem?.status,
|
||||
);
|
||||
const bookingReference = firstText(
|
||||
booking?.reference,
|
||||
(inventory as unknown as { bookingReference?: string })?.bookingReference,
|
||||
invoice.bookingReference,
|
||||
releasedItem?.booking?.reference,
|
||||
);
|
||||
|
||||
return buildSimplePdf([
|
||||
{ text: 'Ethio-Djibouti Railway S.C.', size: 12, bold: true, yGap: 0, align: 'center' },
|
||||
@@ -217,16 +245,18 @@ export function buildWarehouseExitPaperPdf(input: WarehouseFeeInvoice | Warehous
|
||||
{ text: '[ GATE CLEARANCE ]', size: 14, bold: true, color: 'green', yGap: 24, align: 'center' },
|
||||
{ text: `Release Reference: ${releaseReference}`, bold: true, yGap: 30, align: 'center' },
|
||||
{ text: `Invoice No: ${invoice.invoiceNumber}`, align: 'center' },
|
||||
{ text: `Booking Reference: ${firstText(booking?.reference, (inventory as unknown as { bookingReference?: string })?.bookingReference, invoice.bookingId, releasedItem?.bookingId)}`, align: 'center' },
|
||||
{ text: `Booking Reference: ${bookingReference}`, align: 'center' },
|
||||
{ text: `Customer: ${customerName}`, align: 'center' },
|
||||
{ text: `Warehouse: ${firstText(inventory?.warehouse?.name, inventory?.warehouse?.code, invoice.warehouseId, releasedItem?.warehouseId)}`, align: 'center' },
|
||||
{ text: `Yard: ${firstText(inventory?.yard?.name, inventory?.yard?.code, invoice.yardId, releasedItem?.yardId)}`, align: 'center' },
|
||||
{ text: `Zone: ${firstText(inventory?.zone?.name, inventory?.zone?.code, invoice.zoneId, releasedItem?.zoneId)}`, align: 'center' },
|
||||
{ text: `Inventory Info: ${inventoryInfo}`, align: 'center' },
|
||||
{ text: `Warehouse: ${firstText(inventory?.warehouse?.name, inventory?.warehouse?.code)}`, align: 'center' },
|
||||
{ text: `Yard: ${firstText(inventory?.yard?.name, inventory?.yard?.code)}`, align: 'center' },
|
||||
{ text: `Zone: ${firstText(inventory?.zone?.name, inventory?.zone?.code)}`, align: 'center' },
|
||||
{ text: `Booking Container: ${containerSummary(booking, inventory)}`, align: 'center' },
|
||||
{ text: `Weight: ${weightTons}`, align: 'center' },
|
||||
{ text: `Inventory Status: ${releasedItem?.status ?? inventory?.status ?? 'RELEASED'}`, align: 'center' },
|
||||
{ text: `Clearance: ${invoice.clearanceStatus ?? 'CLEARED FOR WAREHOUSE EXIT'}`, bold: true, color: 'green', align: 'center' },
|
||||
{ text: `Release Date & Time: ${fmtDate(releasedAt)}`, align: 'center' },
|
||||
{ text: 'This document authorizes the listed booking/goods to leave the warehouse gate.', yGap: 30, align: 'center' },
|
||||
{ text: 'This sealed document authorizes the listed booking/goods to leave the warehouse gate.', yGap: 30, align: 'center' },
|
||||
], [
|
||||
...buildAuthorizationBand('CLEARED'),
|
||||
textOp('Warehouse officer name / signature / date:', 72, 190, 10),
|
||||
|
||||
Reference in New Issue
Block a user