Skip to content

Commit 6cf8cd7

Browse files
authored
Merge pull request #51 from WINBIGFOX/add-holiday-rule-feature
add: holiday rules feature
2 parents e03e538 + 4a02468 commit 6cf8cd7

25 files changed

+804
-454
lines changed

app/Http/Controllers/AbsenceController.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use App\Http\Requests\StoreAbsenceRequest;
1010
use App\Http\Resources\AbsenceResource;
1111
use App\Models\Absence;
12+
use App\Services\HolidayService;
1213
use App\Services\TimestampService;
1314
use Carbon\Carbon;
1415
use Carbon\CarbonPeriod;
@@ -50,7 +51,7 @@ public function show(Carbon $date)
5051
$absences = Absence::query()->whereBetween('date', [$startDate, $endDate])->get();
5152

5253
$periode = CarbonPeriod::create($startDate, $endDate);
53-
$holidays = TimestampService::getHoliday([$startDate->year, $endDate->year]);
54+
$holidays = HolidayService::getHoliday([$startDate->year, $endDate->year]);
5455
$plans = [];
5556
foreach ($periode as $rangeDate) {
5657
$plans[$rangeDate->format('Y-m-d')] = TimestampService::getPlan($rangeDate);
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Http\Controllers;
6+
7+
use App\Http\Requests\DestroyHolidayRuleRequest;
8+
use App\Http\Requests\StoreHolidayRuleRequest;
9+
use App\Services\HolidayService;
10+
use Carbon\Carbon;
11+
12+
class HolidayRuleController extends Controller
13+
{
14+
/**
15+
* Store a newly created resource in storage.
16+
*/
17+
public function store(StoreHolidayRuleRequest $request): void
18+
{
19+
$date = $request->validated()['date'];
20+
HolidayService::addHoliday(Carbon::create($date));
21+
}
22+
23+
/**
24+
* Remove the specified resource from storage.
25+
*/
26+
public function destroy(DestroyHolidayRuleRequest $request): void
27+
{
28+
$date = $request->validated()['date'];
29+
HolidayService::removeHoliday(Carbon::create($date));
30+
}
31+
}

app/Http/Controllers/Overview/DayController.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use App\Http\Controllers\Controller;
88
use App\Http\Resources\TimestampResource;
9+
use App\Services\HolidayService;
910
use App\Services\TimestampService;
1011
use Carbon\Carbon;
1112
use Inertia\Inertia;
@@ -39,6 +40,7 @@ public function show(Carbon $date)
3940
'dayNoWorkTime' => TimestampService::getNoWorkTime($startDay),
4041
'absences' => TimestampService::getAbsence($startDay),
4142
'date' => $date->format('d.m.Y'),
43+
'isHoliday' => HolidayService::isHoliday($startDay),
4244
]);
4345
}
4446
}

app/Http/Controllers/Overview/WeekController.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use App\Helpers\DateHelper;
88
use App\Http\Controllers\Controller;
99
use App\Http\Resources\AbsenceResource;
10+
use App\Services\HolidayService;
1011
use App\Services\TimestampService;
1112
use Carbon\Carbon;
1213
use Carbon\CarbonPeriod;
@@ -62,6 +63,7 @@ public function show(Carbon $date)
6263
'noWorkTime' => TimestampService::getNoWorkTime($date),
6364
'activeWork' => TimestampService::getActiveWork($date),
6465
'absences' => AbsenceResource::collection(TimestampService::getAbsence($date)),
66+
'isHoliday' => HolidayService::isHoliday($date),
6567
];
6668
})->toArray(),
6769
]);
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Http\Requests;
6+
7+
use Illuminate\Foundation\Http\FormRequest;
8+
9+
class DestroyHolidayRuleRequest extends FormRequest
10+
{
11+
/**
12+
* Determine if the user is authorized to make this request.
13+
*/
14+
public function authorize(): bool
15+
{
16+
return true;
17+
}
18+
19+
/**
20+
* Get the validation rules that apply to the request.
21+
*
22+
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
23+
*/
24+
public function rules(): array
25+
{
26+
return [
27+
'date' => ['required', 'date_format:Y-m-d'],
28+
];
29+
}
30+
}
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Http\Requests;
6+
7+
use Illuminate\Foundation\Http\FormRequest;
8+
9+
class StoreHolidayRuleRequest extends FormRequest
10+
{
11+
/**
12+
* Determine if the user is authorized to make this request.
13+
*/
14+
public function authorize(): bool
15+
{
16+
return true;
17+
}
18+
19+
/**
20+
* Get the validation rules that apply to the request.
21+
*
22+
* @return array<string, \Illuminate\Contracts\Validation\ValidationRule|array<mixed>|string>
23+
*/
24+
public function rules(): array
25+
{
26+
return [
27+
'date' => ['required', 'date_format:Y-m-d'],
28+
];
29+
}
30+
}

