- Add AllocationController with CRUD + bulk endpoints - Add AllocationValidationService for capacity/estimate validation - Add AllocationMatrixService for optimized matrix queries - Add AllocationPolicy for authorization - Add AllocationResource for API responses - Add frontend allocationService and matrix UI - Add E2E tests for allocation matrix (20 tests) - Add unit tests for validation service and policies - Fix month format conversion (YYYY-MM to YYYY-MM-01)
60 lines
1.5 KiB
PHP
60 lines
1.5 KiB
PHP
<?php
|
|
|
|
namespace App\Utilities;
|
|
|
|
use Carbon\Carbon;
|
|
use Carbon\CarbonPeriod;
|
|
|
|
class WorkingDaysCalculator
|
|
{
|
|
public const TIMEZONE = 'America/New_York';
|
|
|
|
public static function calculate(string $month, array $holidays = []): int
|
|
{
|
|
$start = Carbon::createFromFormat('Y-m', $month, self::TIMEZONE)->startOfMonth();
|
|
$end = $start->copy()->endOfMonth();
|
|
|
|
return self::getWorkingDaysInRange($start->toDateString(), $end->toDateString(), $holidays);
|
|
}
|
|
|
|
public static function getWorkingDaysInRange(string $start, string $end, array $holidays = []): int
|
|
{
|
|
$period = CarbonPeriod::create(
|
|
Carbon::create($start, self::TIMEZONE),
|
|
Carbon::create($end, self::TIMEZONE)
|
|
);
|
|
$holidayLookup = array_flip($holidays);
|
|
$workingDays = 0;
|
|
|
|
foreach ($period as $day) {
|
|
$date = $day->toDateString();
|
|
|
|
if (self::isWorkingDay($date, $holidayLookup)) {
|
|
$workingDays++;
|
|
}
|
|
}
|
|
|
|
return $workingDays;
|
|
}
|
|
|
|
public static function isWorkingDay(string $date, array $holidays = []): bool
|
|
{
|
|
$carbonDate = Carbon::create($date, self::TIMEZONE);
|
|
|
|
if ($carbonDate->isWeekend()) {
|
|
return false;
|
|
}
|
|
|
|
if (isset($holidays[$carbonDate->toDateString()])) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
public static function isWeekend(string $date): bool
|
|
{
|
|
return Carbon::create($date, self::TIMEZONE)->isWeekend();
|
|
}
|
|
}
|