PO logic
This commit is contained in:
@@ -45,6 +45,8 @@ export interface PurchaseOrderPdfData {
|
||||
|
||||
type PurchaseLineRecord = {
|
||||
id: string;
|
||||
salesOrderId: string | null;
|
||||
salesOrderLineId: string | null;
|
||||
description: string;
|
||||
quantity: number;
|
||||
unitOfMeasure: string;
|
||||
@@ -58,6 +60,10 @@ type PurchaseLineRecord = {
|
||||
sku: string;
|
||||
name: string;
|
||||
};
|
||||
salesOrder: {
|
||||
id: string;
|
||||
documentNumber: string;
|
||||
} | null;
|
||||
};
|
||||
|
||||
type PurchaseReceiptLineRecord = {
|
||||
@@ -175,6 +181,8 @@ function normalizeLines(lines: PurchaseLineInput[]) {
|
||||
return lines
|
||||
.map((line, index) => ({
|
||||
itemId: line.itemId,
|
||||
salesOrderId: line.salesOrderId ?? null,
|
||||
salesOrderLineId: line.salesOrderLineId ?? null,
|
||||
description: line.description.trim(),
|
||||
quantity: Number(line.quantity),
|
||||
unitOfMeasure: line.unitOfMeasure,
|
||||
@@ -213,6 +221,63 @@ async function validateLines(lines: PurchaseLineInput[]) {
|
||||
return { ok: false as const, reason: "Purchase orders can only include purchasable inventory items." };
|
||||
}
|
||||
|
||||
const salesOrderIds = [...new Set(normalized.flatMap((line) => (line.salesOrderId ? [line.salesOrderId] : [])))];
|
||||
const salesOrderLineIds = [...new Set(normalized.flatMap((line) => (line.salesOrderLineId ? [line.salesOrderLineId] : [])))];
|
||||
|
||||
if (normalized.some((line) => line.salesOrderLineId && !line.salesOrderId)) {
|
||||
return { ok: false as const, reason: "Linked sales-order lines require a linked sales order." };
|
||||
}
|
||||
|
||||
if (salesOrderIds.length > 0) {
|
||||
const salesOrders = await prisma.salesOrder.findMany({
|
||||
where: { id: { in: salesOrderIds } },
|
||||
select: { id: true },
|
||||
});
|
||||
|
||||
if (salesOrders.length !== salesOrderIds.length) {
|
||||
return { ok: false as const, reason: "One or more linked sales orders do not exist." };
|
||||
}
|
||||
}
|
||||
|
||||
if (salesOrderLineIds.length > 0) {
|
||||
const salesOrderLines = await prisma.salesOrderLine.findMany({
|
||||
where: { id: { in: salesOrderLineIds } },
|
||||
select: {
|
||||
id: true,
|
||||
orderId: true,
|
||||
itemId: true,
|
||||
},
|
||||
});
|
||||
const salesOrderLinesById = new Map(
|
||||
salesOrderLines.map((line) => [
|
||||
line.id,
|
||||
{
|
||||
orderId: line.orderId,
|
||||
itemId: line.itemId,
|
||||
},
|
||||
])
|
||||
);
|
||||
|
||||
if (salesOrderLines.length !== salesOrderLineIds.length) {
|
||||
return { ok: false as const, reason: "One or more linked sales-order lines do not exist." };
|
||||
}
|
||||
|
||||
for (const line of normalized) {
|
||||
if (!line.salesOrderLineId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const salesOrderLine = salesOrderLinesById.get(line.salesOrderLineId);
|
||||
if (!salesOrderLine || salesOrderLine.orderId !== line.salesOrderId) {
|
||||
return { ok: false as const, reason: "Linked sales-order line does not belong to the selected sales order." };
|
||||
}
|
||||
|
||||
if (salesOrderLine.itemId !== line.itemId) {
|
||||
return { ok: false as const, reason: "Linked sales-order line item does not match the purchase item." };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return { ok: true as const, lines: normalized };
|
||||
}
|
||||
|
||||
@@ -240,6 +305,9 @@ function mapPurchaseOrder(record: PurchaseOrderRecord): PurchaseOrderDetailDto {
|
||||
lineTotal: line.quantity * line.unitCost,
|
||||
receivedQuantity: receivedByLineId.get(line.id) ?? 0,
|
||||
remainingQuantity: Math.max(0, line.quantity - (receivedByLineId.get(line.id) ?? 0)),
|
||||
salesOrderId: line.salesOrderId,
|
||||
salesOrderLineId: line.salesOrderLineId,
|
||||
salesOrderNumber: line.salesOrder?.documentNumber ?? null,
|
||||
position: line.position,
|
||||
}));
|
||||
const totals = calculateTotals(
|
||||
@@ -305,6 +373,12 @@ const purchaseOrderInclude = Prisma.validator<Prisma.PurchaseOrderInclude>()({
|
||||
name: true,
|
||||
},
|
||||
},
|
||||
salesOrder: {
|
||||
select: {
|
||||
id: true,
|
||||
documentNumber: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
orderBy: [{ position: "asc" }, { createdAt: "asc" }],
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user