ProductionOut Documentation

Production Out Controller Documentation

File: /controllers/productionOutController.php

Purpose: Manages simple production/manufacturing processes for converting raw materials into finished products

Last Updated: December 20, 2024

Total Functions: 15

Lines of Code: ~903

---

๐Ÿ“‹ Overview

The Production Out Controller handles simple manufacturing operations where multiple raw materials are consumed to produce a single finished product. It manages:

Primary Functions

Related Controllers

---

๐Ÿ—„๏ธ Database Tables

Primary Tables (Direct Operations)

Table NamePurposeKey Columns
**productionout**Production header recordsid, outStore, inStore, supplier, productid, sizeid, colorid, outQuantity, outUnitCost, outAllCost, outAllCostTot, comment, userid, del, sysDate, dailyentryid
**productionoutdetails**Raw material consumptionid, productionOutId, productid, sizeid, colorid, unitid, price, quantity, inTotalCost
### Inventory Tables (Modified)

Table NamePurposeKey Columns
**storedetail**Main inventory quantitiesstoredetailid, storeid, productid, productquantity, userid, storedetaildate
**sizecolorstoredetail**Size/color variant inventoryid, storeid, productid, sizeid, colorid, quantity, userid, sysdate
**storereport**Inventory movement logstorereportid, productid, sizeid, colorid, storeid, productquantity, productbefore, productafter, storereporttype, storereportmodelid, processname, tablename, storereportdate, userid
### Financial Tables (Modified)

Table NamePurposeKey Columns
**buypriceshistorybook**Purchase price historyid, theDate, storeId, productid, sizeid, colorid, buyprice, buyQuantity, sellQuantity, del, userid, sysDate
**supplier**Supplier master datasupplierid, suppliername, suppliercurrentDebt, supplierdate, userid
**supplierdebtchange**Supplier debt change logsupplierdebtchangeid, supplierid, supplierdebtchangebefore, supplierdebtchangeamount, supplierdebtchangeafter, supplierdebtchangetype, processname, supplierdebtchangemodelid, tablename, comment, supplierdebtchangedate, userid, dailyentryid
### Reference Tables

Table NamePurposeKey Columns
**product**Product master dataproductId, productName, productCatId, productBuyPrice, lastbuyprice, meanbuyprice
**productcat**Product categoriesproductCatId, productCatName
**productunit**Unit conversionsproductunitid, productid, unitname, productnumber, proUnitBuyPrice
**store**Store/warehouse definitionsstoreId, storeName, conditions, treeId
**programsettings**System configurationprogramsettingsid, settingkey, settingvalue
---

๐Ÿ”‘ Key Functions

1. Default Action - Add Production Form

Location: Line 200

Purpose: Display form for creating new simple production orders

Function Signature:

// Triggered when: do= (empty)

Process Flow:

1. Load all active stores for dropdowns

2. Set production number counter

3. Load manufacturing settings

4. Display add form template

Features:

---

2. add() - Create Production Order

Location: Line 345

Purpose: Process simple manufacturing operation with raw material consumption

Function Signature:

function add()

Process Flow:

1. Extract and validate production header data

2. Handle size/color variants for output product

3. Create production header record

4. Process input raw materials

5. Update inventory quantities (increase output, decrease inputs)

6. Update product pricing information

7. Update supplier debt

8. Generate daily accounting entry

Transaction Control:

$mytransactions = new Transaction();
try {
    // All production operations
    $mytransactions->commit();
    doInventoryDailyEntry($productionOut);
} catch (Exception $e) {
    $mytransactions->rollback();
}

Size/Color Handling:

if (strpos($productId, "hasSizeColor") !== false) {
    $productIdComplex = explode('-', str_replace("hasSizeColor", "", $productId));
    $productId = $outProductId = $productIdComplex[0];
    $sizeId = $productIdComplex[1];
    $colorId = $productIdComplex[2];
}

Raw Material Processing:

for ($i = 1; $i <= $productItr; $i++) {
    if (filter_input(INPUT_POST, 'product' . $i)) {
        // Extract product and unit information
        $productunitData = $myProductunitEx->queryWithProductIdAndUnitId($productId, $unitId);
        $finalquantity = $quantity * $productunitData->productnumber;
        
        // Decrease inventory
        decrease($productId, $sizeId, $colorId, $finalquantity, $id, $inStore);
        $totalInProductsCost += $inTotalCost;
    }
}

