Merge branch 'main' into #43-vacation-summary-for-employee
# Conflicts: # app/Infrastructure/Http/Controllers/HolidayController.php # app/Infrastructure/Http/Controllers/VacationLimitController.php # app/Infrastructure/Http/Controllers/VacationRequestController.php # composer.lock # resources/js/Pages/Holidays/Index.vue # resources/js/Pages/VacationRequest/Create.vue
This commit is contained in:
		@@ -5,9 +5,9 @@ declare(strict_types=1);
 | 
			
		||||
namespace Toby\Domain;
 | 
			
		||||
 | 
			
		||||
use Carbon\CarbonPeriod;
 | 
			
		||||
use Illuminate\Database\Eloquent\Builder;
 | 
			
		||||
use Illuminate\Support\Carbon;
 | 
			
		||||
use Illuminate\Support\Collection;
 | 
			
		||||
use Toby\Domain\Enums\VacationRequestState;
 | 
			
		||||
use Toby\Eloquent\Helpers\YearPeriodRetriever;
 | 
			
		||||
use Toby\Eloquent\Models\Vacation;
 | 
			
		||||
use Toby\Eloquent\Models\YearPeriod;
 | 
			
		||||
@@ -54,7 +54,7 @@ class CalendarGenerator
 | 
			
		||||
    {
 | 
			
		||||
        return Vacation::query()
 | 
			
		||||
            ->whereBetween("date", [$period->start, $period->end])
 | 
			
		||||
            ->whereRelation("vacationRequest", "state", VacationRequestState::Approved->value)
 | 
			
		||||
            ->whereRelation("vacationRequest", fn(Builder $query) => $query->states(VacationRequestStatesRetriever::successStates()))
 | 
			
		||||
            ->get()
 | 
			
		||||
            ->groupBy(fn(Vacation $vacation) => $vacation->date->toDateString());
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -1,56 +0,0 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Toby\Domain\Enums;
 | 
			
		||||
 | 
			
		||||
enum VacationRequestState: string
 | 
			
		||||
{
 | 
			
		||||
    case Created = "created";
 | 
			
		||||
    case Cancelled = "cancelled";
 | 
			
		||||
    case Rejected = "rejected";
 | 
			
		||||
    case Approved = "approved";
 | 
			
		||||
    case WaitingForTechnical = "waiting_for_technical";
 | 
			
		||||
    case WaitingForAdministrative = "waiting_for_administrative";
 | 
			
		||||
    case AcceptedByTechnical = "accepted_by_technical";
 | 
			
		||||
    case AcceptedByAdministrative = "accepted_by_administrative";
 | 
			
		||||
 | 
			
		||||
    public function label(): string
 | 
			
		||||
    {
 | 
			
		||||
        return __($this->value);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function pendingStates(): array
 | 
			
		||||
    {
 | 
			
		||||
        return [
 | 
			
		||||
            self::Created,
 | 
			
		||||
            self::WaitingForTechnical,
 | 
			
		||||
            self::WaitingForAdministrative,
 | 
			
		||||
            self::AcceptedByTechnical,
 | 
			
		||||
            self::AcceptedByAdministrative,
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function successStates(): array
 | 
			
		||||
    {
 | 
			
		||||
        return [self::Approved];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function failedStates(): array
 | 
			
		||||
    {
 | 
			
		||||
        return [
 | 
			
		||||
            self::Rejected,
 | 
			
		||||
            self::Cancelled,
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function filterByStatus(string $filter): array
 | 
			
		||||
    {
 | 
			
		||||
        return match ($filter) {
 | 
			
		||||
            "pending" => VacationRequestState::pendingStates(),
 | 
			
		||||
            "success" => VacationRequestState::successStates(),
 | 
			
		||||
            "failed" => VacationRequestState::failedStates(),
 | 
			
		||||
            default => VacationRequestState::cases(),
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -6,7 +6,7 @@ namespace Toby\Domain\Events;
 | 
			
		||||
 | 
			
		||||
use Illuminate\Foundation\Events\Dispatchable;
 | 
			
		||||
use Illuminate\Queue\SerializesModels;
 | 
			
		||||
use Toby\Domain\Enums\VacationRequestState;
 | 
			
		||||
use Toby\Domain\States\VacationRequest\VacationRequestState;
 | 
			
		||||
use Toby\Eloquent\Models\User;
 | 
			
		||||
use Toby\Eloquent\Models\VacationRequest;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										51
									
								
								app/Domain/Policies/VacationRequestPolicy.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								app/Domain/Policies/VacationRequestPolicy.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,51 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Toby\Domain\Policies;
 | 
			
		||||
 | 
			
		||||
use Toby\Domain\Enums\Role;
 | 
			
		||||
use Toby\Eloquent\Models\User;
 | 
			
		||||
use Toby\Eloquent\Models\VacationRequest;
 | 
			
		||||
 | 
			
		||||
class VacationRequestPolicy
 | 
			
		||||
{
 | 
			
		||||
    public function createOnBehalfOfEmployee(User $user): bool
 | 
			
		||||
    {
 | 
			
		||||
        return $user->role === Role::AdministrativeApprover;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function acceptAsAdminApprover(User $user): bool
 | 
			
		||||
    {
 | 
			
		||||
        return $user->role === Role::AdministrativeApprover;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function acceptAsTechApprover(User $user): bool
 | 
			
		||||
    {
 | 
			
		||||
        return $user->role === Role::TechnicalApprover;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function skipFlow(User $user): bool
 | 
			
		||||
    {
 | 
			
		||||
        return $user->role === Role::AdministrativeApprover;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function reject(User $user): bool
 | 
			
		||||
    {
 | 
			
		||||
        return in_array($user->role, [Role::AdministrativeApprover, Role::TechnicalApprover], true);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function cancel(User $user): bool
 | 
			
		||||
    {
 | 
			
		||||
        return $user->role === Role::AdministrativeApprover;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function show(User $user, VacationRequest $vacationRequest): bool
 | 
			
		||||
    {
 | 
			
		||||
        if ($vacationRequest->user->is($user)) {
 | 
			
		||||
            return true;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return in_array($user->role, [Role::TechnicalApprover, Role::AdministrativeApprover], true);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,10 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Toby\Domain\States\VacationRequest;
 | 
			
		||||
 | 
			
		||||
class AcceptedByAdministrative extends VacationRequestState
 | 
			
		||||
{
 | 
			
		||||
    public static string $name = "accepted_by_administrative";
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										10
									
								
								app/Domain/States/VacationRequest/AcceptedByTechnical.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								app/Domain/States/VacationRequest/AcceptedByTechnical.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Toby\Domain\States\VacationRequest;
 | 
			
		||||
 | 
			
		||||
class AcceptedByTechnical extends VacationRequestState
 | 
			
		||||
{
 | 
			
		||||
    public static string $name = "accepted_by_technical";
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										10
									
								
								app/Domain/States/VacationRequest/Approved.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								app/Domain/States/VacationRequest/Approved.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Toby\Domain\States\VacationRequest;
 | 
			
		||||
 | 
			
		||||
class Approved extends VacationRequestState
 | 
			
		||||
{
 | 
			
		||||
    public static string $name = "approved";
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										10
									
								
								app/Domain/States/VacationRequest/Cancelled.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								app/Domain/States/VacationRequest/Cancelled.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Toby\Domain\States\VacationRequest;
 | 
			
		||||
 | 
			
		||||
class Cancelled extends VacationRequestState
 | 
			
		||||
{
 | 
			
		||||
    public static string $name = "cancelled";
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										10
									
								
								app/Domain/States/VacationRequest/Created.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								app/Domain/States/VacationRequest/Created.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Toby\Domain\States\VacationRequest;
 | 
			
		||||
 | 
			
		||||
class Created extends VacationRequestState
 | 
			
		||||
{
 | 
			
		||||
    public static string $name = "created";
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										10
									
								
								app/Domain/States/VacationRequest/Rejected.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								app/Domain/States/VacationRequest/Rejected.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Toby\Domain\States\VacationRequest;
 | 
			
		||||
 | 
			
		||||
class Rejected extends VacationRequestState
 | 
			
		||||
{
 | 
			
		||||
    public static string $name = "rejected";
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										39
									
								
								app/Domain/States/VacationRequest/VacationRequestState.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								app/Domain/States/VacationRequest/VacationRequestState.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,39 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Toby\Domain\States\VacationRequest;
 | 
			
		||||
 | 
			
		||||
use Spatie\ModelStates\Exceptions\InvalidConfig;
 | 
			
		||||
use Spatie\ModelStates\State;
 | 
			
		||||
use Spatie\ModelStates\StateConfig;
 | 
			
		||||
 | 
			
		||||
abstract class VacationRequestState extends State
 | 
			
		||||
{
 | 
			
		||||
    /**
 | 
			
		||||
     * @throws InvalidConfig
 | 
			
		||||
     */
 | 
			
		||||
    public static function config(): StateConfig
 | 
			
		||||
    {
 | 
			
		||||
        return parent::config()
 | 
			
		||||
            ->default(Created::class)
 | 
			
		||||
            ->allowTransition(Created::class, Approved::class)
 | 
			
		||||
            ->allowTransition(Created::class, WaitingForTechnical::class)
 | 
			
		||||
            ->allowTransition(Created::class, WaitingForAdministrative::class)
 | 
			
		||||
            ->allowTransition(WaitingForTechnical::class, Rejected::class)
 | 
			
		||||
            ->allowTransition(WaitingForTechnical::class, AcceptedByTechnical::class)
 | 
			
		||||
            ->allowTransition(WaitingForAdministrative::class, Rejected::class)
 | 
			
		||||
            ->allowTransition(WaitingForAdministrative::class, AcceptedByAdministrative::class)
 | 
			
		||||
            ->allowTransition(AcceptedByTechnical::class, WaitingForAdministrative::class)
 | 
			
		||||
            ->allowTransition(AcceptedByTechnical::class, Approved::class)
 | 
			
		||||
            ->allowTransition(AcceptedByAdministrative::class, Approved::class)
 | 
			
		||||
            ->allowTransition([
 | 
			
		||||
                Created::class,
 | 
			
		||||
                WaitingForTechnical::class,
 | 
			
		||||
                WaitingForAdministrative::class,
 | 
			
		||||
                AcceptedByTechnical::class,
 | 
			
		||||
                AcceptedByAdministrative::class,
 | 
			
		||||
                Approved::class,
 | 
			
		||||
            ], Cancelled::class);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,10 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Toby\Domain\States\VacationRequest;
 | 
			
		||||
 | 
			
		||||
class WaitingForAdministrative extends VacationRequestState
 | 
			
		||||
{
 | 
			
		||||
    public static string $name = "waiting_for_administrative";
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										10
									
								
								app/Domain/States/VacationRequest/WaitingForTechnical.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								app/Domain/States/VacationRequest/WaitingForTechnical.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,10 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Toby\Domain\States\VacationRequest;
 | 
			
		||||
 | 
			
		||||
class WaitingForTechnical extends VacationRequestState
 | 
			
		||||
{
 | 
			
		||||
    public static string $name = "waiting_for_technical";
 | 
			
		||||
}
 | 
			
		||||
@@ -6,7 +6,6 @@ namespace Toby\Domain;
 | 
			
		||||
 | 
			
		||||
use Illuminate\Database\Eloquent\Builder;
 | 
			
		||||
use Illuminate\Database\Eloquent\Collection;
 | 
			
		||||
use Toby\Domain\Enums\VacationRequestState;
 | 
			
		||||
use Toby\Domain\Enums\VacationType;
 | 
			
		||||
use Toby\Eloquent\Models\User;
 | 
			
		||||
use Toby\Eloquent\Models\YearPeriod;
 | 
			
		||||
@@ -26,7 +25,7 @@ class UserVacationStatsRetriever
 | 
			
		||||
                "vacationRequest",
 | 
			
		||||
                fn(Builder $query) => $query
 | 
			
		||||
                    ->whereIn("type", $this->getLimitableVacationTypes())
 | 
			
		||||
                    ->states(VacationRequestState::successStates()),
 | 
			
		||||
                    ->states(VacationRequestStatesRetriever::successStates()),
 | 
			
		||||
            )
 | 
			
		||||
            ->count();
 | 
			
		||||
    }
 | 
			
		||||
@@ -40,7 +39,7 @@ class UserVacationStatsRetriever
 | 
			
		||||
                "vacationRequest",
 | 
			
		||||
                fn(Builder $query) => $query
 | 
			
		||||
                    ->whereIn("type", $this->getLimitableVacationTypes())
 | 
			
		||||
                    ->states(VacationRequestState::pendingStates()),
 | 
			
		||||
                    ->states(VacationRequestStatesRetriever::pendingStates()),
 | 
			
		||||
            )
 | 
			
		||||
            ->count();
 | 
			
		||||
    }
 | 
			
		||||
@@ -54,7 +53,7 @@ class UserVacationStatsRetriever
 | 
			
		||||
                "vacationRequest",
 | 
			
		||||
                fn(Builder $query) => $query
 | 
			
		||||
                    ->whereIn("type", $this->getNotLimitableVacationTypes())
 | 
			
		||||
                    ->states(VacationRequestState::successStates()),
 | 
			
		||||
                    ->states(VacationRequestStatesRetriever::successStates()),
 | 
			
		||||
            )
 | 
			
		||||
            ->count();
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -6,15 +6,24 @@ namespace Toby\Domain;
 | 
			
		||||
 | 
			
		||||
use Illuminate\Contracts\Auth\Factory as Auth;
 | 
			
		||||
use Illuminate\Contracts\Events\Dispatcher;
 | 
			
		||||
use Toby\Domain\Enums\VacationRequestState;
 | 
			
		||||
use Toby\Domain\Events\VacationRequestAcceptedByAdministrative;
 | 
			
		||||
use Toby\Domain\Events\VacationRequestAcceptedByTechnical;
 | 
			
		||||
use Toby\Domain\Events\VacationRequestApproved;
 | 
			
		||||
use Toby\Domain\Events\VacationRequestCancelled;
 | 
			
		||||
use Toby\Domain\Events\VacationRequestCreated;
 | 
			
		||||
use Toby\Domain\Events\VacationRequestRejected;
 | 
			
		||||
use Toby\Domain\Events\VacationRequestStateChanged;
 | 
			
		||||
use Toby\Domain\Events\VacationRequestWaitsForAdminApproval;
 | 
			
		||||
use Toby\Domain\Events\VacationRequestWaitsForTechApproval;
 | 
			
		||||
use Toby\Domain\States\VacationRequest\AcceptedByAdministrative;
 | 
			
		||||
use Toby\Domain\States\VacationRequest\AcceptedByTechnical;
 | 
			
		||||
use Toby\Domain\States\VacationRequest\Approved;
 | 
			
		||||
use Toby\Domain\States\VacationRequest\Cancelled;
 | 
			
		||||
use Toby\Domain\States\VacationRequest\Rejected;
 | 
			
		||||
use Toby\Domain\States\VacationRequest\VacationRequestState;
 | 
			
		||||
use Toby\Domain\States\VacationRequest\WaitingForAdministrative;
 | 
			
		||||
use Toby\Domain\States\VacationRequest\WaitingForTechnical;
 | 
			
		||||
use Toby\Eloquent\Models\User;
 | 
			
		||||
use Toby\Eloquent\Models\VacationRequest;
 | 
			
		||||
 | 
			
		||||
class VacationRequestStateManager
 | 
			
		||||
@@ -24,64 +33,77 @@ class VacationRequestStateManager
 | 
			
		||||
        protected Dispatcher $dispatcher,
 | 
			
		||||
    ) {}
 | 
			
		||||
 | 
			
		||||
    public function markAsCreated(VacationRequest $vacationRequest): void
 | 
			
		||||
    public function markAsCreated(VacationRequest $vacationRequest, ?User $user = null): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->changeState($vacationRequest, VacationRequestState::Created);
 | 
			
		||||
        $this->fireStateChangedEvent($vacationRequest, null, $vacationRequest->state, $user);
 | 
			
		||||
 | 
			
		||||
        $this->dispatcher->dispatch(new VacationRequestCreated($vacationRequest));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function approve(VacationRequest $vacationRequest): void
 | 
			
		||||
    public function approve(VacationRequest $vacationRequest, ?User $user = null): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->changeState($vacationRequest, VacationRequestState::Approved);
 | 
			
		||||
        $this->changeState($vacationRequest, Approved::class, $user);
 | 
			
		||||
 | 
			
		||||
        $this->dispatcher->dispatch(new VacationRequestApproved($vacationRequest));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function reject(VacationRequest $vacationRequest): void
 | 
			
		||||
    public function reject(VacationRequest $vacationRequest, ?User $user = null): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->changeState($vacationRequest, VacationRequestState::Rejected);
 | 
			
		||||
 | 
			
		||||
        $this->changeState($vacationRequest, Rejected::class, $user);
 | 
			
		||||
        $this->dispatcher->dispatch(new VacationRequestRejected($vacationRequest));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function cancel(VacationRequest $vacationRequest): void
 | 
			
		||||
    public function cancel(VacationRequest $vacationRequest, ?User $user = null): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->changeState($vacationRequest, VacationRequestState::Cancelled);
 | 
			
		||||
        $this->changeState($vacationRequest, Cancelled::class, $user);
 | 
			
		||||
 | 
			
		||||
        $this->dispatcher->dispatch(new VacationRequestCancelled($vacationRequest));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function acceptAsTechnical(VacationRequest $vacationRequest): void
 | 
			
		||||
    public function acceptAsTechnical(VacationRequest $vacationRequest, ?User $user = null): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->changeState($vacationRequest, VacationRequestState::AcceptedByTechnical);
 | 
			
		||||
        $this->changeState($vacationRequest, AcceptedByTechnical::class, $user);
 | 
			
		||||
 | 
			
		||||
        $this->dispatcher->dispatch(new VacationRequestAcceptedByTechnical($vacationRequest));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function acceptAsAdministrative(VacationRequest $vacationRequest): void
 | 
			
		||||
    public function acceptAsAdministrative(VacationRequest $vacationRequest, ?User $user = null): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->changeState($vacationRequest, VacationRequestState::AcceptedByAdministrative);
 | 
			
		||||
        $this->changeState($vacationRequest, AcceptedByAdministrative::class, $user);
 | 
			
		||||
 | 
			
		||||
        $this->dispatcher->dispatch(new VacationRequestAcceptedByAdministrative($vacationRequest));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function waitForTechnical(VacationRequest $vacationRequest): void
 | 
			
		||||
    public function waitForTechnical(VacationRequest $vacationRequest, ?User $user = null): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->changeState($vacationRequest, VacationRequestState::WaitingForTechnical);
 | 
			
		||||
        $this->changeState($vacationRequest, WaitingForTechnical::class, $user);
 | 
			
		||||
 | 
			
		||||
        $this->dispatcher->dispatch(new VacationRequestWaitsForTechApproval($vacationRequest));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function waitForAdministrative(VacationRequest $vacationRequest): void
 | 
			
		||||
    public function waitForAdministrative(VacationRequest $vacationRequest, ?User $user = null): void
 | 
			
		||||
    {
 | 
			
		||||
        $this->changeState($vacationRequest, VacationRequestState::WaitingForAdministrative);
 | 
			
		||||
        $this->changeState($vacationRequest, WaitingForAdministrative::class, $user);
 | 
			
		||||
 | 
			
		||||
        $this->dispatcher->dispatch(new VacationRequestWaitsForAdminApproval($vacationRequest));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function changeState(VacationRequest $vacationRequest, VacationRequestState $state): void
 | 
			
		||||
    protected function changeState(VacationRequest $vacationRequest, string $state, ?User $user = null): void
 | 
			
		||||
    {
 | 
			
		||||
        $vacationRequest->changeStateTo($state);
 | 
			
		||||
        $previousState = $vacationRequest->state;
 | 
			
		||||
        $vacationRequest->state->transitionTo($state);
 | 
			
		||||
        $vacationRequest->save();
 | 
			
		||||
 | 
			
		||||
        $this->fireStateChangedEvent($vacationRequest, $previousState, $vacationRequest->state, $user);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    protected function fireStateChangedEvent(
 | 
			
		||||
        VacationRequest $vacationRequest,
 | 
			
		||||
        ?VacationRequestState $from,
 | 
			
		||||
        VacationRequestState $to,
 | 
			
		||||
        ?User $user = null,
 | 
			
		||||
    ): void {
 | 
			
		||||
        $event = new VacationRequestStateChanged($vacationRequest, $from, $to, $user);
 | 
			
		||||
        $this->dispatcher->dispatch($event);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										60
									
								
								app/Domain/VacationRequestStatesRetriever.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								app/Domain/VacationRequestStatesRetriever.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,60 @@
 | 
			
		||||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Toby\Domain;
 | 
			
		||||
 | 
			
		||||
use Toby\Domain\States\VacationRequest\AcceptedByAdministrative;
 | 
			
		||||
use Toby\Domain\States\VacationRequest\AcceptedByTechnical;
 | 
			
		||||
use Toby\Domain\States\VacationRequest\Approved;
 | 
			
		||||
use Toby\Domain\States\VacationRequest\Cancelled;
 | 
			
		||||
use Toby\Domain\States\VacationRequest\Created;
 | 
			
		||||
use Toby\Domain\States\VacationRequest\Rejected;
 | 
			
		||||
use Toby\Domain\States\VacationRequest\WaitingForAdministrative;
 | 
			
		||||
use Toby\Domain\States\VacationRequest\WaitingForTechnical;
 | 
			
		||||
 | 
			
		||||
class VacationRequestStatesRetriever
 | 
			
		||||
{
 | 
			
		||||
    public static function pendingStates(): array
 | 
			
		||||
    {
 | 
			
		||||
        return [
 | 
			
		||||
            Created::class,
 | 
			
		||||
            WaitingForTechnical::class,
 | 
			
		||||
            WaitingForAdministrative::class,
 | 
			
		||||
            AcceptedByTechnical::class,
 | 
			
		||||
            AcceptedByAdministrative::class,
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function successStates(): array
 | 
			
		||||
    {
 | 
			
		||||
        return [Approved::class];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function failedStates(): array
 | 
			
		||||
    {
 | 
			
		||||
        return [
 | 
			
		||||
            Rejected::class,
 | 
			
		||||
            Cancelled::class,
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function all(): array
 | 
			
		||||
    {
 | 
			
		||||
        return [
 | 
			
		||||
            ...self::pendingStates(),
 | 
			
		||||
            ...self::successStates(),
 | 
			
		||||
            ...self::failedStates(),
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static function filterByStatus(string $filter): array
 | 
			
		||||
    {
 | 
			
		||||
        return match ($filter) {
 | 
			
		||||
            "pending" => self::pendingStates(),
 | 
			
		||||
            "success" => self::successStates(),
 | 
			
		||||
            "failed" => self::failedStates(),
 | 
			
		||||
            default => self::all(),
 | 
			
		||||
        };
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -6,9 +6,9 @@ namespace Toby\Domain\Validation\Rules;
 | 
			
		||||
 | 
			
		||||
use Illuminate\Database\Eloquent\Builder;
 | 
			
		||||
use Illuminate\Database\Eloquent\Collection;
 | 
			
		||||
use Toby\Domain\Enums\VacationRequestState;
 | 
			
		||||
use Toby\Domain\Enums\VacationType;
 | 
			
		||||
use Toby\Domain\VacationDaysCalculator;
 | 
			
		||||
use Toby\Domain\VacationRequestStatesRetriever;
 | 
			
		||||
use Toby\Domain\VacationTypeConfigRetriever;
 | 
			
		||||
use Toby\Eloquent\Models\User;
 | 
			
		||||
use Toby\Eloquent\Models\VacationRequest;
 | 
			
		||||
@@ -52,7 +52,7 @@ class DoesNotExceedLimitRule implements VacationRequestRule
 | 
			
		||||
                "vacationRequest",
 | 
			
		||||
                fn(Builder $query) => $query
 | 
			
		||||
                    ->whereIn("type", $this->getLimitableVacationTypes())
 | 
			
		||||
                    ->noStates(VacationRequestState::failedStates()),
 | 
			
		||||
                    ->noStates(VacationRequestStatesRetriever::failedStates()),
 | 
			
		||||
            )
 | 
			
		||||
            ->count();
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,7 @@ declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Toby\Domain\Validation\Rules;
 | 
			
		||||
 | 
			
		||||
use Toby\Domain\Enums\VacationRequestState;
 | 
			
		||||
use Toby\Domain\VacationRequestStatesRetriever;
 | 
			
		||||
use Toby\Eloquent\Models\VacationRequest;
 | 
			
		||||
 | 
			
		||||
class NoApprovedVacationRequestsInRange implements VacationRequestRule
 | 
			
		||||
@@ -15,7 +15,7 @@ class NoApprovedVacationRequestsInRange implements VacationRequestRule
 | 
			
		||||
            ->user
 | 
			
		||||
            ->vacationRequests()
 | 
			
		||||
            ->overlapsWith($vacationRequest)
 | 
			
		||||
            ->states(VacationRequestState::successStates())
 | 
			
		||||
            ->states(VacationRequestStatesRetriever::successStates())
 | 
			
		||||
            ->exists();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -4,7 +4,7 @@ declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
namespace Toby\Domain\Validation\Rules;
 | 
			
		||||
 | 
			
		||||
use Toby\Domain\Enums\VacationRequestState;
 | 
			
		||||
use Toby\Domain\VacationRequestStatesRetriever;
 | 
			
		||||
use Toby\Eloquent\Models\VacationRequest;
 | 
			
		||||
 | 
			
		||||
class NoPendingVacationRequestInRange implements VacationRequestRule
 | 
			
		||||
@@ -15,7 +15,7 @@ class NoPendingVacationRequestInRange implements VacationRequestRule
 | 
			
		||||
            ->user
 | 
			
		||||
            ->vacationRequests()
 | 
			
		||||
            ->overlapsWith($vacationRequest)
 | 
			
		||||
            ->states(VacationRequestState::pendingStates())
 | 
			
		||||
            ->states(VacationRequestStatesRetriever::pendingStates())
 | 
			
		||||
            ->exists();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user