Employee End Day Controller Documentation
File: /controllers/employeeendday.php
Purpose: Advanced employee shift closure system with attendance tracking, payroll integration, and hierarchical status management
Last Updated: December 20, 2024
Total Functions: 7+
Lines of Code: ~477
---
๐ Overview
The Employee End Day Controller is a sophisticated workforce management system that handles the closure of employee shifts with comprehensive attendance tracking, automatic payroll integration, and hierarchical approval workflows. It provides:
- โข Multi-level shift closure (Employee โ Subgroup โ Group โ Day)
- โข Real-time attendance data processing with discount calculations
- โข Automatic payroll system integration via cURL
- โข Dynamic employee grouping and filtering
- โข Attendance system integration with configurable rules
- โข Late arrival and absence tracking with permission management
- โข Comprehensive audit trail and status tracking
Primary Functions
- โ Hierarchical shift closure workflow management
- โ Real-time attendance data collection and processing
- โ Automatic late/absence discount calculations
- โ Integration with payroll system (employeePersonalController)
- โ Employee grouping and subgroup management
- โ Dynamic attendance system rule application
- โ Multi-level status tracking and validation
- โ Ajax-based real-time operations
- โ Branch-based access control
Related Controllers
- โข employeePersonalController.php - Payroll integration
- โข employeegroups.php - Group management
- โข employeesubgroups.php - Subgroup management
- โข employeeAttendanceSystems.php - Attendance rules
---
๐๏ธ Database Tables
Core Employee Tables
| Table Name | Purpose | Key Columns | |
|---|---|---|---|
| **employee** | Employee master data | employeeId, employeeName, employeegroupid, employeesubgroupid, branchid, conditions | |
| **employeegroup** | Employee group hierarchy | id, name, employeeattendancesystemid, userid, del | |
| **employeesubgroup** | Employee subgroup structure | id, name, employeegroupid, employeeattendancesystemid, userid, del |
| Table Name | Purpose | Key Columns | |
|---|---|---|---|
| **employeeattendancesystem** | Attendance rules configuration | id, attendanceTime, departureTime, userid, del | |
| **employeeclosedayhistory** | Individual employee day closure | id, day, employeeid, attendanceTime, departureTime, latePeriod, lateDiscount, isAbsent, absentDiscount, status |
| Table Name | Purpose | Key Columns | |
|---|---|---|---|
| **employeeclosedaygroupstatus** | Group-level closure status | id, day, employeegroupid, status, userid, sysdate, conditions | |
| **employeeclosedaysubgroupstatus** | Subgroup-level closure status | id, day, employeesubgroupid, status, userid, sysdate, conditions | |
| **employeeclosedaystatus** | System-wide day closure status | id, day, status, userid, sysdate, conditions |
| Table Name | Purpose | Key Columns |
|---|---|---|
| **youtubelink** | Tutorial references | youtubelinkid, title, url |
๐ Key Functions
1. getdaytoclose - Load Employee Day Data (Ajax)
Location: Line 129-176
Purpose: Load employee data for a specific day with attendance system rules
Function Signature:
// Ajax Action: do=getdaytoclose
$day = filter_input(INPUT_POST, 'day');
$employeegroupid = (int) filter_input(INPUT_POST, 'employeegroupid');
$employeesubgroupid = (int) filter_input(INPUT_POST, 'employeesubgroupid');
Process Flow:
1. Build Employee Query:
$queryString = ' WHERE employee.conditions=0 ';
if ($employeesubgroupid > 0) {
$queryString .= " and employeesubgroupid = $employeesubgroupid ";
} elseif ($employeegroupid > 0) {
$queryString .= " and employeegroupid = $employeegroupid ";
}
```
2. **Apply Branch Filtering**:
```php
if ($_SESSION['branchId'] > 0)
$queryString .= ' AND branchid = ' . $_SESSION['branchId'];
```
3. **Load Attendance System Rules**:
```php
foreach ($employeeArr as $emp) {
$attendanceSysData = $employeeAttendanceSystemEX->getAttendanceSystemByEmployeeSubGroup($emp->employeesubgroupid);
$sys->attendanceTime = $attendanceSysData->attendanceTime;
$sys->departureTime = $attendanceSysData->departureTime;
// Load employee-specific discount rates
$sys->halfHourLateWithPermissionDisount = $emp->halfHourLateWithPermissionDisount;
// ... (all other discount configurations)
}
```
**Features**:
- Dynamic group/subgroup filtering
- Real-time attendance system rule loading
- Employee-specific discount configuration
- JSON-encoded rule data for frontend processing
---
### 2. **closeday** - Execute Day Closure (Ajax)
**Location**: Line 177-315
**Purpose**: Process and close employee shifts with payroll integration
**Function Signature**:
php
// Ajax Action: do=closeday
// Transaction-protected operation
$mytransactions = new Transaction();
**Process Flow**:
1. **Validate Input Data**:
```php
$day = filter_input(INPUT_POST, 'day');
$empitr = (int) filter_input(INPUT_POST, 'empitr');
if (isRealDate($day) && $empitr > 1) {
// Process closure
}
```
2. **Process Each Employee**:
```php
for ($i = 1; $i < $empitr; $i++) {
$empid = (int) filter_input(INPUT_POST, 'empid' . $i);
$attendanceTime = filter_input(INPUT_POST, 'attendanceTime' . $empid);
$departureTime = filter_input(INPUT_POST, 'departureTime' . $empid);
$latePeriod = (float) filter_input(INPUT_POST, 'latePeriod' . $empid);
$lateDiscount = (float) filter_input(INPUT_POST, 'lateDiscount' . $empid);
$isAbsent = (int) filter_input(INPUT_POST, 'isAbsent' . $empid);
$absentDiscount = (float) filter_input(INPUT_POST, 'absentDiscount' . $empid);
}
```
3. **Update Employee History**:
```php
if ($isAbsent == 0) { // Not absent
$employeeCloseDayHistory->attendanceTime = $attendanceTime . ":00";
$employeeCloseDayHistory->departureTime = $departureTime . ":00";
$employeeCloseDayHistory->latePeriod = $latePeriod;
$employeeCloseDayHistory->lateDiscount = $lateDiscount;
} elseif ($isAbsent == 1) { // Absent
$employeeCloseDayHistory->attendanceTime = "00:00:00";
$employeeCloseDayHistory->departureTime = "00:00:00";
$employeeCloseDayHistory->isAbsent = $isAbsent;
$employeeCloseDayHistory->absentDiscount = $absentDiscount;
}
```
4. **Payroll Integration**:
```php
affectOnSalary($employeeCloseDayHistory, $oldEmployeeCloseDayHistory);
```
**Hierarchical Status Updates**:
- Updates subgroup status when all employees closed
- Updates group status when all subgroups closed
- Updates day status when all groups closed
---
### 3. **affectOnSalary()** - Payroll System Integration
**Location**: Line 373-404
**Purpose**: Integrate attendance data with payroll system via cURL
**Function Signature**:
php
function affectOnSalary($newEmployeeCloseDayHistory, $oldEmployeeCloseDayHistory)
**Process Flow**:
1. **Change Detection**:
```php
if($oldEmployeeCloseDayHistory->status == 1 &&
$newEmployeeCloseDayHistory->isAbsent == $oldEmployeeCloseDayHistory->isAbsent &&
$newEmployeeCloseDayHistory->absentDiscount == $oldEmployeeCloseDayHistory->absentDiscount &&
$newEmployeeCloseDayHistory->lateDiscount == $oldEmployeeCloseDayHistory->lateDiscount) {
// No changes, do nothing
}
```
2. **Remove Old Salary Effects**:
```php
if ($oldEmployeeCloseDayHistory->status != -1) {
if ($oldEmployeeCloseDayHistory->isAbsent == 0) {
curlDeleteEmployeePersonal($oldEmployeeCloseDayHistory->employeeid,
$oldEmployeeCloseDayHistory->day,
$oldEmployeeCloseDayHistory->lateDiscount, 5);
} elseif ($oldEmployeeCloseDayHistory->isAbsent == 1) {
curlDeleteEmployeePersonal($oldEmployeeCloseDayHistory->employeeid,
$oldEmployeeCloseDayHistory->day,
$oldEmployeeCloseDayHistory->absentDiscount, 9);
}
}
```
3. **Apply New Salary Effects**:
```php
if ($newEmployeeCloseDayHistory->isAbsent == 0) {
curlAddEmployeePersonal($newEmployeeCloseDayHistory->employeeid,
$newEmployeeCloseDayHistory->day,
$newEmployeeCloseDayHistory->lateDiscount, 5);
} elseif ($newEmployeeCloseDayHistory->isAbsent == 1) {
curlAddEmployeePersonal($newEmployeeCloseDayHistory->employeeid,
$newEmployeeCloseDayHistory->day,
$newEmployeeCloseDayHistory->absentDiscount, 9);
}
```
---
### 4. **curlAddEmployeePersonal()** - Add Payroll Entry
**Location**: Line 406-443
**Purpose**: Add late/absence deductions to employee payroll via cURL
**Function Signature**:
php
function curlAddEmployeePersonal($empid, $day, $discountVal, $type)
// $type: 5=late, 9=absent
**cURL Implementation**:
php
$post = [
'fromCtrl' => 'employeeendday',
'empName' => $empid,
'empValue' => $discountVal,
'employeepersonneldate' => $dayAsDateTime,
'type' => $type, // 5=late, 9=absent
'Costcenterid' => '-1',
'paymethod' => '0',
'userid' => $_SESSION['userid'],
'saveid' => $_SESSION["saveid"],
'dbname' => $_SESSION["dbname"],
];
$ch = curl_init('http://localhost/ERP/controllers/employeePersonalController.php?do=add');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
$response = curl_exec($ch);
---
### 5. **curlDeleteEmployeePersonal()** - Remove Payroll Entry
**Location**: Line 445-476
**Purpose**: Remove previously applied payroll deductions via cURL
**Features**:
- Removes late/absence deductions
- Maintains payroll consistency
- Supports editing/reversal operations
---
### 6. **closedayshow** - Historical View
**Location**: Line 316-343
**Purpose**: Display historical employee day closure data
**Features**:
- Monthly attendance history
- Employee-specific filtering
- Branch-based access control
- Historical trend analysis
---
### 7. **isRealDate()** - Date Validation
**Location**: Line 366-372
**Purpose**: Validate date format for closure operations
php
function isRealDate($date) {
if (false === strtotime($date)) {
return false;
}
list($year, $month, $day) = explode('-', $date);
return checkdate($month, $day, $year);
}
---
## ๐ Workflows
### Workflow 1: Hierarchical Day Closure Process
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ START: Select Day to Close โ
โโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 1. Load Employee Data for Day โ
โ - Apply group/subgroup filters โ
โ - Load attendance system rules โ
โ - Apply branch restrictions โ
โ - Generate attendance forms โ
โโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 2. Process Individual Employee Closures โ
โ FOR EACH Employee: โ
โ โ โ
โ โโโ Record attendance/departure times โ
โ โโโ Calculate late period discounts โ
โ โโโ Process absence status and discounts โ
โ โโโ Update employeeclosedayhistory โ
โ โโโ Integrate with payroll system โ
โโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 3. Update Subgroup Status โ
โ - Mark subgroup as closed โ
โ - Check if all employees in subgroup are closed โ
โ - Update employeeclosedaysubgroupstatus โ
โโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 4. Check Group Closure Criteria โ
โ - Count total subgroups in group โ
โ - Count closed subgroups for day โ
โ - IF all subgroups closed: Mark group as closed โ
โ - Update employeeclosedaygroupstatus โ
โโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 5. Check System-Wide Day Closure โ
โ - Count total employee groups โ
โ - Count closed groups for day โ
โ - IF all groups closed: Mark day as system closed โ
โ - Update employeeclosedaystatus โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
---
### Workflow 2: Payroll Integration Process
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ START: Employee Attendance Data Changed โ
โโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 1. Detect Changes in Attendance Data โ
โ - Compare old vs new attendance status โ
โ - Compare old vs new discount amounts โ
โ - Determine if payroll update needed โ
โโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ (if changes detected)
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 2. Remove Old Payroll Effects โ
โ IF Previously Late: โ
โ โ - cURL DELETE late deduction (type=5) โ
โ IF Previously Absent: โ
โ โ - cURL DELETE absence deduction (type=9) โ
โโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 3. Apply New Payroll Effects โ
โ IF Currently Late: โ
โ โ - cURL ADD late deduction (type=5) โ
โ IF Currently Absent: โ
โ โ - cURL ADD absence deduction (type=9) โ
โโโโโโโโโโโโโโโโโโโโโโฌโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ
โผ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ 4. Update Employee Personal Records โ
โ - POST to employeePersonalController.php โ
โ - Include employee ID, date, amount, type โ
โ - Maintain audit trail in payroll system โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
---
## ๐ URL Routes & Actions
| URL Parameter | Function Called | Description | Ajax |
|---------------|----------------|-------------|------|
| (empty) or `do=show` | Default display | Show day closure form | No |
| `do=getdaytoclose` | Load day data | Load employees for specific day | Yes |
| `do=closeday` | `closeday()` | Execute day closure process | Yes |
| `do=closedayshow` | Historical view | Show historical closure data | No |
| `do=sucess` | Success page | Display success message | No |
| `do=error` | Error page | Display error message | No |
### Ajax Operations Parameters
**getdaytoclose** (POST):
- `day` - Date to close (YYYY-MM-DD format)
- `employeegroupid` - Group filter (optional)
- `employeesubgroupid` - Subgroup filter (optional)
**closeday** (POST):
- `day` - Date being closed
- `empitr` - Number of employees being processed
- `employeegroupid_day` - Group ID for closure
- `employeesubgroupid_day` - Subgroup ID for closure
- `empid{N}` - Employee ID for each employee
- `attendanceTime{empid}` - Attendance time
- `departureTime{empid}` - Departure time
- `latePeriod{empid}` - Late period in hours
- `lateDiscount{empid}` - Late discount amount
- `isAbsent{empid}` - Absence status (0/1)
- `absentDiscount{empid}` - Absence discount amount
---
## ๐งฎ Calculation Methods
### Late Period Discount Calculation
Based on employee-specific rates loaded from attendance system:
php
// Example discount structure:
$sys->halfHourLateWithPermissionDisount = $emp->halfHourLateWithPermissionDisount;
$sys->hourLateWithPermissionDisount = $emp->hourLateWithPermissionDisount;
$sys->hourAndHalfLateWithPermissionDisount = $emp->hourAndHalfLateWithPermissionDisount;
$sys->twoHoursLateWithPermissionDisount = $emp->twoHoursLateWithPermissionDisount;
$sys->moreThanTwoHoursLateWithPermissionDisount = $emp->moreThanTwoHoursLateWithPermissionDisount;
// Without permission discounts are typically higher
$sys->halfHourLateWithoutPermissionDisount = $emp->halfHourLateWithoutPermissionDisount;
// ... etc
### Absence Discount Calculation
php
// Day absence discounts
$sys->dayAbsenceWithPermissionDisount = $emp->dayAbsenceWithPermissionDisount;
$sys->dayAbsenceWithoutPermissionDisount = $emp->dayAbsenceWithoutPermissionDisount;
### Hierarchical Status Logic
php
// Subgroup closure check
$noOfSubGroupsInaGroup = count($employeeSubGroupEX->queryByEmployeegroupidEX($subGroupData->employeegroupid));
$noOfSubGroupsClosedInaGroupForADay = count($EmployeeclosedaysubgroupstatusEX->queryByEmployeegroupidAndDayGetDistinctSubGroupsClosed($subGroupData->employeegroupid, $day));
if ($noOfSubGroupsInaGroup == $noOfSubGroupsClosedInaGroupForADay) {
// Mark group as closed
}
// System-wide closure check
$noOfGroups = $employeeGroupEX->queryAllEXCount();
$noOfGroupsClosedInADay = $employeeCloseDayGroupStatusEX->getNoOfGroupsClosedInADay($day);
if ($noOfGroups == $noOfGroupsClosedInADay) {
// Mark entire day as closed
}
---
## ๐ Security & Permissions
### Authentication & Session Management
php
include_once("../public/authentication.php");
### Branch-Level Access Control
php
if ($_SESSION['branchId'] > 0)
$queryString .= ' AND branchid = ' . $_SESSION['branchId'];
### Transaction Security
php
$mytransactions = new Transaction();
try {
// All closure operations
$mytransactions->commit();
} catch (Exception $e) {
echo -1;
$mytransactions->rollback();
}
### cURL Security
- Session-based user identification
- Database name validation
- Save ID verification
- Input parameter validation
---
## ๐ Common Issues & Troubleshooting
### 1. **Payroll Integration Failures**
**Issue**: cURL calls to employeePersonalController.php fail
**Causes**:
- Incorrect URL (hardcoded localhost)
- Missing session parameters
- Target controller unavailable
**Fix**:
php
// Use dynamic host configuration
$host = $_SERVER['HTTP_HOST'];
$ch = curl_init("http://$host/ERP/controllers/employeePersonalController.php?do=add");
### 2. **Hierarchical Status Issues**
**Issue**: Groups/subgroups not marked as closed properly
**Debug Steps**:
1. Check employee count queries
2. Verify status update logic
3. Examine closure criteria calculations
### 3. **Date Validation Problems**
**Issue**: Invalid date formats cause closure failures
**Fix**: Enhance date validation:
php
function isRealDate($date) {
if (false === strtotime($date)) {
return false;
}
if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $date)) {
return false;
}
list($year, $month, $day) = explode('-', $date);
return checkdate($month, $day, $year);
}
### 4. **Ajax Response Handling**
**Issue**: Frontend doesn't receive proper Ajax responses
**Ensure**:
- Return 1 for success, -1 for error
- No HTML output before Ajax responses
- Proper JSON encoding where needed
---
## ๐ Performance Considerations
### Database Optimization
1. **Critical Indexes**:
- `employee(employeegroupid, employeesubgroupid, conditions, branchid)`
- `employeeclosedayhistory(day, employeeid, status)`
- `employeeclosedaygroupstatus(day, employeegroupid, status)`
- `employeeclosedaysubgroupstatus(day, employeesubgroupid, status)`
2. **Query Optimization**:
- Use EXISTS queries for status checks
- Limit date ranges appropriately
- Cache attendance system rules
### cURL Performance
- Implement connection pooling
- Use asynchronous calls where possible
- Add timeout configurations
- Cache payroll responses
### Memory Management
- Process employees in batches for large organizations
- Clear variables in loops
- Optimize JSON data structures
---
## ๐งช Testing Scenarios
### Test Case 1: Complete Day Closure Workflow
1. Select a day with employees in multiple groups/subgroups
2. Close individual employees with various attendance statuses
3. Verify subgroup closure when all employees closed
4. Check group closure when all subgroups closed
5. Confirm system-wide closure when all groups closed
6. Validate payroll integration for each step
### Test Case 2: Payroll Integration
1. Close employee with late arrival
2. Verify late deduction appears in payroll system
3. Edit the same employee's data
4. Confirm old deduction removed and new one applied
5. Test absence scenarios similarly
### Test Case 3: Branch Access Control
1. Login as branch-restricted user
2. Verify only branch employees appear for closure
3. Test closure operations respect branch boundaries
4. Check status updates don't affect other branches
### Test Case 4: Error Handling
1. Test with invalid date formats
2. Simulate cURL failures to payroll system
3. Test transaction rollback scenarios
4. Verify data consistency after failures
```
---
๐ Related Documentation
- โข CLAUDE.md - PHP 8.2 migration guide
- โข employeePersonalController.md - Payroll integration
- โข employeegroups.md - Group management
- โข employeeAttendanceSystems.md - Attendance rules
---
Documented By: AI Assistant
Review Status: โ Complete
Next Review: When major changes occur