---

3. edit() - Edit Production Order

Location: Line 220

Purpose: Load existing production order for modification

Process Flow:

1. Load production header by ID

2. Load all raw material details

3. Build display names with product/category/variant info

4. Assign data to edit template

Product Name Building:

$productionOut->productName = $productionOut->productName . '/ ' . $productionOut->productCatName;
if (!empty($productionOut->sizeid) && !empty($productionOut->colorid)) {
    $productionOut->productid = "hasSizeColor" . $productionOut->productid . "-" . $productionOut->sizeid . "-" . $productionOut->colorid;
    $productionOut->productName .= '/ ' . $productionOut->sizeName . '/ ' . $productionOut->colorName;
}

---

4. update() - Update Production Order

Location: Line 256

Purpose: Modify existing production orders using delete-and-recreate pattern

Function Signature:

function update()

Process Flow:

1. Delete existing production order (reverses all effects)

2. Create new production order with updated data

3. Maintains data integrity through transaction control

Note: This approach ensures all inventory movements, costs, and supplier debts are properly reversed and re-applied.

---

5. show() - List Production Orders

Location: Line 265

Purpose: Display filtered list of production orders with search capabilities

Process Flow:

1. Extract filter parameters

2. Build dynamic query string

3. Apply default date filter if no filters specified

4. Load and display production orders

5. Include YouTube tutorials

Filter Options:

Default Filter Logic:

if ($query == " and productionout.del=0 ") {
    $from = $to = date('Y-m-d');
    $query .= " and date(productionout.sysDate) >= '$from' and date(productionout.sysDate) <= '$to' ";
}

---

6. delete() - Delete Production Order

Location: Line 473

Purpose: Reverse all effects of a production order and remove from system

Function Signature:

function delete()

Process Flow:

1. Load production order data

2. Reverse finished product inventory increase

3. Reverse raw material inventory decreases

4. Reverse supplier debt changes

5. Delete production detail records

6. Delete production header record

7. Reverse daily accounting entry

Reversal Logic:

// Reverse output product increase
decrease($productionOut->productid, $productionOut->sizeid, $productionOut->colorid, $productionOut->outQuantity, $id, $productionOut->outStore);

// Reverse raw material decreases
foreach ($allProductionOutDetail as $p) {
    $productunitData = $myProductunitEx->queryWithProductIdAndUnitId($p->productid, $p->unitid);
    $finalquantity = $p->quantity * $productunitData->productnumber;
    increase($p->productid, $p->sizeid, $p->colorid, $finalquantity, $id, $productionOut->inStore);
}

---

7. decrease() - Reduce Inventory

Location: Line 519

Purpose: Decrease product quantities in inventory (for raw material consumption)

Function Signature:

function decrease($productId, $sizeId, $colorId, $finalquantity, $sellbillId, $sellbillstoreId = 0, $type = "")

Process Flow:

1. Get current inventory levels

2. Decrease main inventory quantity

3. Update size/color specific inventory if applicable

4. Create inventory movement report

5. Handle negative inventory scenarios

Inventory Update Logic:

if (count($allStoredetailData) > 0) {
    // Update existing inventory record
    $productquantityAfter = decreaseProductQuantity($storedetailId, $productquantityBefore, $finalquantity);
    insertStorereportupdate($productId, $sizeId, $colorId, $sellbillstoreId, $finalquantity, $productquantityBefore, $productquantityAfter, 1, $sellbillId, "ุชุตู†ูŠุน ู…ุจุณุท ู„ู„ู…ู†ุชุฌ" . $type, "productionExecutionController.php", date("Y-m-d H:i:s"));
} else {
    // Create new inventory record with negative quantity
    $specialQuantityAfter = $finalquantity * -1;
    insertStoredetailupdate($sellbillstoreId, $productId, $specialQuantityAfter, date("Y-m-d H:i:s"));
}

---

8. increase() - Add to Inventory

Location: Line 570

Purpose: Increase product quantities in inventory (for finished goods)

Function Signature:

function increase($productId, $sizeId, $colorId, $finalquantity, $sellbillId, $sellbillstoreId = 0, $type = "")

Process Flow:

1. Get current inventory levels

2. Increase main inventory quantity

3. Update size/color specific inventory if applicable

4. Create inventory movement report

