# Holiday-Based Employee Attendance Integration

## Overview
This document describes how school holidays affect employee attendance records when the school declares holidays (other than weekly off days).

## Problem Statement
The existing employee attendance system processes biometric device data into daily attendance summaries. When the school declares a holiday (other than weekly offs), employees should NOT be marked as "absent" on that day—instead, they should have their attendance status marked as "holiday".

**Business Logic Priority** (for status determination):
1. **Approved Leave** → status = `'leave'`
2. **Declared Holiday** (staff/all) → status = `'holiday'`  
3. **Weekly Off Day** → status = `'off_day'`
4. **Biometric Data** → status = `'present'`, `'partial'`, or `'absent'`

## Implementation

### 1. Holiday Model Update
**File**: `app/Models/Holiday.php`

Added `applies_to` column with possible values:
- `'students'` - Holiday applies only to students
- `'staff'` - Holiday applies only to employees
- `'all'` - Holiday applies to both students and employees

**Helper Methods**:
```php
Holiday::forStaff();      // Get holidays applicable to staff
Holiday::forStudents();   // Get holidays applicable to students
```

**Migration**: `database/migrations/2026_05_18_000002_update_holidays_table_add_applies_to.php`

### 2. AttendanceBuildDailySummary Command
**File**: `app/Console/Commands/AttendanceBuildDailySummary.php`

**Key Change**: Added holiday check after approved leave check but before processing biometric data.

**Algorithm Flow**:
```
For each employee for each date:
├─ Check Approved Leave
│  └─ If found: status = 'leave' → continue
├─ Check Staff Holiday  
│  └─ If found: status = 'holiday' → continue
├─ Check Weekly Off Day
│  └─ If found: status = 'off_day' → continue
├─ Check Biometric Data
│  ├─ No punches: status = 'absent'
│  └─ Has punches: status = 'present' or 'partial'
```

### 3. Existing Attendance Pipeline
The existing system already had:
- **AttendanceRawLog**: Stores raw biometric device punches
- **AttendanceDailySummary**: Stores processed daily attendance with `attendance_status` field
- **AttendancePushController**: API endpoint receiving device data
- **AttendanceBuildDailySummary**: Daily processing command

The holiday integration was added to step 4 above (the daily processing command).

## How It Works

### Setup: Declare a Holiday
```php
// Declare a school-wide holiday (affects staff and students)
Holiday::create([
    'name' => 'Independence Day',
    'date' => '2026-03-26',
    'applies_to' => 'all'  // or 'staff' / 'students'
]);
```

### Processing: Run Daily Summary Build
```bash
# Run manually
php artisan attendance:build-daily --date=2026-03-26

# Or schedule via scheduler:
$schedule->command('attendance:build-daily')->daily();
```

### Result: Check Attendance
When you query `AttendanceDailySummary` for 2026-03-26:
```php
AttendanceDailySummary::where('date', '2026-03-26')->get();
// All staff records will have attendance_status = 'holiday'
```

## Database Schema

### holidays table
```sql
id              INT PRIMARY KEY
name            VARCHAR(255)
date            DATE
applies_to      ENUM('students', 'staff', 'all') DEFAULT 'all'
description     TEXT
created_at      TIMESTAMP
updated_at      TIMESTAMP
```

### attendance_daily_summaries table
```
...existing columns...
attendance_status  ENUM('present', 'partial', 'absent', 'leave', 'holiday', 'off_day')
```

## Testing

### Manual Test
```bash
# Create a test holiday
php artisan tinker
> Holiday::create([
    'name' => 'Test Holiday',
    'date' => '2026-05-20',
    'applies_to' => 'staff'
])

# Build attendance for that date
> php artisan attendance:build-daily --date=2026-05-20

# Verify results
> AttendanceDailySummary::whereDate('date', '2026-05-20')->get(['employee_id', 'attendance_status']);
```

Expected output: All employee records for 2026-05-20 should have `attendance_status = 'holiday'`

## Notes

- **Backward Compatibility**: The `applies_to` field defaults to `'all'` for existing holidays without the field set
- **Status Priority**: Approved leaves take precedence over holidays (if employee is on leave and it's a holiday, status = `'leave'`)
- **Weekly Offs**: Regular weekly off days (Sunday, Friday, etc.) are handled separately via `EmployeeWorkSchedule.is_off`
- **Real-time**: Attendance status is calculated during the daily summary build process, not in real-time

## Relationship to Existing System

```
Biometric Device
    ↓
AttendancePushController (API endpoint)
    ↓
AttendanceRawLog (raw punches stored)
    ↓
AttendanceBuildDailySummary Command ← Holiday logic added here
    ↓
AttendanceDailySummary (processed with attendance_status)
    ↓
Reports & Views
```

The holiday integration is at the "AttendanceBuildDailySummary Command" stage, which determines the final `attendance_status` value.