app/Models/HolidayRule.php

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Models;
6+
7+
use Illuminate\Database\Eloquent\Model;
8+
9+
class HolidayRule extends Model
10+
{
11+
protected $primaryKey = 'date';
12+
13+
public $incrementing = false;
14+
15+
protected $keyType = 'date';
16+
17+
protected $fillable = [
18+
'date',
19+
'is_holiday',
20+
];
21+
22+
public $timestamps = false;
23+
24+
protected $casts = [
25+
'date' => 'date',
26+
'is_holiday' => 'boolean',
27+
];
28+
}

app/Services/HolidayService.php

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace App\Services;
6+
7+
use App\Jobs\CalculateWeekBalance;
8+
use App\Models\HolidayRule;
9+
use App\Settings\GeneralSettings;
10+
use Carbon\Carbon;
11+
use Illuminate\Support\Collection;
12+
use Umulmrum\Holiday\Constant\HolidayType;
13+
use Umulmrum\Holiday\Filter\IncludeTypeFilter;
14+
use Umulmrum\Holiday\Formatter\DateFormatter;
15+
use Umulmrum\Holiday\HolidayCalculator;
16+
17+
class HolidayService
18+
{
19+
public static function addHoliday(Carbon $date): void
20+
{
21+
$negativeHoliday = HolidayRule::whereDate('date', $date)->where('is_holiday', false)->first();
22+
23+
if ($negativeHoliday) {
24+
$negativeHoliday->delete();
25+
} else {
26+
HolidayRule::updateOrCreate(
27+
['date' => $date],
28+
['is_holiday' => true]
29+
);
30+
}
31+
32+
CalculateWeekBalance::dispatch();
33+
}
34+
35+
public static function removeHoliday(Carbon $date): void
36+
{
37+
$holiday = HolidayRule::whereDate('date', $date)->where('is_holiday', true)->first();
38+
39+
if ($holiday) {
40+
$holiday->delete();
41+
} else {
42+
HolidayRule::updateOrCreate(
43+
['date' => $date],
44+
['is_holiday' => false]
45+
);
46+
}
47+
48+
CalculateWeekBalance::dispatch();
49+
}
50+
51+
private static function mergeHolidays(Collection $dates): Collection
52+
{
53+
$dates = $dates->sort()->unique()->values();
54+
$firstDate = $dates->first();
55+
$lastDate = $dates->last();
56+
57+
$holidays = HolidayRule::whereBetween('date', [$firstDate, $lastDate])->get();
58+
59+
$removeHolidays = $holidays->filter(fn ($holiday): bool => ! $holiday->is_holiday);
60+
61+
$addHolidays = $holidays->filter(fn ($holiday) => $holiday->is_holiday);
62+
63+
$datesToAdd = $addHolidays->pluck('date')->diff($dates);
64+
$datesToRemove = $removeHolidays->pluck('date')->intersect($dates);
65+
$dates = $dates->diff($datesToRemove)->merge($datesToAdd);
66+
67+
return $dates->sort()->unique()->values();
68+
}
69+
70+
public static function getHoliday(int|array $year): Collection
71+
{
72+
$settings = app(GeneralSettings::class);
73+
if ($settings->holidayRegion === null) {
74+
return collect();
75+
}
76+
$holidayCalculator = new HolidayCalculator;
77+
78+
return self::mergeHolidays(collect(
79+
$holidayCalculator->calculate($settings->holidayRegion, $year)
80+
->filter(new IncludeTypeFilter(HolidayType::DAY_OFF))
81+
->format(new DateFormatter)
82+
)->map(fn ($holiday): ?Carbon => Carbon::create($holiday)));
83+
}
84+
85+
public static function isHoliday(Carbon $date): bool
86+
{
87+
return self::getHoliday($date->year)->contains($date);
88+
}
89+
}

