Employeereport Documentation

Employee Report Controller Documentation

File: /controllers/employeereport.php

Purpose: Comprehensive employee reporting system with individual profiles and payroll analytics

Last Updated: December 20, 2024

Total Functions: 5+

Lines of Code: ~216

---

๐Ÿ“‹ Overview

The Employee Report Controller provides detailed reporting capabilities for employee management, focusing on individual employee profiles and comprehensive payroll analytics. It serves as a central hub for employee information display and workforce analytics with advanced filtering and aggregation capabilities.

Key Capabilities

Primary Functions

Related Controllers

---

๐Ÿ—„๏ธ Database Tables

Primary Employee Tables

Table NamePurposeKey Columns
**employee**Employee master recordsemployeeId, employeeName, employeeBOD, employeeSalary, employeegroupid, branchid, conditions
**employeegroup**Employee group definitionsid, name, del
### Payroll Tables

Table NamePurposeKey Columns
**employeepersonnel**Payroll transactionsemployeepersonnelid, employeeid, employeepersonnelvalue, employeepersonneltype, employeepersonneldate, conditions
**salaryreport**Salary processing historysalaryreportid, employeeid, salaryreportnet, salarymonthdate
### Organizational Tables

Table NamePurposeKey Columns
**branch**Branch informationbranchid, branchname, branchstatus
### Configuration Tables

Table NamePurposeKey Columns
**youtubelink**Tutorial referencesyoutubelinkid, title, url
---

๐Ÿ”‘ Key Functions

1. Default Action - Individual Employee Profiles

Location: Line 52-81

Purpose: Display individual employee information with age calculation and optional filtering

Function Signature:

// Default action (empty $do)
// Optional POST parameter: chooseEmp - Employee ID filter

Process Flow:

