# Employee Attendance & Payroll API Documentation

## Overview
Two new modules have been added to the Employee management system:
1. **Attendance Tracking** - Daily attendance records with clock in/out times
2. **Payroll Management** - Automated payroll calculation supporting daily and monthly pay types

---

## Database Schema

### Tables Created

#### `employee_attendances`
| Column | Type | Description |
|--------|------|-------------|
| `id` | bigint | Primary key |
| `employee_id` | bigint | FK to accounts table |
| `attendance_date` | date | Date of attendance |
| `clock_in` | time | Clock in time |
| `clock_out` | time | Clock out time |
| `status` | enum | present/absent/half_day/leave/holiday |
| `remarks` | text | Optional notes |
| `hours_worked` | decimal(5,2) | Auto-calculated working hours |
| `created_by` | bigint | FK to users |
| `updated_by` | bigint | FK to users |
| `created_at` | timestamp | |
| `updated_at` | timestamp | |

**Unique constraint**: `(employee_id, attendance_date)` - prevents duplicate entries

#### `employee_payrolls`
| Column | Type | Description |
|--------|------|-------------|
| `id` | bigint | Primary key |
| `payroll_code` | string | Unique code (PAYROLL-YYYY-XXXXX) |
| `employee_id` | bigint | FK to accounts table |
| `period_start` | date | Payroll period start |
| `period_end` | date | Payroll period end |
| `pay_type` | enum | daily/monthly |
| `days_present` | integer | Count of present days |
| `days_absent` | integer | Count of absent days |
| `days_half` | integer | Count of half days |
| `days_leave` | integer | Count of leave days |
| `days_holiday` | integer | Count of holidays |
| `total_working_hours` | decimal(8,2) | Sum of hours worked |
| `base_amount` | decimal(15,2) | Base salary/wages |
| `incentives` | decimal(15,2) | Sum of applicable incentives |
| `deductions` | decimal(15,2) | Deductions for absences |
| `adjustments` | decimal(15,2) | Manual adjustments (+/-) |
| `gross_salary` | decimal(15,2) | Total before deductions |
| `net_salary` | decimal(15,2) | Final payable amount |
| `status` | enum | draft/calculated/approved/paid/cancelled |
| `payment_date` | date | Date of payment |
| `payment_method` | string | Payment method |
| `payment_reference` | string | Payment reference number |
| `remarks` | text | Optional notes |
| `created_by` | bigint | FK to users |
| `approved_by` | bigint | FK to users |
| `paid_by` | bigint | FK to users |
| `approved_at` | timestamp | Approval timestamp |
| `paid_at` | timestamp | Payment timestamp |
| `created_at` | timestamp | |
| `updated_at` | timestamp | |
| `deleted_at` | timestamp | Soft delete |

**Status workflow**: draft → calculated → approved → paid

---

## Models

### EmployeeAttendance
**Location**: `app/Models/EmployeeAttendance.php`

**Key Features**:
- Auto-calculates `hours_worked` from `clock_in` and `clock_out` before saving
- Activity logging with Spatie
- Relationships: `employee`, `creator`, `updater`
- Scopes: `dateRange()`, `status()`

### EmployeePayroll
**Location**: `app/Models/EmployeePayroll.php`

**Key Features**:
- Uses `HasStatusManagement` trait for workflow enforcement
- Activity logging with Spatie
- Soft deletes enabled
- Relationships: `employee`, `creator`, `approver`, `payer`
- Scopes: `status()`, `period()`
- Status constants defined for workflow management

### Account Model Extensions
**Location**: `app/Models/Account.php`

**New Relationships**:
```php
public function attendances(): HasMany
public function payrolls(): HasMany
public function incentives(): HasMany
```

---

## Services

### PayrollService
**Location**: `app/Services/PayrollService.php`

**Key Methods**:

#### `calculatePayroll(int $employeeId, string $periodStart, string $periodEnd): EmployeePayroll`
Calculates payroll for an employee based on attendance records.

**Logic**:
- **Daily employees**: `daily_wage × (present_days + half_days × 0.5)`
- **Monthly employees**: `basic_salary - (absent_days × daily_rate)`
- **Daily rate**: `monthly_salary / 30`
- Adds incentives from `incentives` table
- Auto-generates unique payroll code

#### `recalculatePayroll(EmployeePayroll $payroll): EmployeePayroll`
Recalculates an existing payroll (only if status allows editing).

#### `approvePayroll(EmployeePayroll $payroll): EmployeePayroll`
Transitions payroll from `calculated` to `approved`.

#### `markAsPaid(EmployeePayroll $payroll, string $method, ?string $ref, ?string $date): EmployeePayroll`
Marks payroll as paid and records payment details.

#### `bulkCalculatePayroll(array $employeeIds, string $periodStart, string $periodEnd): array`
Calculates payroll for multiple employees in one operation.

**Returns**:
```php
[
    'success' => [...],  // Array of successful payroll records
    'failed' => [...],   // Array of failures with error messages
]
```

---

## API Endpoints

### Attendance Endpoints

All routes are prefixed with `/employee-attendance` and require authentication.