app/Services/TimestampService.php

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,6 @@
1919
use Carbon\CarbonPeriod;
2020
use Illuminate\Support\Collection;
2121
use Illuminate\Support\Facades\Cache;
22-
use Umulmrum\Holiday\Constant\HolidayType;
23-
use Umulmrum\Holiday\Filter\IncludeTypeFilter;
24-
use Umulmrum\Holiday\Formatter\DateFormatter;
25-
use Umulmrum\Holiday\HolidayCalculator;
2622

2723
class TimestampService
2824
{
@@ -171,7 +167,7 @@ private static function getTime(TimestampTypeEnum $type, ?Carbon $date, ?Carbon
171167

172168
if (! $project instanceof \App\Models\Project) {
173169

174-
$holiday = self::getHoliday([$date->year, $endDate->year]);
170+
$holiday = HolidayService::getHoliday([$date->year, $endDate->year]);
175171
$absence = self::getAbsence($date, $endDate);
176172

177173
$periode = CarbonPeriod::create($date, $endDate);
@@ -268,21 +264,6 @@ public static function getAbsence(Carbon $date, ?Carbon $endDate = null): Collec
268264
->get();
269265
}
270266

271-
public static function getHoliday(int|array $year): Collection
272-
{
273-
$settings = app(GeneralSettings::class);
274-
if ($settings->holidayRegion === null) {
275-
return collect();
276-
}
277-
$holidayCalculator = new HolidayCalculator;
278-
279-
return collect(
280-
$holidayCalculator->calculate($settings->holidayRegion, $year)
281-
->filter(new IncludeTypeFilter(HolidayType::DAY_OFF))
282-
->format(new DateFormatter)
283-
)->map(fn ($holiday): ?Carbon => Carbon::create($holiday));
284-
}
285-
286267
public static function getWorkSchedule(?Carbon $date = null): array
287268
{
288269
if (! $date instanceof Carbon) {
@@ -374,7 +355,7 @@ public static function getDatesWithTimestamps(?Carbon $date, ?Carbon $endDate =
374355
$timestampDates = self::getTimestamps($date, $endDate, $project)->map(fn (Timestamp $timestamp) => $timestamp->started_at->format('Y-m-d'));
375356

376357
if (! $project instanceof \App\Models\Project) {
377-
$holiday = self::getHoliday(range($date->year, $endDate->year))->map(fn (Carbon $holiday): string => $holiday->format('Y-m-d'));
358+
$holiday = HolidayService::getHoliday(range($date->year, $endDate->year))->map(fn (Carbon $holiday): string => $holiday->format('Y-m-d'));
378359

379360
$absence = self::getAbsence($date, $endDate)->map(fn (Absence $absence) => $absence->date->format('Y-m-d'));
380361

composer.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,9 @@
1414
"emargareten/inertia-modal": "^1.5",
1515
"inertiajs/inertia-laravel": "^2.0",
1616
"laravel-lang/lang": "^15.22",
17-
"laravel/framework": "^12.20",
17+
"laravel/framework": "^12.21",
1818
"laravel/tinker": "^2.10",
19-
"nativephp/electron": "^1.1",
19+
"nativephp/electron": "^1.2",
2020
"nunomaduro/laravel-optimize-database": "^1.0",
2121
"prinsfrank/standards": "^3.12",
2222
"sentry/sentry-laravel": "^4.15",
@@ -32,7 +32,7 @@
3232
"laravel/breeze": "^2.3",
3333
"laravel/pail": "^1.2",
3434
"laravel/pint": "^1.24",
35-
"laravel/sail": "^1.43",
35+
"laravel/sail": "^1.44",
3636
"mockery/mockery": "^1.6",
3737
"nunomaduro/collision": "^8.8",
3838
"pestphp/pest": "^3.8",

0 commit comments

Comments
 (0)