'2026-02-11', 'name' => 'Extra Day', 'description' => 'Standalone']); Holiday::create(['date' => '2026-02-25', 'name' => 'Another Day', 'description' => 'Standalone']); $period = CarbonPeriod::create('2026-02-01', '2026-02-28'); $expected = 0; foreach ($period as $day) { if ($day->isWeekend()) { continue; } if (in_array($day->toDateString(), ['2026-02-11', '2026-02-25'], true)) { continue; } $expected++; } $service = app(CapacityService::class); expect($service->calculateWorkingDays('2026-02'))->toBe($expected); }); test('4.1.20 CapacityService applies availability', function () { $role = Role::factory()->create(); $member = TeamMember::factory()->create(['role_id' => $role->id]); TeamMemberAvailability::factory()->forDate('2026-02-03')->availability(0.5)->create(['team_member_id' => $member->id]); TeamMemberAvailability::factory()->forDate('2026-02-04')->availability(0.0)->create(['team_member_id' => $member->id]); $result = app(CapacityService::class)->calculateIndividualCapacity($member->id, '2026-02'); $details = collect($result['details']); expect($details->firstWhere('date', '2026-02-03')['availability'])->toBe(0.5); expect($details->firstWhere('date', '2026-02-04')['availability'])->toBe(0.0); }); test('4.1.21 CapacityService handles PTO', function () { $role = Role::factory()->create(); $member = TeamMember::factory()->create(['role_id' => $role->id]); Pto::create([ 'team_member_id' => $member->id, 'start_date' => '2026-02-10', 'end_date' => '2026-02-12', 'reason' => 'Rest', 'status' => 'approved', ]); $service = app(CapacityService::class); $workingDays = $service->calculateWorkingDays('2026-02'); $result = $service->calculateIndividualCapacity($member->id, '2026-02'); expect($result['person_days'])->toBe((float) ($workingDays - 3)); }); test('4.1.22 CapacityService handles holidays', function () { $role = Role::factory()->create(); $member = TeamMember::factory()->create(['role_id' => $role->id]); Holiday::create(['date' => '2026-02-17', 'name' => 'Presidents Day', 'description' => 'Holiday']); $service = app(CapacityService::class); $result = $service->calculateIndividualCapacity($member->id, '2026-02'); $dates = collect($result['details'])->pluck('date'); expect($dates)->not->toContain('2026-02-17'); }); test('4.1.23 CapacityService calculates revenue', function () { $role = Role::factory()->create(); $memberA = TeamMember::factory()->create(['role_id' => $role->id, 'hourly_rate' => 150]); $memberB = TeamMember::factory()->create(['role_id' => $role->id, 'hourly_rate' => 125]); $service = app(CapacityService::class); $revenue = $service->calculatePossibleRevenue('2026-02'); $hoursA = $service->calculateIndividualCapacity($memberA->id, '2026-02')['hours']; $hoursB = $service->calculateIndividualCapacity($memberB->id, '2026-02')['hours']; expect($revenue)->toBe(round($hoursA * 150 + $hoursB * 125, 2)); }); test('4.1.24 Redis caching for capacity', function () { $role = Role::factory()->create(); $member = TeamMember::factory()->create(['role_id' => $role->id]); $service = app(CapacityService::class); $key = "capacity:2026-02:{$member->id}"; Cache::store('array')->forget($key); $service->calculateIndividualCapacity($member->id, '2026-02'); expect(Cache::store('array')->get($key))->not->toBeNull(); });