diff --git a/app/Domain/Actions/VacationRequest/CreateAction.php b/app/Domain/Actions/VacationRequest/CreateAction.php index d3e0389a..e5a33e32 100644 --- a/app/Domain/Actions/VacationRequest/CreateAction.php +++ b/app/Domain/Actions/VacationRequest/CreateAction.php @@ -52,7 +52,11 @@ protected function createVacationRequest(array $data, User $creator): VacationRe $vacationRequest->save(); - $days = $this->workDaysCalculator->calculateDays($vacationRequest->from, $vacationRequest->to); + $days = $this->workDaysCalculator->calculateDays( + $vacationRequest->from, + $vacationRequest->to, + $vacationRequest->type, + ); foreach ($days as $day) { $vacationRequest->vacations()->create([ diff --git a/app/Domain/Enums/VacationType.php b/app/Domain/Enums/VacationType.php index 0c377f34..0c2082d2 100644 --- a/app/Domain/Enums/VacationType.php +++ b/app/Domain/Enums/VacationType.php @@ -19,6 +19,7 @@ enum VacationType: string case Sick = "sick_vacation"; case Absence = "absence"; case RemoteWork = "remote_work"; + case Delegation = "delegation"; public function label(): string { diff --git a/app/Domain/UnavailableDaysRetriever.php b/app/Domain/UnavailableDaysRetriever.php new file mode 100644 index 00000000..0299e655 --- /dev/null +++ b/app/Domain/UnavailableDaysRetriever.php @@ -0,0 +1,40 @@ +vacations() + ->whereBelongsTo($yearPeriod) + ->whereRelation( + "vacationRequest", + fn(Builder $query): Builder => $query->noStates(VacationRequestStatesRetriever::failedStates()), + ) + ->pluck("date"); + + if (!$vacationType || !$this->configRetriever->isDuringNonWorkDays($vacationType)) { + $unavailableDays->push(...$yearPeriod->weekends()); + $unavailableDays->push(...$yearPeriod->holidays()->pluck("date")); + } + + return $unavailableDays + ->unique() + ->sort() + ->values(); + } +} diff --git a/app/Domain/UserVacationStatsRetriever.php b/app/Domain/UserVacationStatsRetriever.php index 775ed707..117175dc 100644 --- a/app/Domain/UserVacationStatsRetriever.php +++ b/app/Domain/UserVacationStatsRetriever.php @@ -70,6 +70,7 @@ public function getOtherApprovedVacationDays(User $user, YearPeriod $yearPeriod) fn(Builder $query): Builder => $query ->whereIn("type", $this->getNotLimitableVacationTypes()) ->whereNot("type", VacationType::RemoteWork) + ->whereNot("type", VacationType::Delegation) ->states(VacationRequestStatesRetriever::successStates()), ) ->count(); diff --git a/app/Domain/VacationTypeConfigRetriever.php b/app/Domain/VacationTypeConfigRetriever.php index 7865d413..5ee7d0d9 100644 --- a/app/Domain/VacationTypeConfigRetriever.php +++ b/app/Domain/VacationTypeConfigRetriever.php @@ -6,6 +6,7 @@ use Illuminate\Contracts\Config\Repository; use Toby\Domain\Enums\EmploymentForm; +use Toby\Domain\Enums\Role; use Toby\Domain\Enums\VacationType; class VacationTypeConfigRetriever @@ -16,6 +17,8 @@ class VacationTypeConfigRetriever public const KEY_HAS_LIMIT = "has_limit"; public const KEY_AVAILABLE_FOR = "available_for"; public const KEY_IS_VACATION = "is_vacation"; + public const KEY_DURING_NON_WORKDAYS = "during_non_workdays"; + public const KEY_REQUEST_ALLOWED_FOR = "request_allowed_for"; public function __construct( protected Repository $config, @@ -46,11 +49,21 @@ public function isVacation(VacationType $type): bool return $this->getConfigFor($type)[static::KEY_IS_VACATION]; } + public function isDuringNonWorkDays(VacationType $type): bool + { + return $this->getConfigFor($type)[static::KEY_DURING_NON_WORKDAYS]; + } + public function isAvailableFor(VacationType $type, EmploymentForm $employmentForm): bool { return in_array($employmentForm, $this->getConfigFor($type)[static::KEY_AVAILABLE_FOR], true); } + public function isRequestAllowedFor(VacationType $type, Role $role): bool + { + return in_array($role, $this->getConfigFor($type)[static::KEY_REQUEST_ALLOWED_FOR], true); + } + protected function getConfigFor(VacationType $type): array { return $this->config->get("vacation_types.{$type->value}"); diff --git a/app/Domain/Validation/Rules/DoesNotExceedLimitRule.php b/app/Domain/Validation/Rules/DoesNotExceedLimitRule.php index 8ce82b55..a8e2e91f 100644 --- a/app/Domain/Validation/Rules/DoesNotExceedLimitRule.php +++ b/app/Domain/Validation/Rules/DoesNotExceedLimitRule.php @@ -30,7 +30,7 @@ public function check(VacationRequest $vacationRequest): bool $limit = $this->getUserVacationLimit($vacationRequest->user, $vacationRequest->yearPeriod); $vacationDays = $this->getVacationDaysWithLimit($vacationRequest->user, $vacationRequest->yearPeriod); $estimatedDays = $this->workDaysCalculator - ->calculateDays($vacationRequest->from, $vacationRequest->to) + ->calculateDays($vacationRequest->from, $vacationRequest->to, $vacationRequest->type) ->count(); return $limit >= ($vacationDays + $estimatedDays); diff --git a/app/Domain/Validation/Rules/MinimumOneVacationDayRule.php b/app/Domain/Validation/Rules/MinimumOneVacationDayRule.php index 6a38f408..a5d8c1bf 100644 --- a/app/Domain/Validation/Rules/MinimumOneVacationDayRule.php +++ b/app/Domain/Validation/Rules/MinimumOneVacationDayRule.php @@ -16,7 +16,7 @@ public function __construct( public function check(VacationRequest $vacationRequest): bool { return $this->workDaysCalculator - ->calculateDays($vacationRequest->from, $vacationRequest->to) + ->calculateDays($vacationRequest->from, $vacationRequest->to, $vacationRequest->type) ->isNotEmpty(); } diff --git a/app/Domain/WorkDaysCalculator.php b/app/Domain/WorkDaysCalculator.php index 3dd3c5ff..2f77e0e9 100644 --- a/app/Domain/WorkDaysCalculator.php +++ b/app/Domain/WorkDaysCalculator.php @@ -7,11 +7,16 @@ use Carbon\CarbonInterface; use Carbon\CarbonPeriod; use Illuminate\Support\Collection; +use Toby\Domain\Enums\VacationType; use Toby\Eloquent\Models\YearPeriod; class WorkDaysCalculator { - public function calculateDays(CarbonInterface $from, CarbonInterface $to): Collection + public function __construct( + protected VacationTypeConfigRetriever $configRetriever, + ) {} + + public function calculateDays(CarbonInterface $from, CarbonInterface $to, ?VacationType $vacationType = null): Collection { $period = CarbonPeriod::create($from, $to); $yearPeriod = YearPeriod::findByYear($from->year); @@ -20,7 +25,7 @@ public function calculateDays(CarbonInterface $from, CarbonInterface $to): Colle $validDays = new Collection(); foreach ($period as $day) { - if ($this->passes($day, $holidays)) { + if ($this->passes($day, $holidays, $vacationType)) { $validDays->add($day); } } @@ -28,8 +33,12 @@ public function calculateDays(CarbonInterface $from, CarbonInterface $to): Colle return $validDays; } - protected function passes(CarbonInterface $day, Collection $holidays): bool + protected function passes(CarbonInterface $day, Collection $holidays, ?VacationType $vacationType = null): bool { + if ($vacationType && $this->configRetriever->isDuringNonWorkDays($vacationType)) { + return true; + } + if ($day->isWeekend()) { return false; } diff --git a/app/Eloquent/Models/Vacation.php b/app/Eloquent/Models/Vacation.php index 2dd50181..c2823201 100644 --- a/app/Eloquent/Models/Vacation.php +++ b/app/Eloquent/Models/Vacation.php @@ -4,6 +4,7 @@ namespace Toby\Eloquent\Models; +use Database\Factories\VacationFactory; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; @@ -68,4 +69,9 @@ public function scopeWhereTypes(Builder $query, Collection $types): Builder fn(Builder $query): Builder => $query->whereIn("type", $types), ); } + + protected static function newFactory(): VacationFactory + { + return VacationFactory::new(); + } } diff --git a/app/Eloquent/Models/YearPeriod.php b/app/Eloquent/Models/YearPeriod.php index 7976fca8..386a28c3 100644 --- a/app/Eloquent/Models/YearPeriod.php +++ b/app/Eloquent/Models/YearPeriod.php @@ -52,6 +52,24 @@ public function holidays(): HasMany return $this->hasMany(Holiday::class); } + public function weekends(): Collection + { + $start = Carbon::create($this->year); + $end = Carbon::create($this->year)->endOfYear(); + + $weekends = new Collection(); + + while ($start->lessThanOrEqualTo($end)) { + if ($start->isWeekend()) { + $weekends->push($start->copy()); + } + + $start->addDay(); + } + + return $weekends; + } + protected static function newFactory(): YearPeriodFactory { return YearPeriodFactory::new(); diff --git a/app/Infrastructure/Http/Controllers/Api/CalculateUserUnavailableDaysController.php b/app/Infrastructure/Http/Controllers/Api/CalculateUserUnavailableDaysController.php index 5e4afe52..1da7bc2e 100644 --- a/app/Infrastructure/Http/Controllers/Api/CalculateUserUnavailableDaysController.php +++ b/app/Infrastructure/Http/Controllers/Api/CalculateUserUnavailableDaysController.php @@ -4,11 +4,10 @@ namespace Toby\Infrastructure\Http\Controllers\Api; -use Illuminate\Database\Eloquent\Builder; use Illuminate\Http\JsonResponse; use Illuminate\Support\Carbon; +use Toby\Domain\UnavailableDaysRetriever; use Toby\Domain\UserVacationStatsRetriever; -use Toby\Domain\VacationRequestStatesRetriever; use Toby\Eloquent\Helpers\YearPeriodRetriever; use Toby\Eloquent\Models\User; use Toby\Infrastructure\Http\Controllers\Controller; @@ -20,23 +19,16 @@ public function __invoke( CalculateUserUnavailableDaysRequest $request, UserVacationStatsRetriever $vacationStatsRetriever, YearPeriodRetriever $yearPeriodRetriever, + UnavailableDaysRetriever $unavailableDaysRetriever, ): JsonResponse { /** @var User $user */ $user = User::query()->find($request->get("user")); $yearPeriod = $yearPeriodRetriever->selected(); - $holidays = $yearPeriod->holidays()->pluck("date"); - $vacationDays = $user->vacations() - ->whereBelongsTo($yearPeriod) - ->whereRelation( - "vacationRequest", - fn(Builder $query): Builder => $query->noStates(VacationRequestStatesRetriever::failedStates()), - ) - ->pluck("date"); + $unavailableDays = $unavailableDaysRetriever->getUnavailableDays($user, $yearPeriod, $request->vacationType()) + ->map(fn(Carbon $date): string => $date->toDateString()) + ->toArray(); - return new JsonResponse([ - ...$holidays->map(fn(Carbon $date): string => $date->toDateString()), - ...$vacationDays->map(fn(Carbon $date): string => $date->toDateString()), - ]); + return new JsonResponse($unavailableDays); } } diff --git a/app/Infrastructure/Http/Controllers/Api/CalculateVacationDaysController.php b/app/Infrastructure/Http/Controllers/Api/CalculateVacationDaysController.php index be7348c8..9d84a1fd 100644 --- a/app/Infrastructure/Http/Controllers/Api/CalculateVacationDaysController.php +++ b/app/Infrastructure/Http/Controllers/Api/CalculateVacationDaysController.php @@ -14,7 +14,7 @@ class CalculateVacationDaysController extends Controller { public function __invoke(CalculateVacationDaysRequest $request, WorkDaysCalculator $calculator): JsonResponse { - $days = $calculator->calculateDays($request->from(), $request->to()); + $days = $calculator->calculateDays($request->from(), $request->to(), $request->vacationType()); return new JsonResponse($days->map(fn(Carbon $day): string => $day->toDateString())->all()); } diff --git a/app/Infrastructure/Http/Controllers/Api/GetAvailableVacationTypesController.php b/app/Infrastructure/Http/Controllers/Api/GetAvailableVacationTypesController.php index 48a92a2a..95699f4d 100644 --- a/app/Infrastructure/Http/Controllers/Api/GetAvailableVacationTypesController.php +++ b/app/Infrastructure/Http/Controllers/Api/GetAvailableVacationTypesController.php @@ -22,6 +22,7 @@ public function __invoke( $types = VacationType::all() ->filter(fn(VacationType $type): bool => $configRetriever->isAvailableFor($type, $user->profile->employment_form)) + ->filter(fn(VacationType $type): bool => $configRetriever->isRequestAllowedFor($type, $request->user()->role)) ->map(fn(VacationType $type): array => [ "label" => $type->label(), "value" => $type->value, diff --git a/app/Infrastructure/Http/Requests/Api/CalculateUserUnavailableDaysRequest.php b/app/Infrastructure/Http/Requests/Api/CalculateUserUnavailableDaysRequest.php index 03a6c9cd..dfcfdf8c 100644 --- a/app/Infrastructure/Http/Requests/Api/CalculateUserUnavailableDaysRequest.php +++ b/app/Infrastructure/Http/Requests/Api/CalculateUserUnavailableDaysRequest.php @@ -5,13 +5,23 @@ namespace Toby\Infrastructure\Http\Requests\Api; use Illuminate\Foundation\Http\FormRequest; +use Illuminate\Validation\Rules\Enum; +use Toby\Domain\Enums\VacationType; class CalculateUserUnavailableDaysRequest extends FormRequest { public function rules(): array { return [ + "vacationType" => [new Enum(VacationType::class)], "user" => ["required", "exists:users,id"], ]; } + + public function vacationType(): ?VacationType + { + return $this->request->has("vacationType") + ? VacationType::from($this->request->get("vacationType")) + : null; + } } diff --git a/app/Infrastructure/Http/Requests/Api/CalculateVacationDaysRequest.php b/app/Infrastructure/Http/Requests/Api/CalculateVacationDaysRequest.php index 72e37dea..94ded88b 100644 --- a/app/Infrastructure/Http/Requests/Api/CalculateVacationDaysRequest.php +++ b/app/Infrastructure/Http/Requests/Api/CalculateVacationDaysRequest.php @@ -6,6 +6,8 @@ use Illuminate\Foundation\Http\FormRequest; use Illuminate\Support\Carbon; +use Illuminate\Validation\Rules\Enum; +use Toby\Domain\Enums\VacationType; use Toby\Eloquent\Models\YearPeriod; use Toby\Infrastructure\Http\Rules\YearPeriodExists; @@ -14,11 +16,17 @@ class CalculateVacationDaysRequest extends FormRequest public function rules(): array { return [ + "vacationType" => ["required", new Enum(VacationType::class)], "from" => ["required", "date_format:Y-m-d", new YearPeriodExists()], "to" => ["required", "date_format:Y-m-d", new YearPeriodExists()], ]; } + public function vacationType(): VacationType + { + return VacationType::from($this->request->get("vacationType")); + } + public function from(): Carbon { return Carbon::create($this->request->get("from")); diff --git a/config/vacation_types.php b/config/vacation_types.php index fbd62d46..76f955a6 100644 --- a/config/vacation_types.php +++ b/config/vacation_types.php @@ -3,6 +3,7 @@ declare(strict_types=1); use Toby\Domain\Enums\EmploymentForm; +use Toby\Domain\Enums\Role; use Toby\Domain\Enums\VacationType; use Toby\Domain\VacationTypeConfigRetriever; @@ -15,7 +16,14 @@ VacationTypeConfigRetriever::KEY_AVAILABLE_FOR => [ EmploymentForm::EmploymentContract, ], + VacationTypeConfigRetriever::KEY_REQUEST_ALLOWED_FOR => [ + Role::Employee, + Role::Administrator, + Role::AdministrativeApprover, + Role::TechnicalApprover, + ], VacationTypeConfigRetriever::KEY_IS_VACATION => true, + VacationTypeConfigRetriever::KEY_DURING_NON_WORKDAYS => false, ], VacationType::OnRequest->value => [ VacationTypeConfigRetriever::KEY_TECHNICAL_APPROVAL => true, @@ -25,7 +33,14 @@ VacationTypeConfigRetriever::KEY_AVAILABLE_FOR => [ EmploymentForm::EmploymentContract, ], + VacationTypeConfigRetriever::KEY_REQUEST_ALLOWED_FOR => [ + Role::Employee, + Role::Administrator, + Role::AdministrativeApprover, + Role::TechnicalApprover, + ], VacationTypeConfigRetriever::KEY_IS_VACATION => true, + VacationTypeConfigRetriever::KEY_DURING_NON_WORKDAYS => false, ], VacationType::TimeInLieu->value => [ VacationTypeConfigRetriever::KEY_TECHNICAL_APPROVAL => false, @@ -35,7 +50,14 @@ VacationTypeConfigRetriever::KEY_AVAILABLE_FOR => [ EmploymentForm::EmploymentContract, ], + VacationTypeConfigRetriever::KEY_REQUEST_ALLOWED_FOR => [ + Role::Employee, + Role::Administrator, + Role::AdministrativeApprover, + Role::TechnicalApprover, + ], VacationTypeConfigRetriever::KEY_IS_VACATION => true, + VacationTypeConfigRetriever::KEY_DURING_NON_WORKDAYS => false, ], VacationType::Sick->value => [ VacationTypeConfigRetriever::KEY_TECHNICAL_APPROVAL => false, @@ -45,7 +67,14 @@ VacationTypeConfigRetriever::KEY_AVAILABLE_FOR => [ EmploymentForm::EmploymentContract, ], + VacationTypeConfigRetriever::KEY_REQUEST_ALLOWED_FOR => [ + Role::Employee, + Role::Administrator, + Role::AdministrativeApprover, + Role::TechnicalApprover, + ], VacationTypeConfigRetriever::KEY_IS_VACATION => true, + VacationTypeConfigRetriever::KEY_DURING_NON_WORKDAYS => false, ], VacationType::Unpaid->value => [ VacationTypeConfigRetriever::KEY_TECHNICAL_APPROVAL => true, @@ -55,7 +84,14 @@ VacationTypeConfigRetriever::KEY_AVAILABLE_FOR => [ EmploymentForm::EmploymentContract, ], + VacationTypeConfigRetriever::KEY_REQUEST_ALLOWED_FOR => [ + Role::Employee, + Role::Administrator, + Role::AdministrativeApprover, + Role::TechnicalApprover, + ], VacationTypeConfigRetriever::KEY_IS_VACATION => true, + VacationTypeConfigRetriever::KEY_DURING_NON_WORKDAYS => false, ], VacationType::Special->value => [ VacationTypeConfigRetriever::KEY_TECHNICAL_APPROVAL => true, @@ -65,7 +101,14 @@ VacationTypeConfigRetriever::KEY_AVAILABLE_FOR => [ EmploymentForm::EmploymentContract, ], + VacationTypeConfigRetriever::KEY_REQUEST_ALLOWED_FOR => [ + Role::Employee, + Role::Administrator, + Role::AdministrativeApprover, + Role::TechnicalApprover, + ], VacationTypeConfigRetriever::KEY_IS_VACATION => true, + VacationTypeConfigRetriever::KEY_DURING_NON_WORKDAYS => false, ], VacationType::Childcare->value => [ VacationTypeConfigRetriever::KEY_TECHNICAL_APPROVAL => true, @@ -75,7 +118,14 @@ VacationTypeConfigRetriever::KEY_AVAILABLE_FOR => [ EmploymentForm::EmploymentContract, ], + VacationTypeConfigRetriever::KEY_REQUEST_ALLOWED_FOR => [ + Role::Employee, + Role::Administrator, + Role::AdministrativeApprover, + Role::TechnicalApprover, + ], VacationTypeConfigRetriever::KEY_IS_VACATION => true, + VacationTypeConfigRetriever::KEY_DURING_NON_WORKDAYS => false, ], VacationType::Training->value => [ VacationTypeConfigRetriever::KEY_TECHNICAL_APPROVAL => true, @@ -85,7 +135,14 @@ VacationTypeConfigRetriever::KEY_AVAILABLE_FOR => [ EmploymentForm::EmploymentContract, ], + VacationTypeConfigRetriever::KEY_REQUEST_ALLOWED_FOR => [ + Role::Employee, + Role::Administrator, + Role::AdministrativeApprover, + Role::TechnicalApprover, + ], VacationTypeConfigRetriever::KEY_IS_VACATION => true, + VacationTypeConfigRetriever::KEY_DURING_NON_WORKDAYS => false, ], VacationTypeConfigRetriever::KEY_IS_VACATION => true, VacationType::Volunteering->value => [ @@ -96,7 +153,14 @@ VacationTypeConfigRetriever::KEY_AVAILABLE_FOR => [ EmploymentForm::EmploymentContract, ], + VacationTypeConfigRetriever::KEY_REQUEST_ALLOWED_FOR => [ + Role::Employee, + Role::Administrator, + Role::AdministrativeApprover, + Role::TechnicalApprover, + ], VacationTypeConfigRetriever::KEY_IS_VACATION => true, + VacationTypeConfigRetriever::KEY_DURING_NON_WORKDAYS => false, ], VacationType::Volunteering->value => [ VacationTypeConfigRetriever::KEY_TECHNICAL_APPROVAL => true, @@ -106,7 +170,14 @@ VacationTypeConfigRetriever::KEY_AVAILABLE_FOR => [ EmploymentForm::EmploymentContract, ], + VacationTypeConfigRetriever::KEY_REQUEST_ALLOWED_FOR => [ + Role::Employee, + Role::Administrator, + Role::AdministrativeApprover, + Role::TechnicalApprover, + ], VacationTypeConfigRetriever::KEY_IS_VACATION => true, + VacationTypeConfigRetriever::KEY_DURING_NON_WORKDAYS => false, ], VacationType::Absence->value => [ VacationTypeConfigRetriever::KEY_TECHNICAL_APPROVAL => false, @@ -118,7 +189,14 @@ EmploymentForm::B2bContract, EmploymentForm::BoardMemberContract, ], + VacationTypeConfigRetriever::KEY_REQUEST_ALLOWED_FOR => [ + Role::Employee, + Role::Administrator, + Role::AdministrativeApprover, + Role::TechnicalApprover, + ], VacationTypeConfigRetriever::KEY_IS_VACATION => true, + VacationTypeConfigRetriever::KEY_DURING_NON_WORKDAYS => false, ], VacationType::RemoteWork->value => [ VacationTypeConfigRetriever::KEY_TECHNICAL_APPROVAL => false, @@ -131,6 +209,31 @@ EmploymentForm::B2bContract, EmploymentForm::BoardMemberContract, ], + VacationTypeConfigRetriever::KEY_REQUEST_ALLOWED_FOR => [ + Role::Employee, + Role::Administrator, + Role::AdministrativeApprover, + Role::TechnicalApprover, + ], + VacationTypeConfigRetriever::KEY_IS_VACATION => false, + VacationTypeConfigRetriever::KEY_DURING_NON_WORKDAYS => false, + ], + VacationType::Delegation->value => [ + VacationTypeConfigRetriever::KEY_TECHNICAL_APPROVAL => false, + VacationTypeConfigRetriever::KEY_ADMINISTRATIVE_APPROVAL => false, + VacationTypeConfigRetriever::KEY_BILLABLE => true, + VacationTypeConfigRetriever::KEY_HAS_LIMIT => false, + VacationTypeConfigRetriever::KEY_AVAILABLE_FOR => [ + EmploymentForm::EmploymentContract, + EmploymentForm::CommissionContract, + EmploymentForm::B2bContract, + EmploymentForm::BoardMemberContract, + ], + VacationTypeConfigRetriever::KEY_REQUEST_ALLOWED_FOR => [ + Role::Administrator, + Role::AdministrativeApprover, + ], VacationTypeConfigRetriever::KEY_IS_VACATION => false, + VacationTypeConfigRetriever::KEY_DURING_NON_WORKDAYS => true, ], ]; diff --git a/database/factories/VacationFactory.php b/database/factories/VacationFactory.php index d70c43d5..5afc97fb 100644 --- a/database/factories/VacationFactory.php +++ b/database/factories/VacationFactory.php @@ -4,12 +4,24 @@ namespace Database\Factories; +use Carbon\CarbonImmutable; use Illuminate\Database\Eloquent\Factories\Factory; +use Toby\Eloquent\Models\User; +use Toby\Eloquent\Models\Vacation; +use Toby\Eloquent\Models\VacationRequest; +use Toby\Eloquent\Models\YearPeriod; class VacationFactory extends Factory { + protected $model = Vacation::class; + public function definition(): array { - return []; + return [ + "user_id" => User::factory(), + "vacation_request_id" => VacationRequest::factory(), + "year_period_id" => YearPeriod::factory(), + "date" => CarbonImmutable::create($this->faker->dateTimeThisYear), + ]; } } diff --git a/database/seeders/DatabaseSeeder.php b/database/seeders/DatabaseSeeder.php index 27618cf6..96404664 100644 --- a/database/seeders/DatabaseSeeder.php +++ b/database/seeders/DatabaseSeeder.php @@ -77,6 +77,7 @@ public function run(): void $days = app(WorkDaysCalculator::class)->calculateDays( $vacationRequest->from, $vacationRequest->to, + $vacationRequest->type, ); foreach ($days as $day) { diff --git a/database/seeders/DemoSeeder.php b/database/seeders/DemoSeeder.php index f9bc4c02..7e8cb0c7 100644 --- a/database/seeders/DemoSeeder.php +++ b/database/seeders/DemoSeeder.php @@ -174,6 +174,7 @@ public function run(): void $days = app(WorkDaysCalculator::class)->calculateDays( $vacationRequest->from, $vacationRequest->to, + $vacationRequest->type, ); foreach ($days as $day) { @@ -243,6 +244,7 @@ public function run(): void $days = app(WorkDaysCalculator::class)->calculateDays( $vacationRequest->from, $vacationRequest->to, + $vacationRequest->type, ); foreach ($days as $day) { @@ -301,6 +303,7 @@ public function run(): void $days = app(WorkDaysCalculator::class)->calculateDays( $vacationRequest->from, $vacationRequest->to, + $vacationRequest->type, ); foreach ($days as $day) { diff --git a/lang/pl.json b/lang/pl.json index 6e76379f..9011d187 100644 --- a/lang/pl.json +++ b/lang/pl.json @@ -16,6 +16,7 @@ "sick_vacation": "Zwolnienie lekarskie", "absence": "Nieobecność", "remote_work": "Praca zdalna", + "delegation": "Delegacja", "employee": "Pracownik", "administrator": "Administrator", "technical_approver": "Techniczny akceptujący", diff --git a/resources/js/Composables/vacationTypeInfo.js b/resources/js/Composables/vacationTypeInfo.js index 2d643262..d2b90635 100644 --- a/resources/js/Composables/vacationTypeInfo.js +++ b/resources/js/Composables/vacationTypeInfo.js @@ -10,6 +10,7 @@ import MedicalBagIcon from 'vue-material-design-icons/MedicalBag.vue' import CalendarRemoveIcon from 'vue-material-design-icons/CalendarRemove.vue' import HomeCityIcon from 'vue-material-design-icons/HomeCity.vue' import PlusIcon from 'vue-material-design-icons/Plus.vue' +import PlaneTrainIcon from 'vue-material-design-icons/PlaneTrain.vue' const types = [ { @@ -89,6 +90,13 @@ const types = [ color: 'text-lime-500', border: 'border-lime-500', }, + { + text: 'Delegacja', + value: 'delegation', + icon: PlaneTrainIcon, + color: 'text-sky-500', + border: 'border-sky-500', + }, { text: 'Dodaj wniosek', value: 'create', diff --git a/resources/js/Pages/VacationRequest/Create.vue b/resources/js/Pages/VacationRequest/Create.vue index 8e57bd14..7a9c8271 100644 --- a/resources/js/Pages/VacationRequest/Create.vue +++ b/resources/js/Pages/VacationRequest/Create.vue @@ -36,7 +36,7 @@ watch(form, formData => { isDirty.value = formData.isDirty || from !== null || to !== null }, { immediate: true, deep: true }) -refreshEstimatedDays(form.from, form.to) +refreshEstimatedDays(form.from, form.to, form.vacationType) const estimatedDays = ref([]) const vacationTypes = ref([]) @@ -49,18 +49,14 @@ const stats = ref({ const { minDate, maxDate } = useCurrentYearPeriodInfo() -const weekends = date => (date.getDay() === 0 || date.getDay() === 6) - const fromInputConfig = reactive({ minDate, maxDate, - disable: [weekends], }) const toInputConfig = reactive({ minDate, maxDate, - disable: [weekends], }) watch(() => form.user, user => { @@ -70,6 +66,11 @@ watch(() => form.user, user => { refreshVacationStats(user) }, { immediate: true }) +watch(() => form.vacationType, vacationType => { + refreshEstimatedDays(form.from, form.to, vacationType) + refreshUnavailableDays(form.user, vacationType) +}) + function createForm() { form .transform(data => ({ @@ -87,7 +88,7 @@ function onFromChange(selectedDates, dateStr) { return } - refreshEstimatedDays(form.from, form.to) + refreshEstimatedDays(form.from, form.to, form.vacationType) } function onToChange(selectedDates, dateStr) { @@ -96,7 +97,7 @@ function onToChange(selectedDates, dateStr) { return } - refreshEstimatedDays(form.from, form.to) + refreshEstimatedDays(form.from, form.to, form.vacationType) } function resetForm() { @@ -106,12 +107,15 @@ function resetForm() { } function checkUserId(userId) { - return userId > 0 ? userId: null + return userId > 0 ? userId : null } -async function refreshEstimatedDays(from, to) { - if (from && to) { - const res = await axios.post('/api/vacation/calculate-days', { from, to }) +async function refreshEstimatedDays(from, to, vacationType) { + if (from && to && vacationType) { + const res = await axios.post( + '/api/vacation/calculate-days', + { vacationType: vacationType.value, from: from, to: to }, + ) estimatedDays.value = res.data } @@ -124,18 +128,15 @@ async function refreshVacationStats(user) { } async function refreshUnavailableDays(user) { - const res = await axios.post('/api/vacation/calculate-unavailable-days', { user: user.id }) + const res = await axios.post( + '/api/vacation/calculate-unavailable-days', + { user: user.id, vacationType: form.vacationType?.value }, + ) const unavailableDays = res.data - fromInputConfig.disable = [ - weekends, - ...unavailableDays, - ] + fromInputConfig.disable = unavailableDays - toInputConfig.disable = [ - weekends, - ...unavailableDays, - ] + toInputConfig.disable = unavailableDays } async function refreshAvailableTypes(user) { @@ -150,7 +151,9 @@ async function refreshAvailableTypes(user) {