# Check Withdrawal Controller Documentation

**File**: `/controllers/checkwithdrawalController.php`  
**Purpose**: Manages check withdrawals for supplier payments with comprehensive financial tracking  
**Last Updated**: December 20, 2024  
**Total Functions**: 10  
**Lines of Code**: ~1,027

---

## 📋 Overview

The Check Withdrawal Controller is a sophisticated financial management module that handles check payments to suppliers with comprehensive account tracking and debt management. It handles:
- Check withdrawal creation and processing
- Bank account balance updates
- Supplier debt reduction tracking
- Account movement recording
- Daily entry generation for accounting
- Multi-criteria search and filtering
- Bulk operations management
- Complete audit trail maintenance

### Primary Functions
- [x] Create check withdrawals for supplier payments
- [x] Update bank account balances automatically
- [x] Track supplier debt changes
- [x] Record account movements
- [x] Generate accounting daily entries
- [x] Search by date range, supplier, or check ID
- [x] Edit check details (user and notes only)
- [x] Delete/cancel check withdrawals with reversal
- [x] Bulk operations on multiple checks
- [x] Supplier concurrency management

### Financial Impact
**When Check Withdrawn:**
1. **Bank Account**: Decreased by check amount
2. **Supplier Debt**: Decreased by check amount  
3. **Account Movement**: Withdrawal transaction recorded
4. **Daily Entry**: Debit supplier account, credit bank account

**When Check Cancelled:**
1. **Bank Account**: Increased by check amount (reversed)
2. **Supplier Debt**: Increased by check amount (reversed)
3. **Account Movement**: Deposit transaction recorded
4. **Daily Entry**: Reversed automatically