1. Load Employee Dropdown Data:

   $queryStringAll = '';
   if ($_SESSION['branchId'] > 0)
       $queryStringAll = ' AND  branchid = ' . $_SESSION['branchId'];
   
   $allemployee = $employeeEX->queryAllSimple($queryStringAll);
   $smarty->assign('allemployee', $allemployee);
   ```

2. **Apply Employee Filter** (if specified):
   ```php
   $empid = filter_input(INPUT_POST, "chooseEmp");
   $queryString = "";
   if (!empty($empid)) {
       $queryString = " and employeeId =" . $empid;
   }
   ```

3. **Calculate Employee Ages**:
   ```php
   foreach ($allData as $value) {
       if (!empty($value->employeeBOD) && $value->employeeBOD != "0000-00-00") {
           $value->employeeBOD = floor((time() - strtotime($value->employeeBOD)) / (60 * 60 * 24 * 365));
       } else {
           $value->employeeBOD = "";
       }
   }
   ```

4. **Display Report**:
   - Assign data to Smarty template
   - Load YouTube tutorial links
   - Display employeereportview/show.html

**Features**:
- Dynamic age calculation from birth dates
- Branch-based access control
- Optional employee filtering
- Integration with tutorial system

---

### 2. **totals** - Comprehensive Payroll Analytics
**Location**: Line 82-207  
**Purpose**: Generate detailed payroll analytics with grouping and aggregation

**Function Signature**:
php

// Action: do=totals

// POST Parameters:

$month = filter_input(INPUT_POST, 'month'); // YYYY-MM format

$empGroup = filter_input(INPUT_POST, 'empGroup'); // Employee group filter

$branchId = filter_input(INPUT_POST, 'branchId'); // Branch filter

$from = filter_input(INPUT_POST, 'from'); // Date range start

$to = filter_input(INPUT_POST, 'to'); // Date range end

**Process Flow**:
1. **Load Filter Options**:
   ```php
   $employeeGroup = R::getAll('SELECT * FROM employeegroup WHERE del =0');
   $smarty->assign('employeeGroup', $employeeGroup);
   
   $allbranchdata = R::getAll('SELECT * FROM branch');
   $smarty->assign("allbranchdata", $allbranchdata);
   ```

2. **Build Dynamic SQL Filter**:
   ```php
   $sql = '';
   if ($month) {
       $sql .= ' AND MONTH(employeepersonneldate) = ' . date('m', strtotime($month)) . 
               ' AND Year(employeepersonneldate) = ' . date('Y', strtotime($month));
   } else {
       $month = date('Y-m');
       $sql .= ' AND MONTH(employeepersonneldate) = MONTH(CURDATE()) AND Year(employeepersonneldate) = Year(CURDATE()) ';
   }
   
   if ($from && $to) {
       $month = '';
       $sql .= ' AND employeepersonneldate >= "' . $from . '" AND employeepersonneldate <= "' . $to . '"';
   }
   ```

3. **Apply Additional Filters**:
   ```php
   if ($branchId)
       $sql .= ' AND employee.branchid = ' . $branchId;
   else {
       if ($_SESSION['branchId'] > 0)
           $sql .= ' AND  employee.branchid = ' . $_SESSION['branchId'];
   }
   
   if ($empGroup)
       $sql .= ' AND employee.employeegroupid = ' . $empGroup;
   ```

4. **Execute Aggregation Query**:
   ```php
   $allEmployeePersonals = R::getAll('SELECT employee.employeeName,employeeSalary,employee.employeeId, 
                                      SUM(employeepersonnelvalue) as total,
                                      COUNT(employeepersonnelid) AS typeCounter, 
                                      employeepersonneltype
                                      FROM employeepersonnel 
                                      JOIN employee ON employee.employeeId = employeepersonnel.employeeid
                                      WHERE employee.conditions = 0 AND employeepersonnel.conditions = 0
                                      ' . $sql . '
                                      GROUP BY employeepersonneltype, employeepersonnel.employeeid ');
   ```

5. **Process and Categorize Results**:
   ```php
   foreach ($allEmployeePersonals as $emp) {
       $delay = $reward = $dis = $withdraw = $borrow = $absence = $repay = $permission = $leave = '0';
       $delayCounter = $rewardCounter = $disCounter = $withdrawCounter = $borrowCounter = 
                      $absenceCounter = $repayCounter = $permissionCounter = $leaveCounter = '0';
       
       // Categorize by transaction type
       if ($emp['employeepersonneltype'] == 9) {
           $absence = $emp['total']; // ุบูŠุงุจ
           $absenceCounter = $emp['typeCounter'];
       } elseif ($emp['employeepersonneltype'] == 5) {
           $delay = $emp['total']; // ุชุฃุฎูŠุฑ
           $delayCounter = $emp['typeCounter'];
       }
       // ... (additional type categorization)
   }
   ```

6. **Load Salary History**:
   ```php
   $lastSalary = R::getRow('select salaryreportnet,salarymonthdate from salaryreport 
                           where employeeid = ' . $emp['employeeId'] . ' 
                           order by salaryreportid desc');
   ```

**Payroll Transaction Types**:
- **Type 2**: Deductions (ุฎุตู…)
- **Type 3**: Withdrawals (ุณุญุจ) 
- **Type 4**: Advances/Loans (ุณู„ูุฉ)
- **Type 5**: Late arrivals (ุชุฃุฎูŠุฑ)
- **Type 9**: Absences (ุบูŠุงุจ)
- **Type 11**: Permissions (ุงุณุชุฆุฐุงู†)
- **Type 14**: Early departures (ุงู†ุตุฑุงู)

---

## ๐Ÿงฎ Calculation Methods

### Age Calculation from Birth Date
php

if (!empty($value->employeeBOD) && $value->employeeBOD != "0000-00-00") {

// Calculate age in years using timestamp difference

$value->employeeBOD = floor((time() - strtotime($value->employeeBOD)) / (60 60 24 * 365));

} else {

$value->employeeBOD = "";

}

### Payroll Aggregation Logic
php

// Group by employee and transaction type, then sum values

if (array_key_exists($emp['employeeId'], $empArr)) {

// Add to existing employee record

$empArr[$emp['employeeId']]['dis'] += $dis;

$empArr[$emp['employeeId']]['disCounter'] += $disCounter;

$empArr[$emp['employeeId']]['withdraw'] += $withdraw;

// ... (continue for all types)

} else {

// Create new employee record

$empArr[$emp['employeeId']] = [

'name' => $emp['employeeName'],

'dis' => $dis,

'disCounter' => $disCounter,

// ... (all payroll categories)

'salary' => $emp['employeeSalary'],

'lastSalary' => $lastSalary['salaryreportnet'],

'lastSalaryDate' => $lastSalary['salarymonthdate']

];

}

### Date Range Processing
php

// Month-based filtering

if ($month) {

$sql .= ' AND MONTH(employeepersonneldate) = ' . date('m', strtotime($month)) .

' AND Year(employeepersonneldate) = ' . date('Y', strtotime($month));

}

// Custom date range filtering

if ($from && $to) {

$sql .= ' AND employeepersonneldate >= "' . $from . '" AND employeepersonneldate <= "' . $to . '"';

}

---

## ๐Ÿ”„ Workflows

### Workflow 1: Individual Employee Report Generation

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”

โ”‚ START: Access Employee Report โ”‚

โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”‚

โ–ผ

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”

โ”‚ 1. Load Employee Dropdown โ”‚

โ”‚ - Apply branch filtering if applicable โ”‚

โ”‚ - Load all active employees โ”‚

โ”‚ - Populate employee selection dropdown โ”‚

โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”‚

โ–ผ

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”

โ”‚ 2. Apply Optional Employee Filter โ”‚

โ”‚ IF specific employee selected: โ”‚

โ”‚ โ”‚ - Add employee ID filter to query โ”‚

โ”‚ โ”‚ - Limit results to selected employee โ”‚

โ”‚ ELSE: โ”‚

โ”‚ โ”‚ - Show all employees (branch-filtered) โ”‚

โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”‚

โ–ผ

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”

โ”‚ 3. Process Employee Data โ”‚

โ”‚ - Load employee records with filters applied โ”‚

โ”‚ - Calculate ages from birth dates โ”‚

โ”‚ - Convert birth dates to age in years โ”‚

โ”‚ - Handle missing/invalid birth dates โ”‚

โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”‚

โ–ผ

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”

โ”‚ 4. Generate Report Display โ”‚

โ”‚ - Assign processed data to template โ”‚

โ”‚ - Load YouTube tutorial links โ”‚

โ”‚ - Display individual employee profiles โ”‚

โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

---

### Workflow 2: Payroll Analytics Generation

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”

โ”‚ START: Request Payroll Analytics โ”‚

โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”‚

โ–ผ

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”

โ”‚ 1. Load Filter Configuration โ”‚

โ”‚ - Load all employee groups for dropdown โ”‚

โ”‚ - Load all branches for selection โ”‚

โ”‚ - Set default month to current month โ”‚

โ”‚ - Prepare filter interface โ”‚

โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”‚

โ–ผ

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”

โ”‚ 2. Build Dynamic SQL Filter โ”‚

โ”‚ IF Month specified: โ”‚

โ”‚ โ”‚ - Filter by MONTH() and YEAR() โ”‚

โ”‚ IF Date range specified: โ”‚

โ”‚ โ”‚ - Use >= and <= date comparisons โ”‚

โ”‚ IF Employee group specified: โ”‚

โ”‚ โ”‚ - Filter by employeegroupid โ”‚

โ”‚ IF Branch specified: โ”‚

โ”‚ โ”‚ - Filter by branchid โ”‚

โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”‚

โ–ผ

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”

โ”‚ 3. Execute Aggregation Query โ”‚

โ”‚ - JOIN employeepersonnel with employee โ”‚

โ”‚ - GROUP BY employeeid and transaction type โ”‚

โ”‚ - SUM transaction values by type โ”‚

โ”‚ - COUNT transaction frequencies โ”‚

โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”‚

โ–ผ

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”

โ”‚ 4. Process and Categorize Results โ”‚

โ”‚ FOR EACH Employee Transaction Group: โ”‚

โ”‚ โ”‚ โ”‚

โ”‚ โ”œโ”€โ†’ Categorize by transaction type โ”‚

โ”‚ โ”‚ โ”œโ”€ Type 2: Deductions โ”‚

โ”‚ โ”‚ โ”œโ”€ Type 3: Withdrawals โ”‚

โ”‚ โ”‚ โ”œโ”€ Type 4: Advances โ”‚

โ”‚ โ”‚ โ”œโ”€ Type 5: Late arrivals โ”‚

โ”‚ โ”‚ โ”œโ”€ Type 9: Absences โ”‚

โ”‚ โ”‚ โ”œโ”€ Type 11: Permissions โ”‚

โ”‚ โ”‚ โ””โ”€ Type 14: Early departures โ”‚

โ”‚ โ”‚ โ”‚

โ”‚ โ”œโ”€โ†’ Aggregate amounts and counters by employee โ”‚

โ”‚ โ”‚ โ”‚

โ”‚ โ””โ”€โ†’ Load last salary information โ”‚

โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

โ”‚

โ–ผ

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”

โ”‚ 5. Generate Analytics Report โ”‚

โ”‚ - Display aggregated payroll data by employee โ”‚

โ”‚ - Show transaction counts for frequency analysis โ”‚

โ”‚ - Include last salary information โ”‚

โ”‚ - Provide drill-down capabilities โ”‚

โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

---

## ๐ŸŒ URL Routes & Actions

| URL Parameter | Function Called | Description |
|---------------|----------------|-------------|
| (empty) | Default action | Individual employee profile report |
| `do=totals` | Payroll analytics | Comprehensive payroll analytics dashboard |
| `do=sucess` | Success page | Display success message |
| `do=error` | Error page | Display error message |

### Required Parameters by Action

**Individual Employee Report** (default):
- `chooseEmp` - Employee ID (optional, filters to specific employee)

**Payroll Analytics** (`do=totals`):
- `month` - Month filter (YYYY-MM format, optional)
- `empGroup` - Employee group filter (optional)
- `branchId` - Branch filter (optional)
- `from` - Start date for custom range (optional)
- `to` - End date for custom range (optional)

### Parameter Priority Logic
1. If `from` and `to` are specified: Use date range, ignore month
2. If `month` is specified: Use month/year filter
3. If neither: Default to current month
4. Branch filter: Uses session branchId if user is branch-restricted
5. Group filter: Applied in addition to other filters

---

## ๐Ÿ”’ Security & Permissions

### Authentication Requirements
php

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

- All actions require valid user session
- User session tracked for audit purposes

### Branch-Level Access Control
php

if ($_SESSION['branchId'] > 0)

$queryStringAll = ' AND branchid = ' . $_SESSION['branchId'];

**Access Control Logic**:
- Users with `$_SESSION['branchId'] > 0`: See only their branch employees
- Super administrators (`branchId = 0`): See all employees across branches
- Branch filter parameter only works within user's permitted scope

### Input Sanitization
php

$empid = filter_input(INPUT_POST, "chooseEmp");

$month = filter_input(INPUT_POST, 'month');

$empGroup = filter_input(INPUT_POST, 'empGroup');

$branchId = filter_input(INPUT_POST, 'branchId');

**Security Features**:
- All input parameters filtered using `filter_input()`
- SQL injection prevented by RedBean ORM and prepared statements
- Numeric parameters validated implicitly through database operations
- Date parameters processed through PHP's date functions for validation

---

## ๐Ÿ› Common Issues & Troubleshooting

### 1. **Age Calculation Issues**
**Issue**: Incorrect age display or empty age fields  
**Causes**: 
- Invalid birth date formats (0000-00-00)
- Empty birth date fields
- Date format inconsistencies

**Debug Steps**:
sql

-- Check birth date data quality

SELECT employeeId, employeeName, employeeBOD

FROM employee

WHERE employeeBOD = '0000-00-00' OR employeeBOD IS NULL OR employeeBOD = '';

-- Check date format consistency

SELECT employeeId, employeeBOD,

STR_TO_DATE(employeeBOD, '%Y-%m-%d') as parsed_date

FROM employee

WHERE employeeBOD != '0000-00-00' AND employeeBOD IS NOT NULL;

### 2. **Payroll Analytics Aggregation Issues**
**Issue**: Incorrect totals or missing transaction types  
**Common Causes**:
- New transaction types not handled in categorization logic
- Date range filters excluding expected data
- Employee group assignments missing

**Debug Query**:
sql

-- Check transaction type distribution

SELECT employeepersonneltype, COUNT(*) as count, SUM(employeepersonnelvalue) as total

FROM employeepersonnel

WHERE conditions = 0

AND employeepersonneldate >= '2024-01-01'

AND employeepersonneldate <= '2024-12-31'

GROUP BY employeepersonneltype

ORDER BY employeepersonneltype;

### 3. **Branch Filtering Issues**
**Issue**: Users see employees from other branches  
**Causes**:
- Session branchId not set correctly
- Employee records missing branchid assignments
- Filter logic not applied consistently

**Verification**:
php

// Debug branch filtering

echo "User Branch ID: " . $_SESSION['branchId'] . "\n";

echo "Query String: " . $queryStringAll . "\n";

// Check employee branch assignments

$employees_without_branch = R::getAll(

'SELECT employeeId, employeeName FROM employee WHERE branchid IS NULL OR branchid = 0'

);

### 4. **Performance Issues with Large Datasets**
**Issue**: Slow loading on payroll analytics with many employees  
**Solutions**:
- Implement date range limitations
- Add pagination for large result sets
- Optimize aggregation queries with proper indexing

sql

-- Add performance indexes

CREATE INDEX idx_employeepersonnel_date_type ON employeepersonnel(employeepersonneldate, employeepersonneltype);

CREATE INDEX idx_employeepersonnel_employee ON employeepersonnel(employeeid, conditions);

CREATE INDEX idx_employee_group_branch ON employee(employeegroupid, branchid, conditions);

---

## ๐Ÿ“Š Performance Considerations

### Database Optimization
1. **Essential Indexes**:
   ```sql
   -- Employee queries
   CREATE INDEX idx_employee_branch_conditions ON employee(branchid, conditions);
   CREATE INDEX idx_employee_group_conditions ON employee(employeegroupid, conditions);
   CREATE INDEX idx_employee_bod ON employee(employeeBOD);
   
   -- Payroll queries
   CREATE INDEX idx_employeepersonnel_composite ON employeepersonnel(employeeid, employeepersonneltype, employeepersonneldate, conditions);
   CREATE INDEX idx_employeepersonnel_date_range ON employeepersonnel(employeepersonneldate, conditions);
   
   -- Salary reports
   CREATE INDEX idx_salaryreport_employee_date ON salaryreport(employeeid, salarymonthdate);
   ```

2. **Query Optimization**:
   - Use appropriate date range filters to limit result sets
   - Implement GROUP BY efficiently with proper indexing
   - Consider materialized views for frequently accessed aggregations

### Memory Management
- Large aggregation queries can consume significant memory
- Implement result limiting for interactive displays
- Use streaming processing for export operations

### Caching Strategies
- Cache employee dropdown data for session duration
- Store frequently accessed group/branch combinations
- Implement query result caching for expensive aggregations

---

## ๐Ÿงช Testing Scenarios

### Test Case 1: Individual Employee Report

1. Access default report without employee filter

2. Verify all branch-appropriate employees display

3. Check age calculations for various birth dates

4. Test with specific employee selection

5. Validate branch filtering works correctly

6. Test with employees having no birth date

### Test Case 2: Payroll Analytics

1. Generate report for current month

2. Test with custom date ranges

3. Verify employee group filtering

4. Check branch filtering accuracy

5. Test with employees having various transaction types

6. Validate aggregation calculations

7. Check last salary data integration

### Test Case 3: Branch Access Control

1. Login as branch-restricted user

2. Verify only branch employees appear

3. Test payroll analytics respects branch limits

4. Login as super admin and verify all access

5. Check filter parameters work within permissions

### Test Case 4: Data Quality Handling

1. Test with employees having invalid birth dates

2. Check behavior with missing payroll data

3. Test with employees in multiple groups

4. Verify handling of deleted/inactive records

5. Test edge cases in date range filtering

```

---

๐Ÿ“š Related Documentation

---

Documented By: AI Assistant

Review Status: โœ… Complete

Next Review: When major changes occur