# Cash Save Flow Controller Documentation

**File**: `/controllers/cashSaveFlowController.php`  
**Purpose**: Generates comprehensive cash flow reports for safes and bank accounts  
**Last Updated**: December 20, 2024  
**Total Functions**: 3  
**Lines of Code**: ~829

---

## 📋 Overview

The Cash Save Flow Controller is a sophisticated financial reporting module that provides detailed cash flow analysis for both physical safes and bank accounts. It handles:
- Daily cash flow tracking across multiple safes
- Bank account movement analysis
- Transaction categorization and summarization
- Sales and purchase aggregation
- Multi-currency and time zone support
- User permission-based data filtering
- Comprehensive financial audit trails

### Primary Functions
- [x] Display today's automatic cash flow report
- [x] Generate custom date range cash flow reports
- [x] Track safe balance changes by transaction type
- [x] Monitor bank account movements
- [x] Categorize transactions by source (sales, purchases, expenses, etc.)
- [x] Calculate running balances and totals
- [x] Support multi-safe and multi-account reporting
- [x] Apply user permission restrictions

### Transaction Categories Tracked
**Safe Transactions:**
- Sales bills (sellbillController.php)
- Purchase bills (buyBillController.php)
- Returns (returnsellbillController.php, returnBuyBillController.php)
- Combined bills (sellbillandruternController.php)
- Client payments (clientPayedDeptController.php)
- Supplier payments (supplierPayedDeptController.php)
- Employee expenses (employeePersonalController.php)
- General expenses (expensesController.php)
- Income entries (incomeController.php)
- Partner withdrawals (partnerwithdrawalController.php)

**Bank Transactions:**
- Check deposits (depositcheckController.php)
- Check withdrawals (checkwithdrawalController.php)
- Cash transfers (cashTransferController.php)
- Dated checks (datedCheckedController.php)
- Sales receipts (sellbillController.php)