### Related Controllers
- [cashSaveFlowController.php](cashSaveFlowController.md) - Cash flow reporting
- [supplierPayedDeptController.php](#) - Other supplier payments
- [bankaccountController.php](#) - Bank account management
- [supplierController.php](#) - Supplier management

---

## 🗄️ Database Tables

### Primary Tables (Direct Operations)
| Table Name | Purpose | Key Columns |
|------------|---------|-------------|
| **checkwithdrawal** | Check withdrawal records | checkwithdrawalid, bankaccountid, supplierid, checkwithdrawalamount, checkwithdrawalnumber, conditions, dailyentryid |
| **accountmovement** | Bank account movements | accountmovementid, accountid, accountmovementamount, accountmovementtype, tablename, accountmovementmodelid |
| **supplierdebtchange** | Supplier debt tracking | supplierdebtchangeid, supplierid, supplierdebtchangeamount, supplierdebtchangetype, tablename, supplierdebtchangemodelid |

### Reference Tables
| Table Name | Purpose | Key Columns |
|------------|---------|-------------|
| **bankaccount** | Bank account master | accountid, accountname, accountbeginingbalance, bankid, treeId |
| **bank** | Bank information | bankid, bankname |
| **supplier** | Supplier master data | supplierid, suppliername, suppliercurrentDebt, treeId, inUse |
| **user** | System users | userid, username |

### Accounting Tables
| Table Name | Purpose | Key Columns |
|------------|---------|-------------|
| **dailyentry** | Journal entry header | dailyentryid, entryComment, userid |
| **dailyentrycreditor** | Credit side entries | dailyentrycreditorid, dailyentryid, accountstreeid, value |
| **dailyentrydebtor** | Debit side entries | dailyentrydebttorid, dailyentryid, accountstreeid, value |
| **accountstree** | Chart of accounts | accountstreeid, accountname |

---

## 🔑 Key Functions

### 1. **Default Action** - Add Check Form
**Location**: Lines 141-164  
**Purpose**: Display form to create new check withdrawal

**Process Flow**:
1. Load all banks with extended information
2. Load all suppliers for selection
3. Display add form template
4. Set custom validation flag

**Template Variables**:
- `$bank` - Available banks list
- `$allsuplierdata` - Available suppliers list
- `$customdepositcheck = 1` - Enable custom validation

---

### 2. **add** - Create Check Withdrawal
**Location**: Lines 401-624  
**Purpose**: Process new check withdrawal with full financial impact

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

**Process Flow**:

#### **Phase 1: Input Validation and Setup**
```php
$supplierid = $_POST["supplierid"];
$accountid = (int) $_POST["accountid"];
$checkwithdrawalamount = $_POST["txtAmount"];
$checkwithdrawalnumber = $_POST["txtcheckNum"];
$checkwithdrawaluser = $_POST["txtUser"];
$checkwithdrawalnote = $_POST["textNote"];
```

#### **Phase 2: Check Withdrawal Record Creation**
```php
$checkWithdrawal->bankaccountid = $accountid;
$checkWithdrawal->supplierid = $supplierid;
$checkWithdrawal->accountbeforevalue = $accountbeginingbalance;
$checkWithdrawal->checkwithdrawalamount = $checkwithdrawalamount;
$checkWithdrawal->checkwithdrawaldate = date("Y-m-d H:i:s");
$checkWithdrawal->conditions = 0; // Active
$checkWithdrawal->userid = $_SESSION['userid'];

$checkWithdrawalId = $checkWithdrawalDAO->insert($checkWithdrawal, $checkwithdrawalnote);
```

#### **Phase 3: Supplier Debt Management**
```php
// Load supplier with concurrency control
$supplierdata = getSupplierDataFromSupplierInUseSP($supplierid);
$debtBefore = $supplierdata->suppliercurrentDebt;

// Update supplier debt (decrease by check amount)
$Supplier->suppliercurrentDebt = ($debtBefore - $checkwithdrawalamount);
$SupplierEX->updatedept($Supplier);

// Record debt change
$supDebtChange->supplierdebtchangebefore = $debtBefore;
$supDebtChange->supplierid = $supplierid;
$supDebtChange->supplierdebtchangeamount = $checkwithdrawalamount;
$supDebtChange->supplierdebtchangetype = 1; // Decrease
$supDebtChange->tablename = "checkwithdrawalController.php";
$supDebtChange->supplierdebtchangemodelid = $checkWithdrawalId;
$supDebtChange->supplierdebtchangeafter = $debtBefore - $checkwithdrawalamount;
$supDebtChange->processname = "دفع شيك"; // "Check payment"

$supDebtChangeDAO->insert($supDebtChange);
```

#### **Phase 4: Bank Account Update**
```php
$accoundatat = $accountDAO->load($accountid);
$accountBefore = $accoundatat->accountbeginingbalance;

// Update account balance (decrease by check amount)
$account->accountbeginingbalance = $accountBefore - $checkwithdrawalamount;
$accountExtDAO->updateacount($account);

// Record account movement
$accountMove->accountmovementbefore = $accountBefore;
$accountMove->accountid = $accountid;
$accountMove->accountmovementamount = $checkwithdrawalamount;
$accountMove->accountmovementafter = $accountBefore - $checkwithdrawalamount;
$accountMove->accountmovementtype = 1; // Withdrawal
$accountMove->processname = "سحب شيك"; // "Check withdrawal"
$accountMove->tablename = "checkwithdrawalController.php";
$accountMove->accountmovementmodelid = $checkWithdrawalId;

$accountMoveDAO->insert($accountMove);
```

#### **Phase 5: Daily Entry Generation**
```php
$dailyEntry->entryComment = 'تم عمل سحب شيك للمورد (  ' . $supplierdata->suppliername . ' )';

// Debit: Supplier account (debt reduction)
$dailyEntryDebtor->value = $checkwithdrawalamount;
$dailyEntryDebtor->accountstreeid = $supplierdata->treeId;

// Credit: Bank account
$dailyEntryCreditor->value = $checkwithdrawalamount;
$accountData = $accountDAO->load($accountid);
$dailyEntryCreditor->accountstreeid = $accountData->treeId;

$returnedData = insertEntery($dailyEntry, $dailyEntryDebtorArray, $dailyEntryCreditorArray, 1, $checkWithdrawalId, "checkwithdrawalController.php?do=show&id=$checkWithdrawalId");
```

**Error Handling**:
- Transaction rollback on any failure
- Supplier concurrency lock release
- Validation of account balances

**Return Values**:
- `"0"` - Success
- `"1"` - Error (insufficient funds or validation failure)

---

### 3. **show** - Display Check List
**Location**: Lines 627-690  
**Purpose**: Search and display check withdrawals based on criteria

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

**Search Criteria**:

#### **Date Range Search**:
```php
$from = $_REQUEST["from"];
$to = $_REQUEST["to"];

if (isset($to) && $to != "" && isset($from) && $from != "") {
    $message = "عرض المسحوبات  من تاريخ : " . $from . "  الى تاريخ  " . $to;
    $shownData = $checkWithdrawalExtDAO->queryBydateExt($from, $to);
}
```

#### **Supplier Filter**:
```php
$supplierid = $_REQUEST["supplierid"];

if (isset($supplierid) && $supplierid != "-1") {
    $mysupplierdata = $SupplierDAO->load($supplierid);
    $message = "عرض المسحوبات للمورد : " . $mysupplierdata->suppliername;
    $shownData = $checkWithdrawalExtDAO->queryWithSupplieridExt($supplierid);
}
```

#### **Specific Check ID**:
```php
$id = (int) $_REQUEST["id"];

if (isset($id) && $id > 0) {
    $message = "عرض المسحوبات  رقم: " . $id;
    $temp = $checkWithdrawalExtDAO->loadExt($id);
    $shownData = array($temp);
}
```

#### **Default (Today's Checks)**:
```php
else {
    $message = "عرض المسحوبات  من تاريخ : " . date("Y-m-d") . "  الى تاريخ :   " . date("Y-m-d");
    $shownData = $checkWithdrawalExtDAO->queryBydateExt(date("Y-m-d"), date("Y-m-d"));
}
```

---

### 4. **delete** - Cancel Check Withdrawal
**Location**: Lines 694-850  
**Purpose**: Reverse check withdrawal with complete financial reversal

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

**Process Flow**:

#### **Phase 1: Load Check Data**
```php
$checkdata = $checkWithdrawalDAO->load($checkid);
$accountid = $checkdata->bankaccountid;
$checkwithdrawalamount = $checkdata->checkwithdrawalamount;
$supplierid = $checkdata->supplierid;
```

#### **Phase 2: Reverse Supplier Debt**
```php
$supplierdata = getSupplierDataFromSupplierInUseSP($supplierid);
$debtBefore = $supplierdata->suppliercurrentDebt;

// Increase supplier debt (reverse the payment)
$Supplier->suppliercurrentDebt = ($debtBefore + $checkwithdrawalamount);
$SupplierEX->updatedept($Supplier);

// Record reversal in debt change
$supDebtChange->supplierdebtchangebefore = $debtBefore;
$supDebtChange->supplierdebtchangeamount = $checkwithdrawalamount;
$supDebtChange->supplierdebtchangetype = 0; // Increase
$supDebtChange->tablename = "checkwithdrawalController.php";
$supDebtChange->supplierdebtchangeafter = $debtBefore + $checkwithdrawalamount;
$supDebtChange->processname = "حذف دفع شيك"; // "Delete check payment"

$supDebtChangeDAO->insert($supDebtChange);
```

#### **Phase 3: Mark Check as Deleted**
```php
$checkWithdrawal->conditions = 1; // Deleted
$checkWithdrawal->checkwithdrawalid = $checkid;
$checkWithdrawalExtDAO->updatedel($checkWithdrawal);
```

#### **Phase 4: Reverse Bank Account**
```php
$accountdata = $accountDAO->load($accountid);
$accountBefore = $accountdata->accountbeginingbalance;

// Increase account balance (reverse the withdrawal)
$account->accountbeginingbalance = $accountBefore + $checkwithdrawalamount;
$accountExtDAO->updateacount($account);

// Record reversal movement
$accountMove->accountmovementbefore = $accountBefore;
$accountMove->accountmovementamount = $checkwithdrawalamount;
$accountMove->accountmovementafter = $accountBefore + $checkwithdrawalamount;
$accountMove->accountmovementtype = 0; // Deposit
$accountMove->processname = "الغاء سحب شيك"; // "Cancel check withdrawal"
$accountMove->tablename = "wirhdrawalCheckController.php";

$accountMoveDAO->insert($accountMove);
```

#### **Phase 5: Reverse Daily Entry**
```php
// Reverse the original daily entry
if (isset($dailyentry) && $dailyentryid2 == '') {
    reverseEntryWithItsID($dailyentry, 1);
} else {
    reverseEntryWithItsID($dailyentryid2, 1);
}
```

**Return Values**:
- `"sucess"` - Successful cancellation
- Error message string - If cancellation failed

---

### 5. **edit** - Load Check for Editing
**Location**: Lines 853-879  
**Purpose**: Load check data with debt information for editing

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

**Process Flow**:
1. Load check withdrawal with supplier information
2. Load related debt change information
3. Calculate debt before/after values
4. Return data object for form population

**Debt Information Loading**:
```php
$showData = $checkWithdrawalExtDAO->queryByIdExtwithsuplier($id);

if ($showData->suppliername) {
    $debtRow = R::getRow('select supplierdebtchangebefore,supplierdebtchangeafter from supplierdebtchange where tablename="checkwithdrawalController.php" and supplierdebtchangemodelid=' . $id);
    $debtBefore = $debtRow['supplierdebtchangebefore'];
    $debtAfter = $debtRow['supplierdebtchangeafter'];
}
```

---

### 6. **update** - Update Check Details
**Location**: Lines 882-902  
**Purpose**: Update only user and note fields (amount cannot be changed)

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

**Updateable Fields**:
- `checkwithdrawaluser` - Check recipient name
- `checkwithdrawalnote` - Additional notes

**Restriction**: Check amount, supplier, and bank account cannot be changed after creation.

---

### 7. **execute** - Bulk Operations
**Location**: Lines 927-984  
**Purpose**: Perform bulk operations on multiple selected checks

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

**Process Flow**:
1. Get operation type and selected check IDs
2. For each selected check:
   - Validate operation (only active checks can be deleted)
   - Execute delete operation
   - Record success/failure messages
3. Display results summary

**Operation Types**:
- `1` - Bulk delete/cancel checks

**Validation**:
```php
if ($operationType == '1' && $conditions == 0) { // Can delete only active checks
    $note = delete($checkId);
    if ($note != "sucess") {
        $outputString .= $checkwithdrawalnumber . ": " . $note . "<br/>";
    } else {
        $outputString .= $checkwithdrawalnumber . ": تمت العملية بنجاح <br/>";
    }
} else {
    $outputString .= $checkwithdrawalnumber . ": لا يمكن الغاء هذا الشيك لانه ملغى سابقا<br/>";
}
```

---

### 8. **getSupplierDataFromSupplierInUseSP** - Concurrency Management
**Location**: Lines 986-1007  
**Purpose**: Load supplier data with concurrency control to prevent debt conflicts

**Function Signature**:
```php
function getSupplierDataFromSupplierInUseSP($supplier)
```

**Concurrency Logic**:
```php
$supplier_data = $SupplierEX->callSupplierInUseSP($supplier);

while ($supplier_data->suppliercurrentDebt == 'in_use') {
    sleep(1); // Wait 1 second
    $noOfTries++;
    if ($noOfTries > 15) { // Max 15 seconds wait
        // Force unlock supplier
        R::exec('UPDATE supplier SET inUse = 0 where supplierid = ' . $supplier);
    }
    $supplier_data = $SupplierEX->callSupplierInUseSP($supplier);
}
```

**Purpose**: Prevents multiple users from simultaneously modifying the same supplier's debt, which could lead to data corruption.

---

## 🔄 Workflows

### Workflow 1: Check Withdrawal Creation
```
┌─────────────────────────────────────────────────────────────┐
│                START: User Creates Check                    │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│  1. Form Input Validation                                   │
│     - Supplier ID and name                                  │
│     - Bank account selection                                │
│     - Check amount and number                               │
│     - Check recipient and notes                             │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│  2. Create Check Withdrawal Record                          │
│     - Insert into checkwithdrawal table                    │
│     - Record check details and timestamp                    │
│     - Set conditions = 0 (active)                          │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│  3. Update Supplier Debt                                    │
│     - Load supplier with concurrency control               │
│     - Calculate new debt (current - check amount)          │
│     - Update supplier record                                │
│     - Record debt change transaction                        │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│  4. Update Bank Account                                     │
│     - Load current account balance                          │
│     - Calculate new balance (current - check amount)       │
│     - Update account record                                 │
│     - Record account movement transaction                   │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│  5. Generate Accounting Entry                               │
│     - Create daily entry header                             │
│     - Debit: Supplier account (debt reduction)             │
│     - Credit: Bank account (cash outflow)                  │
│     - Link entry ID to check withdrawal                    │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│  6. Finalize Transaction                                    │
│     - Commit database transaction                           │
│     - Release supplier concurrency lock                    │
│     - Return success status                                 │
└─────────────────────────────────────────────────────────────┘
```

---

### Workflow 2: Check Withdrawal Cancellation
```
┌─────────────────────────────────────────────────────────────┐
│              START: User Cancels Check                      │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│  1. Load Check Data                                         │
│     - Retrieve original check withdrawal record            │
│     - Get check amount, supplier ID, account ID            │
│     - Verify check is active (conditions = 0)              │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│  2. Reverse Supplier Debt                                   │
│     - Load supplier with concurrency control               │
│     - Increase debt by check amount (reverse payment)      │
│     - Update supplier record                                │
│     - Record debt change as increase                       │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│  3. Mark Check as Deleted                                   │
│     - Set conditions = 1 (deleted)                         │
│     - Update check withdrawal record                        │
│     - Preserve original data for audit                     │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│  4. Reverse Bank Account                                    │
│     - Load current account balance                          │
│     - Increase balance by check amount (reverse withdrawal) │
│     - Update account record                                 │
│     - Record account movement as deposit                    │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│  5. Reverse Accounting Entry                                │
│     - Locate original daily entry                           │
│     - Create reversing entry                                │
│     - Update daily entry status                             │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│  6. Complete Reversal                                       │
│     - Commit transaction                                    │
│     - Release supplier concurrency lock                    │
│     - Return success status                                 │
└─────────────────────────────────────────────────────────────┘
```

---

## 🌐 URL Routes & Actions

| URL Parameter | Function Called | Description |
|---------------|----------------|-------------|
| (no parameters) | Default action | Display add check form |
| `do=add` | `add()` | Process new check withdrawal |
| `do=show` | `show()` | Display check list with filters |
| `do=delete` | `delete()` | Cancel/delete check withdrawal |
| `do=edit` | `edit()` | Load check data for editing |
| `do=update` | `update()` | Update check user/notes only |
| `do=details` | `edit()` | Display check details (read-only) |
| `do=editprint` | `edit()` | Display check in print format |
| `do=executeOperation` | `execute()` | Bulk operations on selected checks |
| `do=sucess` | Success page | Display success message |
| `do=error` | Error page | Display error message |

### Required Parameters by Action

**Create Check** (`do=add`):
- `supplierid` - Supplier ID
- `accountid` - Bank account ID  
- `txtAmount` - Check amount
- `txtcheckNum` - Check number
- `txtUser` - Check recipient name
- `textNote` - Optional notes

**Show Checks** (`do=show`):
- `from` - Start date (optional)
- `to` - End date (optional)
- `supplierid` - Supplier filter (optional)
- `id` - Specific check ID (optional)

**Delete Check** (`do=delete`):
- `id` - Check withdrawal ID
- `action` - Daily entry ID (optional)
- `dailyentryid` - Daily entry ID (POST, optional)

**Edit Check** (`do=edit`):
- `id` - Check withdrawal ID

**Update Check** (`do=update`):
- `checkwithdrawalid` - Check ID
- `txtUser` - Updated recipient name
- `textNote` - Updated notes

**Bulk Operations** (`do=executeOperation`):
- `operation` - Operation type (1=delete)
- `choosedItem[]` - Array of check IDs
- `dailyentryid` - Daily entry ID for reversals

---

## 🧮 Financial Calculations

### Check Withdrawal Impact
```php
// Bank Account Balance
$newAccountBalance = $currentAccountBalance - $checkAmount;

// Supplier Debt  
$newSupplierDebt = $currentSupplierDebt - $checkAmount;

// Account Movement
$accountMovement = [
    'before' => $currentAccountBalance,
    'amount' => $checkAmount,
    'after' => $newAccountBalance,
    'type' => 1  // Withdrawal
];

// Supplier Debt Change
$supplierDebtChange = [
    'before' => $currentSupplierDebt,
    'amount' => $checkAmount,
    'after' => $newSupplierDebt,
    'type' => 1  // Decrease
];
```

### Check Cancellation Impact
```php
// Bank Account Balance (Reversal)
$newAccountBalance = $currentAccountBalance + $checkAmount;

// Supplier Debt (Reversal)
$newSupplierDebt = $currentSupplierDebt + $checkAmount;

// Account Movement (Reversal)
$accountMovement = [
    'before' => $currentAccountBalance,
    'amount' => $checkAmount,
    'after' => $newAccountBalance,
    'type' => 0  // Deposit
];

// Supplier Debt Change (Reversal)
$supplierDebtChange = [
    'before' => $currentSupplierDebt,
    'amount' => $checkAmount,
    'after' => $newSupplierDebt,
    'type' => 0  // Increase
];
```

### Daily Entry Structure
```php
// Debit Side: Supplier Account (Accounts Payable decrease)
$debitEntry = [
    'accountstreeid' => $supplier->treeId,
    'value' => $checkAmount,
    'description' => 'Check payment to supplier'
];

// Credit Side: Bank Account (Cash decrease)
$creditEntry = [
    'accountstreeid' => $bankAccount->treeId,
    'value' => $checkAmount,
    'description' => 'Check withdrawal from bank'
];
```

---

## 🔒 Security & Permissions

### Access Control
```php
// All actions require authentication
include_once("../public/authentication.php");

// User session tracking
$checkWithdrawal->userid = $_SESSION['userid'];
```

### Input Validation
```php
// Type casting for critical fields
$accountid = (int) $_POST["accountid"];
$id = (int) $_REQUEST["id"];

// SQL injection prevention through DAO layer
// All database operations use parameterized queries
```

### Concurrency Control
```php
// Supplier locking mechanism
function getSupplierDataFromSupplierInUseSP($supplier) {
    $supplier_data = $SupplierEX->callSupplierInUseSP($supplier);
    
    while ($supplier_data->suppliercurrentDebt == 'in_use') {
        sleep(1); // Wait for lock release
        $noOfTries++;
        
        if ($noOfTries > 15) {
            // Force unlock after 15 seconds
            R::exec('UPDATE supplier SET inUse = 0 where supplierid = ' . $supplier);
        }
        
        $supplier_data = $SupplierEX->callSupplierInUseSP($supplier);
    }
    
    return $supplier_data;
}
```

### Transaction Integrity
```php
// Database transactions ensure consistency
$mytransactions = new Transaction();
try {
    // All operations
    $mytransactions->commit();
} catch (Exception $ex) {
    $mytransactions->rollback();
    markSupplierAsNOTInUse($supplierid);
}
```

---

## 📊 Performance Considerations

### Database Optimization Tips
1. **Critical Indexes**:
   - `checkwithdrawal(bankaccountid, supplierid)` - For account/supplier searches
   - `checkwithdrawal(checkwithdrawaldate)` - For date range queries
   - `supplierdebtchange(tablename, supplierdebtchangemodelid)` - For linking

2. **Query Optimization**:
   - Date range queries could benefit from partitioning
   - Supplier concurrency could use database-level locking
   - Extended DAO queries load multiple related tables

3. **Concurrency Issues**:
   - Sleep-based waiting is inefficient
   - Could implement proper database locking
   - Supplier "inUse" flag needs timeout mechanism

### Performance Bottlenecks
```php
// This pattern appears frequently and could be optimized:
while ($supplier_data->suppliercurrentDebt == 'in_use') {
    sleep(1); // Inefficient - blocks thread
    $noOfTries++;
    if ($noOfTries > 15) {
        // Force unlock - could cause data inconsistency
        R::exec('UPDATE supplier SET inUse = 0 where supplierid = ' . $supplier);
    }
}
```

**Better Approach**:
```sql
-- Use database-level locking instead
SELECT ... FROM supplier WHERE supplierid = ? FOR UPDATE;
```

---

## 🐛 Common Issues & Troubleshooting

### 1. **Check Creation Fails with Insufficient Balance**
**Issue**: Check withdrawal fails even when account has sufficient funds  
**Cause**: Concurrency issues or stale balance data

**Debug**:
```sql
-- Check current account balance
SELECT accountbeginingbalance FROM bankaccount WHERE accountid = [ACCOUNT_ID];

-- Check recent movements
SELECT * FROM accountmovement 
WHERE accountid = [ACCOUNT_ID] 
ORDER BY accountmovementdate DESC 
LIMIT 10;
```

### 2. **Supplier Debt Not Updating**
**Issue**: Supplier debt doesn't decrease after check withdrawal  
**Cause**: Concurrency lock issues or transaction rollback

**Debug**:
```sql
-- Check supplier lock status
SELECT supplierid, suppliercurrentDebt, inUse FROM supplier WHERE supplierid = [SUPPLIER_ID];

-- Check recent debt changes
SELECT * FROM supplierdebtchange 
WHERE supplierid = [SUPPLIER_ID] 
ORDER BY supplierdebtchangedate DESC 
LIMIT 5;
```

### 3. **Daily Entry Not Generated**
**Issue**: Accounting entry missing for check withdrawal  
**Cause**: Missing tree IDs or daily entry function failure

**Debug**:
```sql
-- Check tree ID assignments
SELECT s.supplierid, s.suppliername, s.treeId as supplier_tree,
       ba.accountid, ba.accountname, ba.treeId as account_tree
FROM supplier s, bankaccount ba 
WHERE s.supplierid = [SUPPLIER_ID] AND ba.accountid = [ACCOUNT_ID];

-- Check if daily entry was created
SELECT * FROM dailyentry WHERE tablename = 'checkwithdrawalController.php' 
ORDER BY dailyentrydate DESC LIMIT 5;
```

### 4. **Concurrency Timeout Issues**
**Issue**: Multiple users cannot work with same supplier simultaneously  
**Cause**: Supplier locking mechanism too aggressive

**Solutions**:
- Reduce timeout from 15 to 5 seconds
- Implement proper database locking
- Add user notification for locked suppliers

---

## 🧪 Testing Scenarios

### Test Case 1: Normal Check Withdrawal
```
1. Select supplier with sufficient debt
2. Select bank account with sufficient funds
3. Create check withdrawal
4. Verify all tables updated correctly:
   - checkwithdrawal record created
   - bankaccount balance decreased
   - supplier debt decreased
   - accountmovement recorded
   - supplierdebtchange recorded
   - dailyentry generated
```

### Test Case 2: Check Cancellation
```
1. Create check withdrawal
2. Cancel the check
3. Verify all reversals work:
   - Check marked as deleted (conditions = 1)
   - Bank account balance restored
   - Supplier debt restored
   - Reversal movements recorded
   - Daily entry reversed
```

### Test Case 3: Concurrent Access
```
1. Two users try to create checks for same supplier
2. Verify concurrency control works
3. Check that only one succeeds initially
4. Verify second user can proceed after first completes
```

### Test Case 4: Bulk Operations
```
1. Create multiple check withdrawals
2. Select subset for bulk cancellation
3. Verify all selected checks are cancelled
4. Verify unselected checks remain active
5. Check output messages for success/failure
```

---

## 📚 Related Documentation

- [CLAUDE.md](/Applications/AMPPS/www/erp19/CLAUDE.md) - PHP 8.2 migration guide
- [cashSaveFlowController.md](cashSaveFlowController.md) - Cash flow reporting
- [supplierPayedDeptController.php](#) - Other supplier payments
- [Daily Entry System Documentation](#) - Accounting integration

---

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