# Production Out Many Controller Documentation

**File**: `/controllers/productionOutManyController.php`  
**Purpose**: Manages complex production/manufacturing processes with multiple output products and external manufacturing costs  
**Last Updated**: December 20, 2024  
**Total Functions**: 17  
**Lines of Code**: ~1,019

---

## 📋 Overview

The Production Out Many Controller handles advanced manufacturing operations where multiple raw materials are converted into multiple finished products, typically involving external manufacturing services. It manages:
- Multiple raw material input consumption
- Multiple finished product output creation
- External supplier manufacturing costs
- Complex cost allocation across outputs
- Inventory management for multi-product manufacturing
- Daily accounting entries for complex transactions
- Manufacturing batch tracking with production numbers

### Primary Functions
- [x] Create complex production orders (multiple inputs, multiple outputs)
- [x] External manufacturing cost management
- [x] Multi-product cost allocation
- [x] Raw material and finished goods inventory updates
- [x] Supplier debt management for manufacturing services
- [x] Production batch numbering and tracking
- [x] Daily accounting entry generation
- [x] Size/color variant support for all products
- [x] Unit of measure conversions for inputs and outputs

### Related Controllers
- [productionOutController.php](productionOutController.md) - Simple production (single output)
- [productionEquationController.php](productionEquationController.md) - Production formulas
- [productionRateController.php](productionRateController.md) - Production rates
- [buyBillController.php](#) - Raw material purchasing

---

## 🗄️ Database Tables

### Primary Tables (Direct Operations)
| Table Name | Purpose | Key Columns |
|------------|---------|-------------|
| **productionoutmany** | Production batch headers | id, title, inStore, outStore, supplier, productionoutmanynum, comment, userid, sysDate, del, dailyentryid |
| **productionoutmanyinproducts** | Raw material inputs | id, productionoutmanyid, productid, sizeid, colorid, prounitid, quantity, unitpriceraw, unitManufPrice, inTotalCostUnit, inTotalCost |
| **productionoutmanyoutproducts** | Finished product outputs | id, productionoutmanyid, productid, sizeid, colorid, prounitid, quantity, unitprice, cost |

### Inventory Tables (Modified)
| Table Name | Purpose | Key Columns |
|------------|---------|-------------|
| **storedetail** | Main inventory quantities | storedetailid, storeid, productid, productquantity, userid, storedetaildate |
| **sizecolorstoredetail** | Size/color variant inventory | id, storeid, productid, sizeid, colorid, quantity, userid, sysdate |
| **storereport** | Inventory movement log | storereportid, productid, sizeid, colorid, storeid, productquantity, productbefore, productafter, storereporttype, storereportmodelid, processname, tablename, storereportdate, userid |

### Financial Tables (Modified)
| Table Name | Purpose | Key Columns |
|------------|---------|-------------|
| **buypriceshistorybook** | Purchase price history | id, theDate, storeId, productid, sizeid, colorid, buyprice, buyQuantity, sellQuantity, del, userid, sysDate |
| **supplier** | Supplier master data | supplierid, suppliername, suppliercurrentDebt, supplierdate, userid |
| **supplierdebtchange** | Supplier debt change log | supplierdebtchangeid, supplierid, supplierdebtchangebefore, supplierdebtchangeamount, supplierdebtchangeafter, supplierdebtchangetype, processname, supplierdebtchangemodelid, tablename, comment, supplierdebtchangedate, userid, dailyentryid |

### Reference Tables
| Table Name | Purpose | Key Columns |
|------------|---------|-------------|
| **product** | Product master data | productId, productName, productCatId, productBuyPrice, lastbuyprice, meanbuyprice |
| **productcat** | Product categories | productCatId, productCatName |
| **productunit** | Unit conversions | productunitid, productid, unitname, productnumber, proUnitBuyPrice |
| **store** | Store/warehouse definitions | storeId, storeName, conditions, treeId |
| **programsettings** | System configuration | programsettingsid, settingkey, settingvalue |

---

## 🔑 Key Functions

### 1. **Default Action** - Add Production Form
**Location**: Line 211  
**Purpose**: Display form for creating new complex production batches

**Function Signature**:
```php
// Triggered when: do= (empty)
```

**Process Flow**:
1. Load all active stores for dropdowns
2. Generate next production batch number
3. Load manufacturing settings
4. Set form permissions and flags
5. Display add form template

**Production Number Generation**:
```php
$productionoutmanynum = 0;
$allExecution = $productionOutManyEX->getLastRow();
$productionoutmanynum = (int) $allExecution->id + 1;
$smarty->assign('productionoutmanynum', $productionoutmanynum);
```

---

### 2. **add()** - Create Complex Production Batch
**Location**: Line 414  
**Purpose**: Process complex manufacturing operation with multiple inputs and outputs

**Function Signature**:
```php
function add()
```

**Process Flow**:
1. Create production batch header with unique number
2. Process multiple output products
3. Process multiple input raw materials
4. Calculate total costs and allocations
5. Update inventory levels for all products
6. Update supplier debt for manufacturing costs
7. Generate daily accounting entry

**Transaction Control**:
```php
$mytransactions = new Transaction();
try {
    // All production operations
    $mytransactions->commit();
    doInventoryDailyEntry($productionOutMany);
} catch (Exception $e) {
    $mytransactions->rollback();
}
```

**Production Number Logic**:
```php
if (empty($id)) {
    $count = $productionOutManyEX->countProductionoutmanynumValue($productionOutMany->productionoutmanynum);
    if ($count > 0) {
        $productionOutMany->productionoutmanynum = (int) $productionOutManyEX->getMaxValOfProductionoutmanynum() + 1;
    }
    $id = $productionoutmanyid = $productionOutManyDAO->insert($productionOutMany);
}
```

**Output Product Processing**:
```php
for ($i = 1; $i <= $rowitr; $i++) {
    $productId = filter_input(INPUT_POST, 'pro' . $i);
    $quantity = (float) filter_input(INPUT_POST, 'actual' . $i);
    $actualCost = (float) filter_input(INPUT_POST, 'actualCost' . $i);
    $unitPrice = $actualCost / $quantity;

    if ($productId > 0 && $unitId > 0 && $quantity > 0) {
        // Insert output product record
        // Decrease inventory (removing from output store)
        decrease($productId, $sizeId, $colorId, $finalquantity, $id, $productionOutMany->outStore);
    }
}
```

**Input Product Processing**:
```php
for ($i = 1; $i <= $inProItr; $i++) {
    $unitManufPrice = (float) filter_input(INPUT_POST, 'unitManufPrice' . $i);
    $inTotalCost = $quantity * $inTotalCostUnit;

    if ($productId > 0 && $unitId > 0 && $quantity > 0) {
        $allCost += $inTotalCost;
        $allUnitManufPrice += $quantity * $unitManufPrice;
        
        // Insert input product record
        // Increase inventory (adding to input store)
        increase($productId, $sizeId, $colorId, $finalquantity, $id, $productionOutMany->inStore);
        
        // Update product pricing
        increaseBuyPricesHistoryBookBuyQuantity(date('Y-m-d'), $productionOutMany->inStore, $productId, $sizeId, $colorId, $inTotalCostUnit, $finalquantity);
    }
}
```

---

### 3. **details()** - View Production Details
**Location**: Line 239  
**Purpose**: Display read-only view of production batch with all inputs and outputs

**Process Flow**:
1. Load production batch header
2. Load all output products with display names
3. Load all input products with display names
4. Build product names with category/variant info
5. Display details template

**Product Name Building**:
```php
foreach ($outProducts as $value) {
    $value->productName = $value->productName . '/ ' . $value->productCatName;
    if (!empty($value->sizeid) && !empty($value->colorid)) {
        $value->productid = "hasSizeColor" . $value->productid . "-" . $value->sizeid . "-" . $value->colorid;
        $value->productName .= '/ ' . $value->sizeName . '/ ' . $value->colorName;
    }
}
```

---

### 4. **edit()** - Edit Production Batch
**Location**: Line 280  
**Purpose**: Load existing production batch for modification

**Process Flow**:
1. Load production batch header
2. Load all output products for editing
3. Load all input products for editing
4. Build product display names
5. Assign data to edit template

**Similar to details but with edit capabilities and form pre-population.**

---

### 5. **update()** - Update Production Batch
**Location**: Line 322  
**Purpose**: Modify existing production batches using delete-and-recreate pattern

**Function Signature**:
```php
function update()
```

**Process Flow**:
1. Delete existing production batch (reverses all effects)
2. Create new production batch 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 for complex multi-product scenarios.

---

### 6. **show()** - List Production Batches
**Location**: Line 331  
**Purpose**: Display filtered list of production batches with search capabilities

**Filter Options**:
- Output store selection
- Input store selection
- Supplier selection
- Production batch number
- Date range filtering
- Batch ID

**Default Filter Logic**:
```php
if ($query == " and productionoutmany.del=0 ") {
    $from = $to = date('Y-m-d');
    $query .= " and date(productionoutmany.sysDate) >= '$from' and date(productionoutmany.sysDate) <= '$to' ";
}
```

---

### 7. **delete()** - Delete Production Batch
**Location**: Line 571  
**Purpose**: Reverse all effects of a complex production batch and remove from system

**Function Signature**:
```php
function delete()
```

**Process Flow**:
1. Load production batch data
2. Reverse all output product inventory decreases
3. Reverse all input product inventory increases
4. Reverse supplier debt changes
5. Delete all detail records (input and output)
6. Delete batch header record
7. Reverse daily accounting entry

**Output Products Reversal**:
```php
$outProducts = $productionOutManyOutProductDAO->queryByProductionoutmanyid($id);
foreach ($outProducts as $value) {
    $productunitData = $myProductunitEx->queryWithProductIdAndUnitId($value->productid, $value->prounitid);
    $finalquantity = $value->quantity * $productunitData->productnumber;
    // Increase back to output store (reverse the decrease)
    increase($value->productid, $value->sizeid, $value->colorid, $finalquantity, $id, $productionOutMany->outStore);
}
```

**Input Products Reversal**:
```php
$inProducts = $productionOutManyInProductDAO->queryByProductionoutmanyid($id);
foreach ($inProducts as $value) {
    $productunitData = $myProductunitEx->queryWithProductIdAndUnitId($value->productid, $value->prounitid);
    $finalquantity = $value->quantity * $productunitData->productnumber;
    // Decrease from input store (reverse the increase)
    decrease($value->productid, $value->sizeid, $value->colorid, $finalquantity, $id, $productionOutMany->inStore);
}
```

---

### 8. **decrease()** - Reduce Inventory
**Location**: Line 633  
**Purpose**: Decrease product quantities in inventory (for output products taken from store)

**Function Signature**:
```php
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 with "external manufacturing" label

**Inventory Report Label**: "تصنيع خارجى للمنتج" (External manufacturing for product)

---

### 9. **increase()** - Add to Inventory
**Location**: Line 684  
**Purpose**: Increase product quantities in inventory (for input products added to store)

**Function Signature**:
```php
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 with "external manufacturing" label

---

### 10. **increaseBuyPricesHistoryBookBuyQuantity()** - Price History Update
**Location**: Line 906  
**Purpose**: Record new inventory purchases in price history for input products

**Function Signature**:
```php
function increaseBuyPricesHistoryBookBuyQuantity($theDate, $storeId, $productid, $sizeid, $colorid, $buyprice, $buyQuantity)
```

**Features**:
- Records purchase date and allocated cost
- Supports size/color variants
- Enables FIFO cost calculation
- Tracks available quantities for future consumption

---

### 11. **doInventoryDailyEntry()** - Complex Accounting Integration
**Location**: Line 981  
**Purpose**: Generate daily accounting entries for complex production transactions

**Function Signature**:
```php
function doInventoryDailyEntry($productionOutMany)
```

**Process Flow**:
1. Calculate total raw material costs (output products)
2. Calculate total manufacturing costs (supplier charges)
3. Get store and supplier account tree IDs
4. Create debit entry for input store (finished products)
5. Create credit entries for output store and supplier
6. Link to production batch for reference

**Accounting Logic**:
```php
$rawMaterialCost = R::getCell('select sum(cost) from productionoutmanyoutproducts where productionoutmanyid=' . $productionOutMany->id);
$suppCost = R::getCell('select sum(unitManufPrice*quantity) from productionoutmanyinproducts where productionoutmanyid=' . $productionOutMany->id);

$dailyEntryDebtorArray = array();
// Debit: Input store (finished products received)
$dailyEntryDebtor->value = $rawMaterialCost + $suppCost;
$dailyEntryDebtor->accountstreeid = $treeIdInStore;

$dailyEntryCreditorArray = array();
// Credit: Output store (raw materials sent)
$dailyEntryCreditor->accountstreeid = $treeIdOutStore;
$dailyEntryCreditor->value = $rawMaterialCost;

// Credit: Supplier (manufacturing services)
$dailyEntryCreditor->accountstreeid = $suppData['treeId'];
$dailyEntryCreditor->value = $suppCost;
```

---

## 🔄 Workflows

### Workflow 1: Complex Production Batch Process
```
┌─────────────────────────────────────────────────────────────┐
│            START: Complex Production Batch                 │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│  1. Define Production Batch Parameters                     │
│     - Set batch title and number                           │
│     - Choose input store (for finished products)           │
│     - Choose output store (for raw materials)              │
│     - Select external manufacturer/supplier                │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│  2. Define Output Products (Raw Materials Sent)            │
│     FOR EACH output product:                               │
│       │                                                     │
│       ├─→ Select product (with variants)                   │
│       ├─→ Choose unit of measure                           │
│       ├─→ Set quantity to send                             │
│       └─→ Set total cost allocation                        │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│  3. Define Input Products (Finished Goods Received)        │
│     FOR EACH input product:                                │
│       │                                                     │
│       ├─→ Select product (with variants)                   │
│       ├─→ Choose unit of measure                           │
│       ├─→ Set quantity received                            │
│       ├─→ Set raw material unit cost                       │
│       └─→ Set manufacturing unit cost                      │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│  4. Process Production Batch                               │
│     - Create batch header with unique number               │
│     - Generate unique batch ID if conflict exists          │
│     - Calculate total costs and allocations                │
│     - Validate all required data                           │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│  5. Update Output Store Inventory                          │
│     - Decrease raw material quantities                     │
│     - Handle size/color variant tracking                   │
│     - Create inventory movement reports                     │
│     - Process unit conversions                             │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│  6. Update Input Store Inventory                           │
│     - Increase finished product quantities                 │
│     - Handle size/color variant tracking                   │
│     - Create inventory movement reports                     │
│     - Update product pricing information                   │
│     - Record purchase price history                        │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│  7. Update Financial Records                               │
│     - Update supplier debt balance                         │
│     - Log debt change transaction                          │
│     - Calculate total manufacturing costs                   │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│  8. Generate Complex Accounting Entry                      │
│     - Debit: Input store (finished products)               │
│     - Credit: Output store (raw materials)                 │
│     - Credit: Supplier (manufacturing costs)               │
│     - Link to production batch for reference               │
└─────────────────────────────────────────────────────────────┘
```

---

## 🌐 URL Routes & Actions

| URL Parameter | Function Called | Description |
|---------------|-----------------|-------------|
| `do=` (empty) | Default action | Display add production batch form |
| `do=add` | `add()` | Create new production batch |
| `do=details&id={id}` | Details display | View production batch details |
| `do=edit&id={id}` | Edit display | Load production batch for editing |
| `do=update` | `update()` | Update existing production batch |
| `do=show` | `show()` | List production batches with filters |
| `do=delete&id={id}` | `delete()` | Delete production batch |

### Required Parameters by Action

**Add Production Batch** (`do=add`):
- `title` - Batch title/description
- `inStore` - Input store ID (for finished products)
- `outStore` - Output store ID (for raw materials)
- `supplier` - External manufacturer/supplier ID
- `productionoutmanynum` - Batch number
- `rowitr` - Number of output products
- `pro{i}` - Output product IDs (with hasSizeColor encoding)
- `unit{i}` - Output product unit IDs
- `actual{i}` - Output product quantities
- `actualCost{i}` - Output product total costs
- `inProItr` - Number of input products
- `product{i}` - Input product IDs (with hasSizeColor encoding)
- `unitIdIn{i}` - Input product unit IDs
- `quantity{i}` - Input product quantities
- `price{i}` - Input raw material unit costs
- `unitManufPrice{i}` - Input manufacturing unit costs

**Show/Filter** (`do=show`):
- `outStore` - Output store filter (optional)
- `inStore` - Input store filter (optional)
- `supplier` - Supplier filter (optional)
- `productionoutmanynum` - Batch number filter (optional)
- `from` - Date from filter (optional)
- `to` - Date to filter (optional)
- `outId` - Batch ID filter (optional)

---

## 🧮 Calculation Methods

### Multi-Product Cost Allocation
```php
// Output products (raw materials sent)
for ($i = 1; $i <= $rowitr; $i++) {
    $quantity = (float) filter_input(INPUT_POST, 'actual' . $i);
    $actualCost = (float) filter_input(INPUT_POST, 'actualCost' . $i);
    $unitPrice = $actualCost / $quantity;
    
    $productionOutManyOutProduct->quantity = $quantity;
    $productionOutManyOutProduct->unitprice = $unitPrice;
    $productionOutManyOutProduct->cost = $actualCost;
}
```

### Complex Cost Tracking
```php
// Input products (finished goods received)
$allCost = 0;
$allUnitManufPrice = 0;

for ($i = 1; $i <= $inProItr; $i++) {
    $unitpriceraw = (float) filter_input(INPUT_POST, 'price' . $i);
    $unitManufPrice = (float) filter_input(INPUT_POST, 'unitManufPrice' . $i);
    $inTotalCostUnit = (float) filter_input(INPUT_POST, 'inTotalCostUnit_h' . $i);
    $inTotalCost = $quantity * $inTotalCostUnit;

    $allCost += $inTotalCost;
    $allUnitManufPrice += $quantity * $unitManufPrice;
    
    $productionOutManyInProduct->unitpriceraw = $unitpriceraw;
    $productionOutManyInProduct->unitManufPrice = $unitManufPrice;
    $productionOutManyInProduct->inTotalCostUnit = $inTotalCostUnit;
    $productionOutManyInProduct->inTotalCost = $inTotalCost;
}
```

### Supplier Debt Calculation
```php
// Supplier debt increase by manufacturing costs only
$supdata = $supplierDAO->load($productionOutMany->supplier);
$totaldeptbefore = $supdata->suppliercurrentDebt;
$totaldeptafter = $totaldeptbefore + $allUnitManufPrice; // Only manufacturing costs
updateSupplierDebt($productionOutMany->supplier, $totaldeptafter);
```

---

## 🔒 Security & Permissions

### Authentication Requirements
```php
include_once("../public/authentication.php");
```

### Input Validation
- All numeric inputs cast to appropriate types
- Product and unit IDs validated against database
- Production batch number uniqueness enforced
- Date parameters validated for proper format
- Transaction control prevents partial updates

### Data Integrity
- Automatic batch number generation if conflict
- Transaction rollback on any failure
- Complex inventory movement logging
- Supplier debt change tracking
- Daily accounting entry generation
- Cascading deletion logic for multi-table operations

---

## 📊 Performance Considerations

### Database Optimization Tips
1. **Critical Indexes**:
   - `productionoutmany(outStore, inStore, sysDate, productionoutmanynum)`
   - `productionoutmanyinproducts(productionoutmanyid)`
   - `productionoutmanyoutproducts(productionoutmanyid)`
   - `storedetail(storeid, productid)`

2. **Query Optimization**:
   - Batch operations for multiple products
   - Efficient unit conversion calculations
   - Minimize database round trips
   - Proper transaction scope management

3. **Memory Management**:
   - Process products incrementally
   - Clear arrays after processing
   - Proper variable cleanup
   - Transaction scope optimization

---

## 🧪 Testing Scenarios

### Test Case 1: Basic Multi-Product Manufacturing
```
1. Create batch: Send 10kg fabric + 5m thread → Receive 8 shirts + 2 pants
2. Set costs:
   - Fabric: $50 ($5/kg)
   - Thread: $10 ($2/m)
   - Manufacturing: $30 total
3. Verify inventory changes:
   - Output store: Fabric -10kg, Thread -5m
   - Input store: Shirts +8, Pants +2
4. Check cost allocations and price updates
5. Verify supplier debt increased by $30 (manufacturing only)
6. Check complex accounting entry
```

### Test Case 2: Batch Number Conflict Resolution
```
1. Create batch with number 100
2. Create another batch with same number
3. Verify system auto-generates unique number
4. Check database consistency
```

### Test Case 3: Size/Color Variant Production
```
1. Send red large fabric, blue medium fabric
2. Receive red large shirts, blue medium shirts
3. Verify variant-specific inventory tracking
4. Check size/color inventory updates
```

### Test Case 4: Complex Delete Operation
```
1. Create batch with multiple inputs/outputs
2. Delete batch
3. Verify all effects reversed:
   - All input inventory decreased
   - All output inventory increased
   - Supplier debt reversed
   - Accounting entry reversed
   - All detail records deleted
```

---

## 📚 Related Documentation

- [CLAUDE.md](/Applications/AMPPS/www/erp19/CLAUDE.md) - PHP 8.2 migration guide
- [productionOutController.md](productionOutController.md) - Simple production
- [productionEquationController.md](productionEquationController.md) - Production formulas
- [buyBillController.md](#) - Raw material purchasing

---

**Documented By**: AI Assistant  
**Review Status**: ✅ Complete  
**Next Review**: When major changes occur