Key Difference: Creates new positive inventory records if product doesn't exist in store.

---

9. getBuyPriceFromAndHandleBuyPricesHistoryBook() - FIFO Cost Calculation

Location: Line 727

Purpose: Calculate raw material costs using FIFO methodology

Function Signature:

function getBuyPriceFromAndHandleBuyPricesHistoryBook($storeId, $productid, $sizeid, $colorid, $productBuyPrice, $soldQuantity, $type = 0)

Process Flow:

1. Find earliest available inventory batches

2. Consume quantities in FIFO order

3. Calculate weighted average cost

4. Update sell quantities in price history

5. Return actual cost per unit

FIFO Logic:

do {
    $buyPriceFromHistoryBook = $buyPricesHistoryBookEX->getBuyPriceOfFirstAvailableSellQuantity($storeId, $productid, $sizeid, $colorid);
    if (isset($buyPriceFromHistoryBook->id) && $buyPriceFromHistoryBook->id > 0 && $remainQuantity > 0) {
        $availableBuyQuantity = $buyPriceFromHistoryBook->buyQuantity - $buyPriceFromHistoryBook->sellQuantity;
        // Process available quantity
    }
} while (isset($buyPriceFromHistoryBook->id) && $buyPriceFromHistoryBook->id > 0 && $remainQuantity > 0);

---

10. increaseBuyPricesHistoryBookBuyQuantity() - Price History Update

Location: Line 792

Purpose: Record new inventory purchases in price history

Function Signature:

function increaseBuyPricesHistoryBookBuyQuantity($theDate, $storeId, $productid, $sizeid, $colorid, $buyprice, $buyQuantity)

Features:

---

11. updateSupplierDebt() - Supplier Debt Management

Location: Line 830

Purpose: Update supplier debt balances

Function Signature:

function updateSupplierDebt($supplierId, $supplierDebtAfter)

Updates: Current debt balance and last update date.

---

12. insertSupplierDebtChange() - Debt Change Logging

Location: Line 846

Purpose: Log all supplier debt changes for audit trail

Function Signature:

function insertSupplierDebtChange($supplierId, $supplierDebtChangeBefore, $supplierDebtChangeAmount, $supplierDebtChangeType, $processname, $supplierDebtChangeModelId, $supplierDebtChangeAfter, $tablename, $comment)

Tracks: Before/after balances, change amount, change type, and linking information.

---

13. doInventoryDailyEntry() - Accounting Integration

Location: Line 867

Purpose: Generate daily accounting entries for production transactions

Function Signature:

function doInventoryDailyEntry($productionOut)

Process Flow:

1. Calculate raw material cost totals

2. Get store and supplier account tree IDs

3. Create debit entries (finished goods inventory, supplier debt)

4. Create credit entry (raw materials inventory)

5. Link to production order for reference

Accounting Logic:

$dailyEntryDebtorArray = array();
// Debit: Finished goods inventory
$dailyEntryDebtor->accountstreeid = $treeIdOutStore;
$dailyEntryDebtor->value = $rawMaterialCost;

// Debit: Supplier debt
$dailyEntryDebtor->accountstreeid = $suppData['treeId'];
$dailyEntryDebtor->value = $productionOut->outAllCost;

$dailyEntryCreditorArray = array();
// Credit: Raw materials inventory
$dailyEntryCreditor->value = $rawMaterialCost + $productionOut->outAllCost;
$dailyEntryCreditor->accountstreeid = $treeIdInStore;

---

๐Ÿ”„ Workflows

Workflow 1: Simple Production Process

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
START: Simple Production Order
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ–ผ
โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
1Define Production Parameters
- Select output product (with variants)
- Set output quantity and unit cost
- Choose output store
- Select supplier
- Choose input store
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ–ผ
โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
2Define Raw Material Requirements
FOR EACH raw material:
โ”‚
โ†’ Select product (with variants)
โ†’ Choose unit of measure
โ†’ Set quantity required
โ”‚ โ””โ”€โ†’ Set unit price โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ–ผ
โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
3Process Production Order
- Create production header record
- Calculate total costs
- Validate inventory availability
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ–ผ
โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
4Update Inventory Levels
- Decrease raw material quantities
- Increase finished product quantity
- Handle size/color variant tracking
- Create inventory movement reports
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ–ผ
โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
5Update Financial Records
- Update finished product pricing
- Record purchase price history
- Update supplier debt balance
- Log debt change transaction
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
โ–ผ
โ–ผ
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
6Generate Accounting Entry
- Debit: Finished goods inventory
- Debit: Supplier debt
- Credit: Raw materials inventory
- Link to production order
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