#### List/Filter Attendance (DataTables)
```http
GET /employee-attendance
```

**Query Parameters**:
- `employee_id` (optional) - Filter by employee
- `date_from` (optional) - Filter from date
- `date_to` (optional) - Filter to date
- `status` (optional) - Filter by status

**Response** (DataTables format):
```json
{
  "data": [
    {
      "id": 1,
      "employee_name": "John Doe",
      "employee_code": "EMP-2130-00001",
      "attendance_date": "2026-06-01",
      "clock_in": "08:00",
      "clock_out": "17:00",
      "status": "present",
      "hours_worked": 9.0
    }
  ]
}
```

#### Store Attendance
```http
POST /employee-attendance
Content-Type: application/json
```

**Request Body**:
```json
{
  "employee_id": 123,
  "attendance_date": "2026-06-01",
  "clock_in": "08:00",
  "clock_out": "17:00",
  "status": "present",
  "remarks": "On time"
}
```

**Response** (201 Created):
```json
{
  "success": true,
  "message": "Attendance recorded successfully.",
  "data": {
    "id": 1,
    "employee_id": 123,
    "attendance_date": "2026-06-01",
    "status": "present",
    "hours_worked": 9.0,
    "employee": { ... }
  }
}
```

#### Bulk Store Attendance
```http
POST /employee-attendance/bulk
Content-Type: application/json
```

**Request Body**:
```json
{
  "attendance_date": "2026-06-01",
  "attendances": [
    {
      "employee_id": 123,
      "status": "present",
      "clock_in": "08:00",
      "clock_out": "17:00"
    },
    {
      "employee_id": 124,
      "status": "absent",
      "remarks": "Sick leave"
    }
  ]
}
```

**Response** (201 Created):
```json
{
  "success": true,
  "message": "Bulk attendance recorded.",
  "created_count": 2,
  "skipped_count": 0,
  "created_ids": [1, 2],
  "skipped_employee_ids": []
}
```

#### Get Attendance Summary
```http
GET /employee-attendance/summary?employee_id=123&date_from=2026-06-01&date_to=2026-06-30
```

**Response**:
```json
{
  "success": true,
  "data": {
    "employee_id": 123,
    "period": {
      "from": "2026-06-01",
      "to": "2026-06-30"
    },
    "summary": {
      "present": 22,
      "absent": 2,
      "half_day": 1,
      "leave": 3,
      "holiday": 2,
      "total_hours": 198.0
    },
    "total_records": 30
  }
}
```

#### Show Attendance
```http
GET /employee-attendance/{id}
```

#### Update Attendance
```http
PUT /employee-attendance/{id}
Content-Type: application/json
```

**Request Body**:
```json
{
  "clock_in": "08:15",
  "clock_out": "17:15",
  "status": "present",
  "remarks": "Updated times"
}
```

#### Delete Attendance
```http
DELETE /employee-attendance/{id}
```

---

### Payroll Endpoints

All routes are prefixed with `/employee-payroll` and require authentication.

#### List/Filter Payrolls (DataTables)
```http
GET /employee-payroll
```

**Query Parameters**:
- `employee_id` (optional)
- `status` (optional)
- `pay_type` (optional)
- `period_start` (optional)
- `period_end` (optional)

**Response** (DataTables format):
```json
{
  "data": [
    {
      "id": 1,
      "payroll_code": "PAYROLL-2026-00001",
      "employee_name": "John Doe",
      "period_start": "2026-06-01",
      "period_end": "2026-06-30",
      "pay_type": "monthly",
      "status": "approved",
      "net_salary": "50,000.00"
    }
  ]
}
```

#### Calculate Payroll
```http
POST /employee-payroll/calculate
Content-Type: application/json
```

**Request Body**:
```json
{
  "employee_id": 123,
  "period_start": "2026-06-01",
  "period_end": "2026-06-30"
}
```

**Response** (201 Created):
```json
{
  "success": true,
  "message": "Payroll calculated successfully.",
  "data": {
    "id": 1,
    "payroll_code": "PAYROLL-2026-00001",
    "employee_id": 123,
    "period_start": "2026-06-01",
    "period_end": "2026-06-30",
    "pay_type": "monthly",
    "days_present": 22,
    "days_absent": 2,
    "base_amount": 50000.00,
    "incentives": 5000.00,
    "deductions": 3333.33,
    "adjustments": 0.00,
    "gross_salary": 55000.00,
    "net_salary": 51666.67,
    "status": "calculated",
    "employee": { ... }
  }
}
```

#### Bulk Calculate Payroll
```http
POST /employee-payroll/bulk-calculate
Content-Type: application/json
```

**Request Body**:
```json
{
  "employee_ids": [123, 124, 125],
  "period_start": "2026-06-01",
  "period_end": "2026-06-30"
}
```

**Response** (201 Created):
```json
{
  "success": true,
  "message": "Bulk payroll calculation completed.",
  "data": {
    "success": [
      {
        "employee_id": 123,
        "payroll_id": 1,
        "net_salary": 51666.67
      },
      {
        "employee_id": 124,
        "payroll_id": 2,
        "net_salary": 25000.00
      }
    ],
    "failed": [
      {
        "employee_id": 125,
        "error": "Employee not active"
      }
    ]
  }
}
```

