demand planning
This commit is contained in:
137
server/tests/sales-planning.test.ts
Normal file
137
server/tests/sales-planning.test.ts
Normal file
@@ -0,0 +1,137 @@
|
||||
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);
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user