import { describe, expect, it } from "vitest"; import { buildSalesOrderPlanning, type SalesOrderPlanningSnapshot } from "../src/modules/sales/planning.js"; describe("sales order planning", () => { it("nets stock and open supply before cascading build demand into child components", () => { const snapshot: SalesOrderPlanningSnapshot = { orderId: "order-1", documentNumber: "SO-00001", status: "APPROVED", lines: [ { id: "line-1", itemId: "assembly-1", itemSku: "ASSY-100", itemName: "Assembly", quantity: 5, unitOfMeasure: "EA", }, ], itemsById: { "assembly-1": { id: "assembly-1", sku: "ASSY-100", name: "Assembly", type: "ASSEMBLY", unitOfMeasure: "EA", isPurchasable: false, bomLines: [ { componentItemId: "mfg-1", quantity: 2, unitOfMeasure: "EA", }, { componentItemId: "buy-1", quantity: 3, unitOfMeasure: "EA", }, ], }, "mfg-1": { id: "mfg-1", sku: "MFG-200", name: "Manufactured Child", type: "MANUFACTURED", unitOfMeasure: "EA", isPurchasable: false, bomLines: [ { componentItemId: "buy-2", quantity: 4, unitOfMeasure: "EA", }, ], }, "buy-1": { id: "buy-1", sku: "BUY-300", name: "Purchased Child", type: "PURCHASED", unitOfMeasure: "EA", isPurchasable: true, bomLines: [], }, "buy-2": { id: "buy-2", sku: "BUY-400", name: "Raw Material", type: "PURCHASED", unitOfMeasure: "EA", isPurchasable: true, bomLines: [], }, }, supplyByItemId: { "assembly-1": { onHandQuantity: 1, reservedQuantity: 0, availableQuantity: 1, openWorkOrderSupply: 1, openPurchaseSupply: 0, }, "mfg-1": { onHandQuantity: 2, reservedQuantity: 0, availableQuantity: 2, openWorkOrderSupply: 1, openPurchaseSupply: 0, }, "buy-1": { onHandQuantity: 4, reservedQuantity: 1, availableQuantity: 3, openWorkOrderSupply: 0, openPurchaseSupply: 5, }, "buy-2": { onHandQuantity: 1, reservedQuantity: 0, availableQuantity: 1, openWorkOrderSupply: 0, openPurchaseSupply: 2, }, }, }; const planning = buildSalesOrderPlanning(snapshot); expect(planning.summary.totalBuildQuantity).toBe(6); expect(planning.summary.totalPurchaseQuantity).toBe(10); const assembly = planning.items.find((item) => item.itemId === "assembly-1"); const manufacturedChild = planning.items.find((item) => item.itemId === "mfg-1"); const purchasedChild = planning.items.find((item) => item.itemId === "buy-1"); const rawMaterial = planning.items.find((item) => item.itemId === "buy-2"); expect(assembly?.recommendedBuildQuantity).toBe(3); expect(assembly?.supplyFromStock).toBe(1); expect(assembly?.supplyFromOpenWorkOrders).toBe(1); expect(manufacturedChild?.grossDemand).toBe(6); expect(manufacturedChild?.recommendedBuildQuantity).toBe(3); expect(manufacturedChild?.supplyFromStock).toBe(2); expect(manufacturedChild?.supplyFromOpenWorkOrders).toBe(1); expect(purchasedChild?.grossDemand).toBe(9); expect(purchasedChild?.recommendedPurchaseQuantity).toBe(1); expect(purchasedChild?.supplyFromStock).toBe(3); expect(purchasedChild?.supplyFromOpenPurchaseOrders).toBe(5); expect(rawMaterial?.grossDemand).toBe(12); expect(rawMaterial?.recommendedPurchaseQuantity).toBe(9); expect(rawMaterial?.supplyFromStock).toBe(1); expect(rawMaterial?.supplyFromOpenPurchaseOrders).toBe(2); }); });