#### Show Payroll
```http
GET /employee-payroll/{id}
```

#### Recalculate Payroll
```http
POST /employee-payroll/{id}/recalculate
```

**Response**:
```json
{
  "success": true,
  "message": "Payroll recalculated successfully.",
  "data": { ... }
}
```

#### Update Adjustments
```http
PATCH /employee-payroll/{id}/adjustments
Content-Type: application/json
```

**Request Body**:
```json
{
  "adjustments": 1000.00,
  "remarks": "Bonus for exceptional performance"
}
```

**Note**: Adjustments can be positive (bonus) or negative (penalty). The net salary is recalculated automatically.

#### Approve Payroll
```http
POST /employee-payroll/{id}/approve
```

**Response**:
```json
{
  "success": true,
  "message": "Payroll approved successfully.",
  "data": { ... }
}
```

#### Mark as Paid
```http
POST /employee-payroll/{id}/mark-paid
Content-Type: application/json
```

**Request Body**:
```json
{
  "payment_method": "Bank Transfer",
  "payment_reference": "TXN123456",
  "payment_date": "2026-07-05"
}
```

#### Cancel Payroll
```http
POST /employee-payroll/{id}/cancel
Content-Type: application/json
```

**Request Body**:
```json
{
  "remarks": "Calculation error - needs recalculation"
}
```

#### Delete Payroll (Soft Delete)
```http
DELETE /employee-payroll/{id}
```

---

## Payroll Calculation Logic

### Daily Wage Employees (`wage_type = 'daily_wager'`)

```
base_amount = daily_wage × (days_present + days_half × 0.5)
deductions = 0  (already accounted in base)
gross_salary = base_amount + incentives
net_salary = gross_salary
```

### Monthly Salary Employees (`wage_type = 'salary'` or `'contract'`)

```
base_amount = basic_salary
per_day_rate = basic_salary / 30
deductions = per_day_rate × days_absent
gross_salary = base_amount + incentives + adjustments
net_salary = gross_salary - deductions
```

### Incentives
Sum of all active incentive records from `incentives` table for the employee.

### Adjustments
Manual additions or deductions entered via the `updateAdjustments` endpoint. Can be positive (bonus) or negative (penalty).

---

## Status Workflows

### Attendance
No formal workflow - records can be created, updated, or deleted at any time.

### Payroll
```
draft → calculated → approved → paid
```

**Editable states**: `draft`, `calculated`  
**Deletable states**: `draft`  
**Cancellable states**: `draft`, `calculated`, `approved`  
**Cannot edit/delete**: `paid`, `cancelled`

---

## Form Request Classes

### Attendance
- `App\Http\Requests\Employee\StoreAttendanceRequest`
- `App\Http\Requests\Employee\UpdateAttendanceRequest`

### Payroll
- `App\Http\Requests\Employee\CalculatePayrollRequest`

---

## Controllers

- `App\Http\Controllers\EmployeeAttendanceController`
- `App\Http\Controllers\EmployeePayrollController`

Both use the `LogsActivity` trait for audit logging.

---

## Activity Logging

All operations are logged to `activity_log` table via Spatie Activity Log:

**Log names**:
- `employee_attendance`
- `employee_payroll`

**Actions logged**:
- Attendance: store, update, delete, bulk_store
- Payroll: calculate, bulk_calculate, recalculate, approve, mark_paid, cancel, delete, update_adjustments

---

## Usage Examples

### Daily Attendance Flow
1. Record attendance for employees each day using `POST /employee-attendance` or bulk endpoint
2. View attendance records on `GET /employee-attendance` with DataTables
3. Get summary for payroll period using `GET /employee-attendance/summary`

### Payroll Processing Flow
1. **Calculate**: `POST /employee-payroll/calculate` for single employee OR `POST /employee-payroll/bulk-calculate` for multiple
2. **Review**: Check calculated payroll via `GET /employee-payroll/{id}`
3. **Adjust** (if needed): `PATCH /employee-payroll/{id}/adjustments` to add bonuses/deductions
4. **Approve**: `POST /employee-payroll/{id}/approve`
5. **Process Payment**: After payment, `POST /employee-payroll/{id}/mark-paid`
6. **Cancel** (if error): `POST /employee-payroll/{id}/cancel` and recalculate

---

## Notes

- All monetary values are stored as `decimal(15,2)`
- Dates use `Y-m-d` format (ISO 8601)
- Times use `H:i` format (24-hour)
- All endpoints return JSON responses
- Authentication required for all endpoints
- Activity logging tracks all changes
- Payroll codes auto-generated in format `PAYROLL-YYYY-XXXXX`
- Employee validation ensures `model_type = 'employee'` in accounts table

---

## Migration Files

- `2026_06_01_000001_create_employee_attendances_table.php`
- `2026_06_01_000002_create_employee_payrolls_table.php`

Run migrations:
```bash
php artisan migrate
```
