Files
HRM-System/docs/PLAN-biometric-shift-detection.md

68 lines
3.5 KiB
Markdown

# PLAN: Shift-Aware Biometric Routing and Double-Punch Protection
This plan documents the integration of shift-aware punch classification (In/Out routing for single punches) and the prevention of duplicate check-ins (double-punch filtering).
---
## 🏗️ Target Files
1. **Backend Controller:** `app/Http/Controllers/BiometricAttendanceController.php`
2. **Frontend UI Page:** `resources/js/pages/hr/biometric-attendance/index.tsx`
---
## 🛠️ Proposed Implementation Steps
### Phase 1: Main Dashboard UI Updates (Frontend)
Modify [index.tsx](file:///Users/dvapp/Documents/HRM/resources/js/pages/hr/biometric-attendance/index.tsx):
- Remove the `Total Entries` column from the `columns` array.
- Ensure the table renders clean and responsive rows without the total entries column.
### Phase 2: Double-Punch Filtering Logic (Backend)
Modify [BiometricAttendanceController.php](file:///Users/dvapp/Documents/HRM/app/Http/Controllers/BiometricAttendanceController.php):
- Add a helper method to filter out raw punches occurring within 60 seconds of the previous valid punch:
```php
private static function filterDoublePunches($dayEntries) {
$sorted = $dayEntries->sortBy('punch_time');
$filtered = collect();
foreach ($sorted as $entry) {
if ($filtered->isEmpty()) {
$filtered->push($entry);
} else {
$lastValid = $filtered->last();
$diffInSeconds = $entry->punch_time->diffInSeconds($lastValid->punch_time);
if ($diffInSeconds > 60) {
$filtered->push($entry);
}
}
}
return $filtered;
}
```
### Phase 3: Shift-Aware Single Punch Routing (Backend)
Modify [BiometricAttendanceController.php](file:///Users/dvapp/Documents/HRM/app/Http/Controllers/BiometricAttendanceController.php):
- Refactor the grouping map in `index` and the processing loop in `syncAll` to:
1. Filter out double-punches first using `filterDoublePunches`.
2. If the remaining entries count is exactly **1**:
- Check if the employee has a shift.
- If so, calculate the expected shift `start_time` and `end_time` (accounting for night shifts) on that work date.
- Calculate the distance from the punch to the shift start and shift end.
- If the punch is closer to the shift **end time**, set `clock_out` as the punch time, and `clock_in` as `null` (or `-`).
- Otherwise, set `clock_in` as the punch time, and `clock_out` as `null`.
- If no shift is found, default to treating the single punch as `clock_in`.
3. If the remaining entries count is **2 or more**:
- Treat the earliest punch as `clock_in` and the latest as `clock_out`.
---
## 🏁 Verification Checklist
- [ ] **Verify Column Removal:** Open the main biometric attendance page and check that the "Total Entries" column is removed.
- [ ] **Verify Double-Punch Filtering:** Push mock data containing two punches for the same employee 30 seconds apart (e.g. `08:30:00` and `08:30:30`). Verify that the dashboard groups this as a single punch at `08:30:00` and treats it as a Clock In.
- [ ] **Verify Shift-Aware Routing (Clock In):** Push a single punch at `08:45:00` for an employee with a `09:00 - 18:00` shift. Verify that the system assigns it as **Clock In**.
- [ ] **Verify Shift-Aware Routing (Clock Out):** Push a single punch at `17:45:00` for the same employee. Verify that the system assigns it as **Clock Out** and leaves Clock In blank.
- [ ] **Vite compilation:** Run `npm run build` to verify React compilation.
- [ ] **PHP syntax check:** Run `php -l` on the controller.