ExpensesType Documentation
Expenses Type Controller Documentation
File: /controllers/expensesTypeController.php
Purpose: Manages hierarchical expense category system with tree structure, accounting integration, and user group permissions
Last Updated: December 20, 2024
Total Functions: 12+
Lines of Code: ~620
---
๐ Overview
The Expenses Type Controller manages a comprehensive expense categorization system with hierarchical tree structure and accounting chart integration. It provides:
- โข Hierarchical expense category management with parent-child relationships
- โข Integration with chart of accounts for financial reporting
- โข User group-based permission control for category access
- โข Tree-structured expense type display with visual hierarchy
- โข Bulk operations for category management
- โข Save account filtering based on user permissions
- โข Web API integration support
- โข Supervision ratio and amount configurations
Primary Functions
- โ Create hierarchical expense categories
- โ Tree-structured category display with indentation
- โ Integration with accounting chart of accounts
- โ User group permission controls
- โ Bulk delete operations with dependency checking
- โ Save account filtering by user permissions
- โ Parent-child relationship management
- โ CRUD operations with JSON API support
Related Controllers
- โข expensesController.php - General expense management
- โข expenseexchange.php - Project expense transactions
- โข accountstree.md - Chart of accounts management
- โข saveController.php - Save account management
---
๐๏ธ Database Tables
Primary Tables (Direct Operations)
| Table Name | Purpose | Key Columns | |
|---|---|---|---|
| **expensestype** | Expense category hierarchy | expensestypeid, expensestypename, parent, treeId, type, treeType, saveid, addOnlyGroupIds | |
| **expenses** | Expense transactions | expensestypeid, expensesValue, expensesdate, conditions |
| Table Name | Purpose | Key Columns | |
|---|---|---|---|
| **accountstree** | Chart of accounts | id, name, parent, customName, itemtype | |
| **save** | Cash registers/safes | saveid, savename, treeId | |
| **usergroup** | User permission groups | usergroupid, usergroupname |
| Table Name | Purpose | Key Columns | |
|---|---|---|---|
| **user** | System users | userid, username, usergroupid | |
| **youtubelink** | Tutorial links | youtubelinkid, title, url |
๐ Key Functions
1. Default Action - Add Form Display
Location: Line 96
Purpose: Display hierarchical expense type creation form
Process Flow:
1. Build tree-ordered expense type hierarchy
2. Configure save account access based on permissions
3. Load user groups for permission assignment
4. Display form with tree structure
Tree Building:
orderExtepensesTypeParentsAsTree(0);
$allParents = $dataOrdered;
$smarty->assign("allParents", $allParents);
---
2. add() - Create Expense Type
Location: Line 289
Purpose: Create new expense type with accounting integration
Function Signature:
function add()
Process Flow:
1. Input Processing:
$name = $_POST['name'];
$withinsupervision_ratio = $_POST['withinsupervision_ratio'];
$supervision_ratiotype = $_POST['supervision_ratiotype'];
$supervision_amount = $_POST['supervision_amount'];
$parentid = $_POST['parent'];
$type = (int) $_POST["type"];
$treeType = (int) $_POST["treeType"];
$saveid = (int) $_POST["saveid"];
```
2. **User Group Processing**:
```php
$addOnlyGroupIds = filter_input(INPUT_POST, 'addOnlyGroupIds', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY);
$addOnlyGroupIds_str = implode(',', $addOnlyGroupIds);
```
3. **Database Insert**:
```php
$id = $expensesTypeDAO->insert($expensesType);
```
4. **Chart of Accounts Integration**:
```php
if ($parentid < 1) {
if ($treeType == 0) $parent = 414; // Operating expenses
elseif ($treeType == 1) $parent = 413; // Administrative expenses
elseif ($treeType == 2) $parent = 412; // Cost of goods sold
} else {
$parentData = $expensesTypeDAO->load($parentid);
$parent = $parentData->treeId;
}
$treeId = addTreeElement($name, $parent, 3, 0, 0, '', 0, 0);
```
**Tree Type Categories**:
- `treeType = 0` - Operating Expenses (Tree ID 414)
- `treeType = 1` - Administrative Expenses (Tree ID 413)
- `treeType = 2` - Cost of Goods Sold (Tree ID 412)
---
### 3. **show()** - Display Expense Types
**Location**: Line 351
**Purpose**: Show hierarchical expense type listing with filtering
**Process Flow**:
1. Build tree-ordered hierarchy for display
2. Apply parent filter if specified
3. Process name-based filtering with tree traversal
**Hierarchy Display**:
php
orderExtepensesTypeParentsAsTree(0);
$allData = $dataOrdered;
$name = $_REQUEST['parent'];
if ($name != '-1') {
$name = ltrim(str_replace("_", " ", $name));
$qname = $expensesTypeExt->queryAllname($name);
} else {
$qname = $allData;
}
---
### 4. **orderExtepensesTypeParentsAsTree()** - Build Tree Structure
**Location**: Line 258
**Purpose**: Recursively build hierarchical tree display with indentation
**Function Signature**:
php
function orderExtepensesTypeParentsAsTree($parent, $expensestypeid = 0, $level)
**Process Flow**:
1. **Permission-Based Filtering**:
```php
$queryString = '';
if ($_SESSION['searchinonesave'] == 0) {
if ($_SESSION['saveids'] != 0) {
$queryString = ' and (expensestype.saveid = 0 or expensestype.saveid in (' . $_SESSION['saveids'] . '))';
}
} else {
$queryString = ' and expensestype.saveid = ' . $_SESSION['saveid'];
}
```
2. **Recursive Tree Building**:
```php
$result = $expensesTypeExt->getTypesWithoutExpenses(" and expensestype.expensestypeid != $expensestypeid and expensestype.parent = $parent $queryString");
foreach ($result as $type) {
$type->conditions = $level;
$preString = str_repeat('_', $level);
$type->expensestypename = $preString . ' ' . $type->expensestypename;
array_push($dataOrdered, $type);
orderExtepensesTypeParentsAsTree($type->expensestypeid, $expensestypeid, $level + 1);
}
```
**Visual Hierarchy Example**:
Operating Expenses
_ Utilities
__ Electricity
__ Water
_ Transportation
__ Fuel
__ Maintenance
Administrative Expenses
_ Office Supplies
_ Professional Services
---
### 5. **update()** - Modify Expense Type
**Location**: Line 425
**Purpose**: Update expense type with accounting tree synchronization
**Process Flow**:
1. Update expense type record
2. Synchronize with chart of accounts
3. Handle parent relationship changes
**Tree Synchronization**:
php
$oldData = $expensesTypeDAO->load($id);
$treeId = $oldData->treeId;
$getRow = $accountsTreeDAO->load($treeId);
if ($parentid == 0) {
$getRow->parent = 151; // Default parent
} else {
$oldData2 = $expensesTypeDAO->load($parentid);
$getRow->parent = $oldData2->treeId;
}
editTreeElement($getRow);
---
### 6. **executeOperation()** - Bulk Operations
**Location**: Line 375
**Purpose**: Perform bulk operations on selected expense types
**Process Flow**:
1. Parse selected expense type IDs
2. Execute operation (currently supports delete)
3. Check dependencies for each item
4. Generate operation report
**Bulk Delete Implementation**:
php
$choosedItemArr = $_POST['choosedItem'];
foreach ($choosedItemArr as $expensesTypeId) {
if ($operationType == '1') { // delete
$note = deleteExt($expensesTypeId);
if ($note != "success") {
$expenseTypeData = $expensesTypeDAO->load($expensesTypeId);
$outputString .= $expenseTypeData->expensestypename . ": " . $note . "
";
}
}
}
---
### 7. **delete()** - Delete Expense Type with Validation
**Location**: Line 532
**Purpose**: Delete expense type with dependency checking
**Process Flow**:
1. **Dependency Validation**:
```php
// Check for associated expenses
$expensesdata = $expensesRecord->queryByExpensestypeid($expensestypeid);
// Check for child categories
$childCategories = $expensesTypeDAO->queryByParent($expensestypeid);
if (count($expensesdata) > 0 || count($childCategories) > 0) {
$note = "ูุง ูู
ูู ุญุฐู ูุฐุง ุงูููุน ูุฃูู ู
ุฑุชุจุท ุจุจูุงูุงุช ุฃุฎุฑู";
}
```
2. **Safe Deletion**:
```php
$rowDelData = $expensesTypeDAO->load($expensestypeid);
delTreeElement($rowDelData->expensestypename);
$expensesType->conditions = 1; // Mark as deleted
$expensesTypeExt->updateConditions($expensesType);
```
---
## ๐ Workflows
### Workflow 1: Hierarchical Expense Type Creation
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ START: Create Expense Type โ
โโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 1. Load Form Dependencies โ
โ - Build parent hierarchy tree โ
โ - Load user groups for permissions โ
โ - Configure save account access โ
โโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 2. Process Form Input โ
โ - Validate expense type name โ
โ - Set supervision configurations โ
โ - Process user group permissions โ
โ - Determine tree type and parent โ
โโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 3. Create Database Record โ
โ - Insert expense type record โ
โ - Generate unique expense type ID โ
โโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 4. Chart of Accounts Integration โ
โ IF No Parent (parentid = 0): โ
โ โโ Use default tree parent by type โ
โ โ โโ Operating: 414 โ
โ โ โโ Administrative: 413 โ
โ โ โโ COGS: 412 โ
โ ELSE: โ
โ โโ Use parent's tree ID โ
โ โ
โ - Create tree element in chart โ
โ - Link expense type to tree ID โ
โโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 5. Finalize Creation โ
โ - Update expense type with tree ID โ
โ - Return success response โ
โ - Redirect to success page โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
---
### Workflow 2: Tree Structure Display Building
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ START: Build Tree Structure โ
โโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 1. Initialize Tree Building โ
โ - Set parent = 0 (root level) โ
โ - Clear ordered data array โ
โ - Set level = 0 โ
โโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 2. Build Permission Filter โ
โ IF searchinonesave = 0: โ
โ IF saveids != 0: โ
โ โโ Filter: saveid = 0 OR saveid in (saveids) โ
โ ELSE: โ
โ โโ Filter: saveid = current saveid โ
โโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 3. Recursive Processing โ
โ FOR EACH Level: โ
โ โ โ
โ โโ Query children of current parent โ
โ โ โโ Apply permission filters โ
โ โ โ
โ โโ Process each child: โ
โ โ โโ Set hierarchy level โ
โ โ โโ Add indentation prefix โ
โ โ โ โโ preString = repeat('_', level) โ
โ โ โโ Update display name โ
โ โ โโ Add to ordered array โ
โ โ โ
โ โโ Recurse for each child: โ
โ โโ Call with (childId, level+1) โ
โโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 4. Return Hierarchical Structure โ
โ - Complete tree with visual indentation โ
โ - Proper parent-child ordering โ
โ - Permission-filtered results โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
---
## ๐ URL Routes & Actions
| URL Parameter | Function Called | Description |
|---------------|----------------|-------------|
| `do=` (empty) | Default action | Display expense type creation form |
| `do=add` | `add()` | Create new expense type |
| `do=show` | `show()` | Display expense type hierarchy |
| `do=executeOperation` | `executeOperation()` | Bulk operations on selected types |
| `do=edit` | `edit()` | Load expense type for editing |
| `do=update` | `update()` | Update existing expense type |
| `do=delete` | `delete()` | Delete expense type with validation |
### Required Parameters by Action
**Add Expense Type** (`do=add`):
- `name` - Expense type name
- `descripe` - Description (optional)
- `parent` - Parent expense type ID (0 for root)
- `type` - Type classification
- `treeType` - Chart of accounts category (0/1/2)
- `saveid` - Associated save account ID
- `addOnlyGroupIds[]` - User group permissions array
**Show with Filter** (`do=show`):
- `parent` - Parent name filter (optional, "-1" for all)
**Bulk Operations** (`do=executeOperation`):
- `operation` - Operation type ("1" for delete)
- `choosedItem[]` - Array of expense type IDs
**Edit/Update** (`do=edit`, `do=update`):
- `id` - Expense type ID
- Additional parameters same as add for update
---
## ๐งฎ Calculation Methods
### Tree Path Generation
php
function orderExtepensesTypeParentsAsTree($parent, $expensestypeid = 0, $level) {
// Generate visual hierarchy
$preString = '';
for ($index = 0; $index < $level; $index++) {
$preString .= '_';
}
$type->expensestypename = $preString . ' ' . $type->expensestypename;
}
### Permission Group Processing
php
$addOnlyGroupIds = filter_input(INPUT_POST, 'addOnlyGroupIds', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY);
$addOnlyGroupIds_str = '';
foreach ($addOnlyGroupIds as $value) {
$addOnlyGroupIds_str .= $value . ",";
}
$addOnlyGroupIds_str = rtrim($addOnlyGroupIds_str, ',');
### Chart of Accounts Parent Assignment
php
if ($parentid < 1) {
if ($treeType == 0) $parent = 414; // Operating expenses
elseif ($treeType == 1) $parent = 413; // Administrative expenses
elseif ($treeType == 2) $parent = 412; // Cost of goods sold
} else {
$parentData = $expensesTypeDAO->load($parentid);
$parent = $parentData->treeId;
}
---
## ๐ Security & Permissions
### User Authentication
php
// Standard authentication check
include_once("../public/authentication.php");
### Save Account Access Control
php
if ($_SESSION['searchinonesave'] == 0) {
if ($_SESSION['saveids'] == 0) {
$saves = $saveDAO->queryAll(); // Access to all
} else {
// Restricted to specific save accounts
$queryString = ' and saveid in (' . $_SESSION['saveids'] . ')';
$saves = $saveEX->queryWithConditionWithQueryString($queryString);
}
} else {
// Single save account mode
$saves = $_SESSION['saveid'];
}
### JSON API Security
php
if (isset($_POST['curlpost']) && $_POST['curlpost'] == 1) {
// API response format
$data = array(
'status' => 1,
'message' => 'ุชู ุช ุงูุนู ููู ุจูุฌุงุญ',
'message_en' => 'Success',
'id' => $id
);
echo json_encode($data);
} else {
// Web interface redirect
header("location:?do=sucess");
}
### Input Sanitization
- All POST data filtered and validated
- SQL injection prevention via DAO layer
- User group array validation
- Parent-child relationship validation
- Dependency checking before deletion
---
## ๐ Performance Considerations
### Database Optimization Tips
1. **Indexes Required**:
- `expensestype(parent, conditions)` - For tree traversal
- `expensestype(saveid)` - For permission filtering
- `expensestype(expensestypename)` - For name searches
- `expenses(expensestypeid)` - For dependency checking
2. **Query Optimization**:
- Recursive tree building can be expensive for deep hierarchies
- Consider caching tree structure for frequently accessed data
- Use efficient parent-child queries
3. **Memory Management**:
- Tree building stores all nodes in memory
- Consider pagination for very large hierarchies
- Efficient permission filtering at query level
### Known Performance Issues
sql
-- This recursive query can be slow for deep hierarchies
SELECT * FROM expensestype
WHERE parent = ? AND conditions = 0
ORDER BY expensestypename;
-- Solution: Add composite index
CREATE INDEX idx_parent_conditions ON expensestype(parent, conditions, expensestypename);
---
## ๐ Common Issues & Troubleshooting
### 1. **Tree Hierarchy Display Problems**
**Issue**: Missing indentation or incorrect ordering
**Cause**: Recursive function logic errors or missing parent relationships
**Debug**:
php
// Add debugging to tree building
echo "Processing parent: $parent, level: $level
";
print_r($result);
### 2. **Chart of Accounts Integration Errors**
**Issue**: Missing tree IDs or broken account links
**Cause**: Failed tree element creation or invalid parent IDs
**Debug**:
sql
SELECT et.expensestypeid, et.expensestypename, et.treeId,
at.name as account_name, at.parent
FROM expensestype et
LEFT JOIN accountstree at ON et.treeId = at.id
WHERE et.treeId IS NULL OR at.id IS NULL;
### 3. **Permission Filtering Issues**
**Issue**: Users seeing expense types they shouldn't access
**Cause**: Incorrect save account filtering or permission logic
**Debug**:
php
// Check user permissions
echo "Search in one save: " . $_SESSION['searchinonesave'] . "
";
echo "Save IDs: " . $_SESSION['saveids'] . "
";
echo "Current save ID: " . $_SESSION['saveid'] . "
";
### 4. **Bulk Operation Failures**
**Issue**: Incomplete bulk deletions or error reporting
**Cause**: Dependency validation errors or transaction issues
**Debug**:
php
// Enhanced error reporting
foreach ($choosedItemArr as $expensesTypeId) {
try {
$note = deleteExt($expensesTypeId);
echo "ID $expensesTypeId: $note
";
} catch (Exception $e) {
echo "Error deleting $expensesTypeId: " . $e->getMessage() . "
";
}
}
---
## ๐งช Testing Scenarios
### Test Case 1: Hierarchical Structure Creation
1. Create root level expense type
2. Create child expense types under root
3. Create grandchild types under children
4. Verify tree display shows proper indentation
5. Check chart of accounts integration
### Test Case 2: Permission-Based Filtering
1. Login with restricted save account access
2. Create expense types with different save assignments
3. Verify only permitted types appear
4. Test bulk operations with mixed permissions
### Test Case 3: Dependency Validation
1. Create expense type
2. Create expenses using the type
3. Attempt to delete the type
4. Verify deletion is prevented
5. Test error message display
### Debug Mode Enable
php
// Add at top of controller for debugging
error_reporting(E_ALL);
ini_set('display_errors', 1);
// Debug tree building
function debug_tree_building($parent, $level) {
echo str_repeat(" ", $level) . "Processing parent: $parent at level: $level
";
}
```
---
๐ Related Documentation
- โข CLAUDE.md - PHP 8.2 migration guide
- โข expensesController.md - General expense management
- โข accountstree.md - Chart of accounts management
- โข userController.md - User management and permissions
---
Documented By: AI Assistant
Review Status: โ Complete
Next Review: When major changes occur