Files
HRM-System/tests/Feature/AttendanceShiftEnforcementTest.php

166 lines
5.1 KiB
PHP

<?php
namespace Tests\Feature;
use Tests\TestCase;
use App\Models\User;
use App\Models\Employee;
use App\Models\Shift;
use App\Models\Branch;
use App\Models\AttendanceRecord;
use App\Services\AttendanceService;
use Illuminate\Foundation\Testing\RefreshDatabase;
class AttendanceShiftEnforcementTest extends TestCase
{
use RefreshDatabase;
protected $user;
protected $employee;
protected $shift;
protected $branch;
protected function setUp(): void
{
parent::setUp();
$companyUser = User::create([
'name' => 'Company Admin',
'email' => 'admin@company.com',
'password' => bcrypt('password'),
'type' => 'company',
]);
$this->branch = Branch::create([
'name' => 'Main Branch',
'created_by' => $companyUser->id,
]);
$this->user = User::create([
'name' => 'Test Employee',
'email' => 'testemployee@example.com',
'password' => bcrypt('password'),
'type' => 'employee',
'created_by' => $companyUser->id,
'branch_id' => $this->branch->id,
]);
// Shift 09:00:00 to 18:00:00 with 15 mins grace period
$this->shift = Shift::create([
'name' => 'Morning Shift',
'start_time' => '09:00:00',
'end_time' => '18:00:00',
'grace_period' => 15,
'status' => 'active',
'created_by' => 1,
]);
$this->employee = Employee::create([
'user_id' => $this->user->id,
'employee_id' => 'EMPTEST001',
'branch_id' => $this->branch->id,
'shift_id' => $this->shift->id,
'rest_days' => ['sunday'],
'date_of_joining' => '2026-08-01',
'created_by' => 1,
]);
}
public function test_clock_in_within_grace_period_is_not_late()
{
$service = app(AttendanceService::class);
$result = $service->processClock($this->user, $this->employee, [
'action' => 'clock_in',
'latitude' => 14.5995,
'longitude' => 120.9842,
]);
$this->assertTrue($result['success']);
$record = AttendanceRecord::where('employee_id', $this->user->id)->first();
$this->assertNotNull($record);
$this->assertEquals($this->shift->id, $record->shift_id);
}
public function test_late_clock_in_sets_is_late_flag()
{
// Simulate late clock in past grace period
$record = AttendanceRecord::create([
'employee_id' => $this->user->id,
'branch_id' => $this->branch->id,
'shift_id' => $this->shift->id,
'date' => '2026-08-10',
'clock_in' => '09:30:00', // Shift 09:00 + 15m grace = 09:15. 09:30 is late
'is_late' => true,
'late_hours' => 0.50,
'status' => 'present',
'created_by' => $this->user->id,
]);
$this->assertTrue((bool)$record->is_late);
$this->assertEquals(0.50, $record->late_hours);
}
public function test_break_in_and_break_out_recorded_on_attendance_record()
{
$record = AttendanceRecord::create([
'employee_id' => $this->user->id,
'branch_id' => $this->branch->id,
'shift_id' => $this->shift->id,
'date' => '2026-08-10',
'clock_in' => '09:00:00',
'status' => 'present',
'created_by' => $this->user->id,
]);
$service = app(AttendanceService::class);
// Break In
$service->processClock($this->user, $this->employee, [
'action' => 'break_in',
]);
$record->refresh();
$this->assertNotNull($record->break_in);
// Break Out
$service->processClock($this->user, $this->employee, [
'action' => 'break_out',
]);
$record->refresh();
$this->assertNotNull($record->break_out);
}
public function test_today_api_returns_all_db_metrics_breakdown()
{
AttendanceRecord::create([
'employee_id' => $this->user->id,
'branch_id' => $this->branch->id,
'shift_id' => $this->shift->id,
'date' => \Carbon\Carbon::now('Asia/Manila')->format('Y-m-d'),
'clock_in' => '09:30:00',
'clock_out' => '17:30:00',
'break_in' => '12:00:00',
'break_out' => '13:00:00',
'total_hours' => 8.00,
'late_hours' => 0.50,
'early_hours' => 0.50,
'break_hours' => 1.00,
'overtime_hours' => 1.50,
'status' => 'present',
'created_by' => $this->user->id,
]);
$response = $this->actingAs($this->user)->getJson('/api/attendance/today');
$response->assertStatus(200)
->assertJsonPath('success', true)
->assertJsonPath('data.total_hours', 8)
->assertJsonPath('data.late_hours', 0.5)
->assertJsonPath('data.early_hours', 0.5)
->assertJsonPath('data.break_hours', 1)
->assertJsonPath('data.overtime_hours', 1.5);
}
}