### Related Controllers
- [sellbillController.php](sellbillController.md) - Sales operations
- [buyBillController.php](#) - Purchase operations
- [clientPayedDeptController.php](#) - Customer payments
- [expensesController.php](#) - Expense management
- [incomeController.php](#) - Income tracking

---

## 🗄️ Database Tables

### Primary Tables (Direct Operations)
| Table Name | Purpose | Key Columns |
|------------|---------|-------------|
| **savedaily** | Safe transaction log | savedailyid, saveid, savedailychangeamount, savedailychangetype, tablename, processname, savedailysavebefore, savedailysaveafter |
| **save** | Safe/cash register master | saveid, savename, savecurrentvalue, conditions |
| **accountmovement** | Bank account transactions | accountmovementid, accountid, accountmovementamount, accountmovementtype, tablename, accountmovementbefore, accountmovementafter |

### Financial Reference Tables
| Table Name | Purpose | Key Columns |
|------------|---------|-------------|
| **bankaccount** | Bank account master | accountid, accountname, accountbeginingbalance |
| **bank** | Bank master data | bankid, bankname |
| **client** | Customer information | clientid, clientname |
| **supplier** | Supplier information | supplierid, suppliername |
| **user** | System users | userid, username, searchinonesave, saveid |

### Transaction Source Tables
| Table Name | Purpose | Key Columns |
|------------|---------|-------------|
| **sellbill** | Sales bills | sellbillid, sellbillclientid, sellbilltotalpayed |
| **buybill** | Purchase bills | buybillid, buybillsupplierid, buybilltotalpayed |
| **clientdebtchange** | Customer debt tracking | clientdebtchangeid, clientid, clientdebtchangeamount |
| **supplierdebtchange** | Supplier debt tracking | supplierdebtchangeid, supplierid, supplierdebtchangeamount |
| **expenses** | Expense records | expensesid, expensesname |
| **income** | Income records | incomeId, incomeName |
| **checkdeposit** | Check deposits | checkdepositid, clientid, checkamount |
| **checkwithdrawal** | Check withdrawals | checkwithdrawalid, supplierid, checkamount |

---

## 🔑 Key Functions

### 1. **Default Action** - Today's Cash Flow Report
**Location**: Lines 323-376  
**Purpose**: Display automatic cash flow report for current day

**Function Signature**:
```php
// Triggered when: empty($do) or no action specified
if (empty($do)) {
```

**Process Flow**:
1. **Permission Check**: Include authentication
2. **Load Configuration**: 
   - Get user save privileges
   - Load program settings for time zone handling
   - Load YouTube tutorial links

3. **Date Calculation**:
   - Calculate today's date range
   - Apply program setting hour offsets for time zones
   - Determine if current time is before/after daily cutoff

4. **Data Loading**:
   - Load available safes based on user permissions
   - Load available bank accounts
   - Call `search()` function with calculated parameters

**Time Zone Logic**:
```php
if (isset($Programsetting->reportsPlusHours) && !empty($Programsetting->reportsPlusHours)) {
    $reportsPlusHours = $Programsetting->reportsPlusHours + 24;
    $endToday = date('Y-m-d H:i:s', strtotime('+' . $reportsPlusHours . ' hour', strtotime($today)));
    $startToday = date('Y-m-d H:i:s', strtotime('+' . $Programsetting->reportsPlusHours . ' hour', strtotime($today)));
}

// Determine which day's data to show based on current hour
if (date('H') < $Programsetting->reportsPlusHours) {
    $startDate = $startYesterday;  // Show yesterday's data
    $endDate = $endYesterday;
} else {
    $startDate = $startToday;      // Show today's data
    $endDate = $endToday;
}
```

---

### 2. **show** - Custom Date Range Report
**Location**: Lines 377-438  
**Purpose**: Generate cash flow report for user-specified criteria

**Function Signature**:
```php
// Triggered when: do=show
elseif ($do == "show") {
```

**Process Flow**:
1. **Parameter Processing**:
   - Parse save/account selection: `$_REQUEST['saveId']` format: `{type}_{id}`
   - Extract date range: `$_REQUEST['from']`, `$_REQUEST['to']`
   - Handle search type: `dateOnly` vs exact datetime

2. **Message Building**:
   - Build descriptive report title
   - Include safe name or bank account name
   - Include date range information

3. **Date Range Processing**:
```php
if ($search == "dateOnly") {
    if (isset($Programsetting->reportsPlusHours)) {
        $endDate = date('Y-m-d H:i:s', strtotime('+' . $reportsPlusHours . ' hour', strtotime($endDate)));
        $startDate = date('Y-m-d H:i:s', strtotime('+' . $Programsetting->reportsPlusHours . ' hour', strtotime($startDate)));
    } else {
        $endDate = $endDate . ' 23:59:59';
        $startDate = $startDate . " 00:00:00";
    }
}
```

4. **Report Generation**: Call `search()` with processed parameters

**Input Parameters**:
- `saveId`: Format `save_{id}` or `bank_{id}`
- `from`: Start date (YYYY-MM-DD)
- `to`: End date (YYYY-MM-DD)
- `search`: Search type (`dateOnly` or exact)

---

### 3. **loadSaveByUserPrivileg()** - User Permission Filtering
**Location**: Lines 456-475  
**Purpose**: Load safes based on user access privileges

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

**Process Flow**:
1. Load current user data
2. Check `searchinonesave` permission:
   - `0`: User can see all safes
   - `1`: User restricted to assigned safe only
3. Return appropriate safe list

**Permission Logic**:
```php
$userData = $myUserRecord->load($_SESSION['userid']);
if ($userData->searchinonesave == 0) {
    $saveData = $mySaveRecord->queryByConditions(0);  // All safes
} else {
    $saveData = array();
    $userSave = $mySaveRecord->load($userData->saveid);  // Only assigned safe
    array_push($saveData, $userSave);
}
```

---

### 4. **search()** - Core Report Generation Engine
**Location**: Lines 478-829  
**Purpose**: Complex report generation with transaction analysis

**Function Signature**:
```php
function search($saveid, $startDate, $endDate, $accountId)
```

**Process Flow**:

#### **Phase 1: Parameter Processing**
- Determine report scope (all, save-specific, or account-specific)
- Build dynamic SQL WHERE clauses
- Apply user permission restrictions

#### **Phase 2: Safe Transaction Processing**
```php
if ($all == 1 || $type == 'save') {
    $savedailyData = $mySavedailyEx->searchInAdsindexWithUsername($queryString, $order);
    
    // Initialize aggregation objects
    $allSell = []; // Sales totals by safe
    $allBuy = [];  // Purchase totals by safe
    
    foreach ($savedailyData as $data) {
        // Process each transaction
    }
}
```

#### **Phase 3: Transaction Categorization**
**Sales Transactions**:
```php
if (in_array($data->tablename, ["sellbillController.php", "sellbillandruternController.php", "returnsellbillController.php"])) {
    if ($data->savedailychangetype == 1) { // Decrease (refund)
        $data->savedailychangeamount = $data->savedailychangeamount * -1;
        $inSum = $data->savedailychangeamount;
    } else { // Increase (sale)
        $inSum = $data->savedailychangeamount;
    }
    $allSell[$data->saveid]->savedailychangeamount += $data->savedailychangeamount;
}
```

**Purchase Transactions**:
```php
elseif (in_array($data->tablename, ["buyBillController.php", "returnBuyBillController.php"])) {
    if ($data->savedailychangetype == 1) { // Decrease (purchase)
        $outSum = $data->savedailychangeamount;
    } else { // Increase (return)
        $data->savedailychangeamount = $data->savedailychangeamount * -1;
        $outSum = $data->savedailychangeamount;
    }
    $allBuy[$data->saveid]->savedailychangeamount += $data->savedailychangeamount;
}
```

**Other Transactions** (Expenses, Income, Payments):
```php
else {
    switch ($data->tablename) {
        case "supplierPayedDeptController.php":
            $data->savecurrentvalue = $supplierDebtChangeExt->getSupplierName($data->savedailymodelid)->suppliername;
            break;
        case "clientPayedDeptController.php":
            $data->savecurrentvalue = $clientDeptChangeExt->getClientName($data->savedailymodelid)->clientname;
            break;
        case "expensesController.php":
            $data->savecurrentvalue = R::getRow('SELECT expensesname FROM expenses WHERE expensesid =' . $data->savedailymodelid)['expensesname'];
            break;
        // ... more cases
    }
    
    if ($data->savedailychangetype == 1) { // Outflow
        $outData[] = $data;
    } else { // Inflow
        $inData[] = $data;
    }
}
```

#### **Phase 4: Bank Account Processing**
```php
if ($all == 1 || $type == 'bank') {
    $allMovements = $accountMovementExt->queryAllMovements($accQueryString);
    
    foreach ($allMovements as $movement) {
        // Process bank movements by transaction type
        if ($movement->tablename == "depositcheckController.php") {
            $depositData = $CheckdepositEX->loadEX($movement->accountmovementmodelid);
            $movement->clientname = $depositData->clientname;
        }
        // ... handle other bank transaction types
    }
}
```

#### **Phase 5: Balance Calculations**
```php
// For each safe
if (!array_key_exists($data->saveid, $savesData)) {
    $saveData = $mySaveRecord->load($data->saveid);
    $savesData[$data->saveid] = [
        'savename' => $data->savename,
        'balance' => $data->savedailysavebefore,     // Starting balance
        'currentBalance' => $saveData->savecurrentvalue, // Current balance
        'inSum' => $inSum,   // Total inflow
        'outSum' => $outSum  // Total outflow
    ];
}
```

---

## 🔄 Workflows

### Workflow 1: Automatic Daily Report Generation
```
┌─────────────────────────────────────────────────────────────┐
│                START: User Accesses Controller              │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│  1. System Initialization                                   │
│     - Load user permissions and safe assignments           │
│     - Load program settings for time zones                 │
│     - Determine today's date range                          │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│  2. Time Zone Calculation                                   │
│     - Apply reportsPlusHours offset                         │
│     - Determine if showing today or yesterday data          │
│     - Calculate start and end timestamps                    │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│  3. Permission-Based Data Loading                           │
│     IF searchinonesave = 0:                                 │
│       └─→ Load all safes user has access to                │
│     ELSE:                                                   │
│       └─→ Load only user's assigned safe                   │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│  4. Generate Report                                         │
│     - Call search() with calculated parameters             │
│     - Process safe and bank transactions                    │
│     - Display results via show.html template               │
└─────────────────────────────────────────────────────────────┘
```

---

### Workflow 2: Custom Report Generation
```
┌─────────────────────────────────────────────────────────────┐
│              START: User Submits Search Form                │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│  1. Parse Search Parameters                                 │
│     - Extract safe/bank selection                           │
│     - Parse date range                                      │
│     - Determine search type (dateOnly vs exact)            │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│  2. Build Report Message                                    │
│     - Include selected safe/bank name                       │
│     - Format date range display                             │
│     - Create descriptive title                              │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│  3. Process Date Range                                      │
│     IF search = "dateOnly":                                 │
│       ├─→ Apply time zone offsets                          │
│       └─→ Set full day range (00:00:00 to 23:59:59)        │
│     ELSE:                                                   │
│       └─→ Use exact timestamps                              │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│  4. Execute Search and Display                              │
│     - Call search() with processed parameters              │
│     - Generate comprehensive report                         │
│     - Display formatted results                             │
└─────────────────────────────────────────────────────────────┘
```

---

### Workflow 3: Transaction Processing Engine
```
┌─────────────────────────────────────────────────────────────┐
│               START: Search Function Called                 │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│  1. Build SQL Queries                                       │
│     - Apply safe/account filters                            │
│     - Add date range restrictions                           │
│     - Include user permission filters                       │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│  2. Process Safe Transactions                               │
│     FOR EACH transaction in savedaily:                      │
│       │                                                     │
│       ├─→ Determine transaction category                   │
│       │   ├─ Sales (in/out based on type)                 │
│       │   ├─ Purchases (in/out based on type)             │
│       │   └─ Other (expenses, income, payments)            │
│       │                                                     │
│       ├─→ Load related entity names                        │
│       │   ├─ Client/supplier names                         │
│       │   ├─ Expense/income descriptions                   │
│       │   └─ Employee names                                │
│       │                                                     │
│       └─→ Update safe totals and categorize               │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│  3. Process Bank Transactions                               │
│     FOR EACH movement in accountmovement:                   │
│       │                                                     │
│       ├─→ Identify transaction source                      │
│       │   ├─ Check deposits                                │
│       │   ├─ Check withdrawals                             │
│       │   ├─ Cash transfers                                │
│       │   └─ Sales receipts                                │
│       │                                                     │
│       ├─→ Load source document details                     │
│       │                                                     │
│       └─→ Update account totals                            │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│  4. Calculate Totals and Balances                           │
│     - Aggregate inflow and outflow by safe/account         │
│     - Calculate starting balances                           │
│     - Determine current balances                            │
│     - Handle safes/accounts with no transactions           │
└────────────────────┬────────────────────────────────────────┘
                     │
                     ▼
┌─────────────────────────────────────────────────────────────┐
│  5. Assign Data to Template                                 │
│     - Safe transaction data                                 │
│     - Bank transaction data                                 │
│     - Summary totals                                        │
│     - Sales/purchase aggregations                          │
└─────────────────────────────────────────────────────────────┘
```

---

## 🌐 URL Routes & Actions

| URL Parameter | Function Called | Description |
|---------------|----------------|-------------|
| (no parameters) | Default action | Today's automatic cash flow report |
| `do=show` | Custom report | User-specified date range and criteria |
| `do=sucess` | Success page | Display success message |
| `do=error` | Error page | Display error message |

### Required Parameters by Action

**Today's Report** (no parameters):
- No parameters required
- Uses system date and user permissions

**Custom Report** (`do=show`):
- `saveId` - Format: `save_{saveid}` or `bank_{accountid}` (optional)
- `from` - Start date (YYYY-MM-DD)
- `to` - End date (YYYY-MM-DD)
- `search` - Search type: `dateOnly` or exact timestamps

---

## 🧮 Transaction Analysis & Calculations

### Transaction Type Determination
```php
// Sales and returns affect cash positively/negatively
if (in_array($data->tablename, ["sellbillController.php", "sellbillandruternController.php", "returnsellbillController.php"])) {
    if ($data->savedailychangetype == 1) { // Decrease (refund/return)
        $inSum = $data->savedailychangeamount * -1; // Convert to negative inflow
    } else { // Increase (sale)
        $inSum = $data->savedailychangeamount; // Positive inflow
    }
}

// Purchases affect cash negatively/positively
elseif (in_array($data->tablename, ["buyBillController.php", "returnBuyBillController.php"])) {
    if ($data->savedailychangetype == 1) { // Decrease (purchase payment)
        $outSum = $data->savedailychangeamount; // Outflow
    } else { // Increase (return refund)
        $outSum = $data->savedailychangeamount * -1; // Negative outflow
    }
}
```

### Balance Calculations
```php
// Calculate totals for each safe
$savesData[$data->saveid] = [
    'savename' => $data->savename,
    'balance' => $data->savedailysavebefore,        // Starting balance for period
    'currentBalance' => $saveData->savecurrentvalue, // Current actual balance
    'inSum' => $inSum,                              // Total period inflow
    'outSum' => $outSum                             // Total period outflow
];

// Net change = inSum - outSum
// Expected ending balance = balance + (inSum - outSum)
```

### Entity Name Resolution
```php
switch ($data->tablename) {
    case "supplierPayedDeptController.php":
        $data->savecurrentvalue = $supplierDebtChangeExt->getSupplierName($data->savedailymodelid)->suppliername;
        break;
    case "clientPayedDeptController.php":
        $data->savecurrentvalue = $clientDeptChangeExt->getClientName($data->savedailymodelid)->clientname;
        break;
    case "expensesController.php":
        $data->savecurrentvalue = R::getRow('SELECT expensesname FROM expenses WHERE expensesid =' . $data->savedailymodelid)['expensesname'];
        break;
    case "incomeController.php":
        $data->savecurrentvalue = R::getRow('SELECT incomeName FROM income WHERE incomeId =' . $data->savedailymodelid)['incomeName'];
        break;
}
```

---

## 🔒 Security & Permissions

### User Permission System
```php
// Load user data to check permissions
$userData = $myUserRecord->load($_SESSION['userid']);

// Safe access control
if ($userData->searchinonesave == 0) {
    // User can access all safes
    if ($_SESSION['saveids'] != 0) {
        $queryString .= ' savedaily.saveid in (' . $_SESSION['saveids'] . ') AND';
    }
} else {
    // User restricted to specific safe
    $queryString .= ' savedaily.saveid = ' . $_SESSION['saveid'] . ' AND';
}
```

### Input Validation
- Date parameters validated through framework
- Save/account IDs filtered and parsed
- SQL injection prevented by DAO layer
- Session-based user authentication

### Data Access Control
- Users only see transactions for safes they have permission to access
- Bank account access controlled by user privileges
- Transaction details filtered by user group permissions

---

## 📊 Performance Considerations

### Database Optimization Tips
1. **Critical Indexes**:
   - `savedaily(saveid, savedailydate)` - For date range queries
   - `accountmovement(accountid, accountmovementdate)` - For bank queries
   - `savedaily(tablename, savedailymodelid)` - For transaction linking

2. **Query Optimization**:
   - Uses complex date range filtering
   - Could benefit from materialized views for common aggregations
   - N+1 query issues when loading entity names

3. **Memory Management**:
   - Large date ranges can return thousands of records
   - Consider pagination for very active periods
   - Template variables accumulate across all transactions

### Performance Issues
```sql
-- This query pattern appears frequently and could be slow
SELECT * FROM savedaily 
WHERE saveid IN (1,2,3,4,5) 
AND savedailydate >= '2024-01-01 00:00:00' 
AND savedailydate <= '2024-01-31 23:59:59'
ORDER BY savedailydate ASC;

-- Then for each record, loads entity names individually:
SELECT expensesname FROM expenses WHERE expensesid = ?;
SELECT incomeName FROM income WHERE incomeId = ?;
-- etc...
```

**Optimization Approach**:
```sql
-- Better to use JOINs where possible
SELECT sd.*, e.expensesname, i.incomeName, c.clientname, s.suppliername
FROM savedaily sd
LEFT JOIN expenses e ON sd.tablename = 'expensesController.php' AND e.expensesid = sd.savedailymodelid
LEFT JOIN income i ON sd.tablename = 'incomeController.php' AND i.incomeId = sd.savedailymodelid
-- etc...
```

---

## 🐛 Common Issues & Troubleshooting

### 1. **Incorrect Time Zone Handling**
**Issue**: Report shows wrong day's data  
**Cause**: `reportsPlusHours` setting not properly configured

**Debug**:
```php
// Check current hour vs setting
echo "Current hour: " . date('H') . "<br>";
echo "Reports plus hours: " . $Programsetting->reportsPlusHours . "<br>";
echo "Calculated start: " . $startDate . "<br>";
echo "Calculated end: " . $endDate . "<br>";
```

### 2. **Missing Transactions**
**Issue**: Some transactions don't appear in report  
**Cause**: Permission restrictions or date range issues

**Debug**:
```sql
-- Check user permissions
SELECT userid, searchinonesave, saveid FROM user WHERE userid = [USER_ID];

-- Check transaction dates
SELECT COUNT(*), MIN(savedailydate), MAX(savedailydate) 
FROM savedaily WHERE saveid = [SAVE_ID];
```

### 3. **Incorrect Balance Calculations**
**Issue**: Totals don't match expected values  
**Cause**: Transaction type logic or sign handling

**Debug**:
```sql
-- Verify transaction types and amounts
SELECT tablename, savedailychangetype, SUM(savedailychangeamount)
FROM savedaily 
WHERE saveid = [SAVE_ID] AND savedailydate BETWEEN '[START]' AND '[END]'
GROUP BY tablename, savedailychangetype;
```

### 4. **Performance Issues**
**Issue**: Report takes long time to load  
**Cause**: Large date ranges or missing indexes

**Solutions**:
- Add appropriate database indexes
- Implement date range limits
- Consider caching for frequently accessed reports
- Optimize entity name loading queries

---

## 🧪 Testing Scenarios

### Test Case 1: Daily Report Accuracy
```
1. Record test transactions in different safes
2. Access controller without parameters
3. Verify correct day's data is shown
4. Check time zone handling
5. Confirm permission filtering works
```

### Test Case 2: Custom Date Range
```
1. Select specific safe and date range
2. Verify all transactions in range appear
3. Check transaction categorization
4. Confirm totals are accurate
5. Test bank account reporting
```

### Test Case 3: Permission Restrictions
```
1. Login as restricted user (searchinonesave = 1)
2. Verify only assigned safe appears
3. Test with unrestricted user
4. Confirm all accessible safes show
```

### Test Case 4: Transaction Type Handling
```
1. Create transactions of each type
2. Verify proper categorization (in/out)
3. Check entity name resolution
4. Confirm aggregation accuracy
```

---

## 📚 Related Documentation

- [CLAUDE.md](/Applications/AMPPS/www/erp19/CLAUDE.md) - PHP 8.2 migration guide
- [sellbillController.md](sellbillController.md) - Sales operations
- [buyBillController.php](#) - Purchase operations
- [Financial Reports Documentation](#) - Other financial reports

---

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