---

๐ŸŒ URL Routes & Actions

URL ParameterFunction CalledDescription
`do=` (empty)Default actionDisplay add production form
`do=add``add()`Create new production order
`do=edit&id={id}`Edit displayLoad production order for editing
`do=update``update()`Update existing production order
`do=show``show()`List production orders with filters
`do=delete&id={id}``delete()`Delete production order
### Required Parameters by Action

Add Production (do=add):

Show/Filter (do=show):

---

๐Ÿงฎ Calculation Methods

Production Cost Calculation

// Raw material total cost
$totalInProductsCost = 0;
for ($i = 1; $i <= $productItr; $i++) {
    $price = (float) filter_input(INPUT_POST, 'price' . $i);
    $quantity = (float) filter_input(INPUT_POST, 'quantity' . $i);
    $inTotalCost = $price * $quantity;
    $totalInProductsCost += $inTotalCost;
}

// Output product cost allocation
$outProductPrice = $outAllCostTot; // Total allocated cost
$outQuantity = (float) filter_input(INPUT_POST, 'outQuantity');
$unitCost = $outAllCostTot / $outQuantity;

Unit Conversion Calculation

$productunitData = $myProductunitEx->queryWithProductIdAndUnitId($productId, $unitId);
$finalquantity = $quantity * $productunitData->productnumber;

FIFO Cost Calculation

$totalPrice = 0;
$remainQuantity = $soldQuantity;

do {
    $buyPriceFromHistoryBook = $buyPricesHistoryBookEX->getBuyPriceOfFirstAvailableSellQuantity($storeId, $productid, $sizeid, $colorid);
    $availableBuyQuantity = $buyPriceFromHistoryBook->buyQuantity - $buyPriceFromHistoryBook->sellQuantity;
    
    if ($availableBuyQuantity >= $remainQuantity) {
        $totalPrice += $remainQuantity * $buyPriceFromHistoryBook->buyprice;
        $remainQuantity = 0;
    } else {
        $totalPrice += $availableBuyQuantity * $buyPriceFromHistoryBook->buyprice;
        $remainQuantity -= $availableBuyQuantity;
    }
} while ($remainQuantity > 0 && isset($buyPriceFromHistoryBook->id));

$averageCost = $totalPrice / $soldQuantity;

---

๐Ÿ”’ Security & Permissions

Authentication Requirements

include_once("../public/authentication.php");

Input Validation

Data Integrity

---

๐Ÿ“Š Performance Considerations

Database Optimization Tips

1. Critical Indexes:

- productionout(outStore, inStore, sysDate)

- productionoutdetails(productionOutId)

- storedetail(storeid, productid)

- buypriceshistorybook(storeId, productid, sizeid, colorid, theDate)

2. Query Optimization:

- Batch inventory updates within transactions

- Efficient FIFO price calculation

- Minimize N+1 query patterns

3. Memory Management:

- Process raw materials incrementally

- Clean up temporary variables

- Proper transaction scope

---

๐Ÿงช Testing Scenarios

Test Case 1: Basic Production Order

1. Create production order: 1 chair from 4 legs + 1 seat
2. Set costs: legs $5 each, seat $20, total chair cost $50
3. Verify inventory changes:
   - Chair quantity +1
   - Leg quantity -4
   - Seat quantity -1
4. Check cost updates:
   - Chair buy price updated to $50
   - Price history recorded
5. Verify supplier debt increased by $50
6. Check daily accounting entry created

Test Case 2: Size/Color Variant Production

1. Create red large chair from materials
2. Verify hasSizeColor encoding works
3. Check variant-specific inventory updates
4. Confirm size/color inventory tracking

Test Case 3: Edit and Delete Operations

1. Create production order
2. Edit with different materials/quantities
3. Verify old data reversed and new applied
4. Delete order
5. Confirm all effects reversed:
   - Inventory restored
   - Supplier debt reversed
   - Accounting entry reversed

---

๐Ÿ“š Related Documentation

---

Documented By: AI Assistant

Review Status: โœ… Complete

Next Review: When major changes occur