From 2ccdfed2eceb150575fd5e07a79c4cf48294edfa Mon Sep 17 00:00:00 2001 From: Adrian Hopek Date: Mon, 21 Feb 2022 08:11:28 +0100 Subject: [PATCH] wip --- app/Domain/CalendarGenerator.php | 4 +- app/Domain/Enums/VacationRequestState.php | 56 ---- .../Events/VacationRequestStateChanged.php | 2 +- .../AcceptedByAdministrative.php | 10 + .../VacationRequest/AcceptedByTechnical.php | 10 + .../States/VacationRequest/Approved.php | 10 + .../States/VacationRequest/Cancelled.php | 10 + app/Domain/States/VacationRequest/Created.php | 10 + .../States/VacationRequest/Rejected.php | 10 + .../VacationRequest/VacationRequestState.php | 39 +++ .../WaitingForAdministrative.php | 10 + .../VacationRequest/WaitingForTechnical.php | 10 + app/Domain/VacationRequestStateManager.php | 61 +++-- app/Domain/VacationRequestStatesRetriever.php | 60 +++++ .../Rules/DoesNotExceedLimitRule.php | 4 +- .../NoApprovedVacationRequestsInRange.php | 4 +- .../Rules/NoPendingVacationRequestInRange.php | 4 +- app/Eloquent/Models/VacationRequest.php | 19 +- .../Models/VacationRequestActivity.php | 2 +- .../Observers/VacationRequestObserver.php | 30 --- .../Controllers/VacationRequestController.php | 38 ++- .../VacationRequestActivityResource.php | 1 - composer.json | 3 +- composer.lock | 243 ++++++++++++++---- config/model-states.php | 7 + database/factories/VacationRequestFactory.php | 4 +- public/avatars | 1 - resources/js/Pages/VacationRequest/Show.vue | 24 +- tests/Feature/VacationRequestTest.php | 27 +- tests/Unit/VacationRequestStatesTest.php | 16 +- 30 files changed, 511 insertions(+), 218 deletions(-) delete mode 100644 app/Domain/Enums/VacationRequestState.php create mode 100644 app/Domain/States/VacationRequest/AcceptedByAdministrative.php create mode 100644 app/Domain/States/VacationRequest/AcceptedByTechnical.php create mode 100644 app/Domain/States/VacationRequest/Approved.php create mode 100644 app/Domain/States/VacationRequest/Cancelled.php create mode 100644 app/Domain/States/VacationRequest/Created.php create mode 100644 app/Domain/States/VacationRequest/Rejected.php create mode 100644 app/Domain/States/VacationRequest/VacationRequestState.php create mode 100644 app/Domain/States/VacationRequest/WaitingForAdministrative.php create mode 100644 app/Domain/States/VacationRequest/WaitingForTechnical.php create mode 100644 app/Domain/VacationRequestStatesRetriever.php create mode 100644 config/model-states.php delete mode 120000 public/avatars diff --git a/app/Domain/CalendarGenerator.php b/app/Domain/CalendarGenerator.php index f1d72f2..a4c9d3f 100644 --- a/app/Domain/CalendarGenerator.php +++ b/app/Domain/CalendarGenerator.php @@ -7,8 +7,8 @@ namespace Toby\Domain; use Carbon\CarbonImmutable; use Carbon\CarbonInterface; use Carbon\CarbonPeriod; +use Illuminate\Database\Eloquent\Builder; use Illuminate\Support\Collection; -use Toby\Domain\Enums\VacationRequestState; use Toby\Eloquent\Helpers\YearPeriodRetriever; use Toby\Eloquent\Models\Vacation; use Toby\Eloquent\Models\YearPeriod; @@ -73,7 +73,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()); } diff --git a/app/Domain/Enums/VacationRequestState.php b/app/Domain/Enums/VacationRequestState.php deleted file mode 100644 index cde2e2f..0000000 --- a/app/Domain/Enums/VacationRequestState.php +++ /dev/null @@ -1,56 +0,0 @@ -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(), - }; - } -} diff --git a/app/Domain/Events/VacationRequestStateChanged.php b/app/Domain/Events/VacationRequestStateChanged.php index 7779917..d521f16 100644 --- a/app/Domain/Events/VacationRequestStateChanged.php +++ b/app/Domain/Events/VacationRequestStateChanged.php @@ -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; diff --git a/app/Domain/States/VacationRequest/AcceptedByAdministrative.php b/app/Domain/States/VacationRequest/AcceptedByAdministrative.php new file mode 100644 index 0000000..c0b70ab --- /dev/null +++ b/app/Domain/States/VacationRequest/AcceptedByAdministrative.php @@ -0,0 +1,10 @@ +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); + } +} diff --git a/app/Domain/States/VacationRequest/WaitingForAdministrative.php b/app/Domain/States/VacationRequest/WaitingForAdministrative.php new file mode 100644 index 0000000..dd57906 --- /dev/null +++ b/app/Domain/States/VacationRequest/WaitingForAdministrative.php @@ -0,0 +1,10 @@ +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); } - 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); } - 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); } - 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); } } diff --git a/app/Domain/VacationRequestStatesRetriever.php b/app/Domain/VacationRequestStatesRetriever.php new file mode 100644 index 0000000..ebe66fa --- /dev/null +++ b/app/Domain/VacationRequestStatesRetriever.php @@ -0,0 +1,60 @@ + self::pendingStates(), + "success" => self::successStates(), + "failed" => self::failedStates(), + default => self::all(), + }; + } +} diff --git a/app/Domain/Validation/Rules/DoesNotExceedLimitRule.php b/app/Domain/Validation/Rules/DoesNotExceedLimitRule.php index c8c9ab5..a21dfa8 100644 --- a/app/Domain/Validation/Rules/DoesNotExceedLimitRule.php +++ b/app/Domain/Validation/Rules/DoesNotExceedLimitRule.php @@ -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; @@ -53,7 +53,7 @@ class DoesNotExceedLimitRule implements VacationRequestRule "vacationRequest", fn(Builder $query) => $query ->whereIn("type", $this->getLimitableVacationTypes()) - ->noStates(VacationRequestState::failedStates()), + ->noStates(VacationRequestStatesRetriever::failedStates()), ) ->count(); } diff --git a/app/Domain/Validation/Rules/NoApprovedVacationRequestsInRange.php b/app/Domain/Validation/Rules/NoApprovedVacationRequestsInRange.php index d06fd95..5758724 100644 --- a/app/Domain/Validation/Rules/NoApprovedVacationRequestsInRange.php +++ b/app/Domain/Validation/Rules/NoApprovedVacationRequestsInRange.php @@ -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(); } diff --git a/app/Domain/Validation/Rules/NoPendingVacationRequestInRange.php b/app/Domain/Validation/Rules/NoPendingVacationRequestInRange.php index 3031b56..1fbc7a5 100644 --- a/app/Domain/Validation/Rules/NoPendingVacationRequestInRange.php +++ b/app/Domain/Validation/Rules/NoPendingVacationRequestInRange.php @@ -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(); } diff --git a/app/Eloquent/Models/VacationRequest.php b/app/Eloquent/Models/VacationRequest.php index f8d29b9..ea4353f 100644 --- a/app/Eloquent/Models/VacationRequest.php +++ b/app/Eloquent/Models/VacationRequest.php @@ -12,8 +12,9 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Support\Carbon; use Illuminate\Support\Collection; -use Toby\Domain\Enums\VacationRequestState; +use Spatie\ModelStates\HasStates; use Toby\Domain\Enums\VacationType; +use Toby\Domain\States\VacationRequest\VacationRequestState; /** * @property int $id @@ -32,6 +33,7 @@ use Toby\Domain\Enums\VacationType; class VacationRequest extends Model { use HasFactory; + use HasStates; protected $guarded = []; @@ -62,21 +64,14 @@ class VacationRequest extends Model return $this->hasMany(Vacation::class); } - public function changeStateTo(VacationRequestState $state): void + public function scopeStates(Builder $query, VacationRequestState|array $states): Builder { - $this->state = $state; - - $this->save(); + return $query->whereState("state", $states); } - public function scopeStates(Builder $query, array $states): Builder + public function scopeNoStates(Builder $query, VacationRequestState|array $states): Builder { - return $query->whereIn("state", $states); - } - - public function scopeNoStates(Builder $query, array $states): Builder - { - return $query->whereNotIn("state", $states); + return $query->whereNotState("state", $states); } public function scopeOverlapsWith(Builder $query, self $vacationRequest): Builder diff --git a/app/Eloquent/Models/VacationRequestActivity.php b/app/Eloquent/Models/VacationRequestActivity.php index 8425d99..178254a 100644 --- a/app/Eloquent/Models/VacationRequestActivity.php +++ b/app/Eloquent/Models/VacationRequestActivity.php @@ -6,7 +6,7 @@ namespace Toby\Eloquent\Models; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; -use Toby\Domain\Enums\VacationRequestState; +use Toby\Domain\States\VacationRequest\VacationRequestState; /** * @property int $id diff --git a/app/Eloquent/Observers/VacationRequestObserver.php b/app/Eloquent/Observers/VacationRequestObserver.php index eec46bc..35b29da 100644 --- a/app/Eloquent/Observers/VacationRequestObserver.php +++ b/app/Eloquent/Observers/VacationRequestObserver.php @@ -6,9 +6,6 @@ namespace Toby\Eloquent\Observers; use Illuminate\Contracts\Auth\Factory as Auth; use Illuminate\Events\Dispatcher; -use Toby\Domain\Enums\VacationRequestState; -use Toby\Domain\Events\VacationRequestStateChanged; -use Toby\Eloquent\Models\User; use Toby\Eloquent\Models\VacationRequest; class VacationRequestObserver @@ -29,31 +26,4 @@ class VacationRequestObserver $vacationRequest->name = "{$vacationRequestNumber}/${year}"; } - - public function saved(VacationRequest $vacationRequest): void - { - if ($vacationRequest->isDirty("state")) { - $previousState = $vacationRequest->getOriginal("state"); - - $this->fireStateChangedEvent($vacationRequest, $previousState, $vacationRequest->state); - } - } - - protected function fireStateChangedEvent( - VacationRequest $vacationRequest, - ?VacationRequestState $from, - VacationRequestState $to, - ): void { - $event = new VacationRequestStateChanged($vacationRequest, $from, $to, $this->getAuthUser()); - - $this->dispatcher->dispatch($event); - } - - protected function getAuthUser(): ?User - { - /** @var User $user */ - $user = $this->auth->guard()->user(); - - return $user; - } } diff --git a/app/Infrastructure/Http/Controllers/VacationRequestController.php b/app/Infrastructure/Http/Controllers/VacationRequestController.php index c24cbe2..e3c8a1c 100644 --- a/app/Infrastructure/Http/Controllers/VacationRequestController.php +++ b/app/Infrastructure/Http/Controllers/VacationRequestController.php @@ -8,11 +8,17 @@ use Barryvdh\DomPDF\Facade\Pdf; use Illuminate\Http\RedirectResponse; use Illuminate\Http\Request; use Illuminate\Http\Response as LaravelResponse; +use Illuminate\Support\Arr; use Inertia\Response; -use Toby\Domain\Enums\VacationRequestState; +use Toby\Domain\Enums\Role; use Toby\Domain\Enums\VacationType; +use Toby\Domain\States\VacationRequest\AcceptedByAdministrative; +use Toby\Domain\States\VacationRequest\AcceptedByTechnical; +use Toby\Domain\States\VacationRequest\Cancelled; +use Toby\Domain\States\VacationRequest\Rejected; use Toby\Domain\VacationDaysCalculator; use Toby\Domain\VacationRequestStateManager; +use Toby\Domain\VacationRequestStatesRetriever; use Toby\Domain\Validation\VacationRequestValidator; use Toby\Eloquent\Helpers\YearPeriodRetriever; use Toby\Eloquent\Models\VacationRequest; @@ -31,7 +37,7 @@ class VacationRequestController extends Controller ->with("vacations") ->where("year_period_id", $yearPeriodRetriever->selected()->id) ->latest() - ->states(VacationRequestState::filterByStatus($status)) + ->states(VacationRequestStatesRetriever::filterByStatus($status)) ->paginate(); return inertia("VacationRequest/Index", [ @@ -42,11 +48,23 @@ class VacationRequestController extends Controller ]); } - public function show(VacationRequest $vacationRequest): Response + public function show(Request $request, VacationRequest $vacationRequest): Response { + $user = $request->user(); + return inertia("VacationRequest/Show", [ "request" => new VacationRequestResource($vacationRequest), "activities" => VacationRequestActivityResource::collection($vacationRequest->activities), + "can" => [ + "acceptAsTechnical" => $vacationRequest->state->canTransitionTo(AcceptedByTechnical::class) + && $user === Role::TechnicalApprover, + "acceptAsAdministrative" => $vacationRequest->state->canTransitionTo(AcceptedByAdministrative::class) + && $user === Role::AdministrativeApprover, + "reject" => $vacationRequest->state->canTransitionTo(Rejected::class) + && in_array($user->role, [Role::TechnicalApprover, Role::AdministrativeApprover]), + "cancel" => $vacationRequest->state->canTransitionTo(Cancelled::class) + && $user === Role::TechnicalApprover, + ] ]); } @@ -92,7 +110,7 @@ class VacationRequestController extends Controller ]); } - $stateManager->markAsCreated($vacationRequest); + $stateManager->markAsCreated($vacationRequest, $request->user()); return redirect() ->route("vacation.requests.show", $vacationRequest) @@ -100,40 +118,44 @@ class VacationRequestController extends Controller } public function reject( + Request $request, VacationRequest $vacationRequest, VacationRequestStateManager $stateManager, ): RedirectResponse { - $stateManager->reject($vacationRequest); + $stateManager->reject($vacationRequest, $request->user()); return redirect()->back() ->with("success", __("Vacation request has been rejected.")); } public function cancel( + Request $request, VacationRequest $vacationRequest, VacationRequestStateManager $stateManager, ): RedirectResponse { - $stateManager->cancel($vacationRequest); + $stateManager->cancel($vacationRequest, $request->user()); return redirect()->back() ->with("success", __("Vacation request has been cancelled.")); } public function acceptAsTechnical( + Request $request, VacationRequest $vacationRequest, VacationRequestStateManager $stateManager, ): RedirectResponse { - $stateManager->acceptAsTechnical($vacationRequest); + $stateManager->acceptAsTechnical($vacationRequest, $request->user()); return redirect()->back() ->with("success", __("Vacation request has been accepted.")); } public function acceptAsAdministrative( + Request $request, VacationRequest $vacationRequest, VacationRequestStateManager $stateManager, ): RedirectResponse { - $stateManager->acceptAsAdministrative($vacationRequest); + $stateManager->acceptAsAdministrative($vacationRequest, $request->user()); return redirect()->back() ->with("success", __("Vacation request has been accepted.")); diff --git a/app/Infrastructure/Http/Resources/VacationRequestActivityResource.php b/app/Infrastructure/Http/Resources/VacationRequestActivityResource.php index c513785..fb9ff70 100644 --- a/app/Infrastructure/Http/Resources/VacationRequestActivityResource.php +++ b/app/Infrastructure/Http/Resources/VacationRequestActivityResource.php @@ -17,7 +17,6 @@ class VacationRequestActivityResource extends JsonResource "time" => $this->created_at->format("H:i"), "user" => $this->user ? $this->user->fullName : __("System"), "state" => $this->to, - "text" => $this->to->label(), ]; } } diff --git a/composer.json b/composer.json index 92a4bdb..1d5857d 100644 --- a/composer.json +++ b/composer.json @@ -18,7 +18,8 @@ "laravel/telescope": "^4.6", "laravel/tinker": "^2.5", "lasserafn/php-initial-avatar-generator": "^4.2", - "spatie/laravel-google-calendar": "^3.5" + "spatie/laravel-google-calendar": "^3.5", + "spatie/laravel-model-states": "^2.1" }, "require-dev": { "blumilksoftware/codestyle": "^0.9.0", diff --git a/composer.lock b/composer.lock index 6733691..b266227 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "c0f36b87659921d0b7db0464b5d79ed5", + "content-hash": "3fdff95b32e84ce3b115bc3bc7289cf4", "packages": [ { "name": "asm89/stack-cors", @@ -709,6 +709,59 @@ ], "time": "2021-10-11T09:18:27+00:00" }, + { + "name": "facade/ignition-contracts", + "version": "1.0.2", + "source": { + "type": "git", + "url": "https://github.com/facade/ignition-contracts.git", + "reference": "3c921a1cdba35b68a7f0ccffc6dffc1995b18267" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/facade/ignition-contracts/zipball/3c921a1cdba35b68a7f0ccffc6dffc1995b18267", + "reference": "3c921a1cdba35b68a7f0ccffc6dffc1995b18267", + "shasum": "" + }, + "require": { + "php": "^7.3|^8.0" + }, + "require-dev": { + "friendsofphp/php-cs-fixer": "^v2.15.8", + "phpunit/phpunit": "^9.3.11", + "vimeo/psalm": "^3.17.1" + }, + "type": "library", + "autoload": { + "psr-4": { + "Facade\\IgnitionContracts\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "homepage": "https://flareapp.io", + "role": "Developer" + } + ], + "description": "Solution contracts for Ignition", + "homepage": "https://github.com/facade/ignition-contracts", + "keywords": [ + "contracts", + "flare", + "ignition" + ], + "support": { + "issues": "https://github.com/facade/ignition-contracts/issues", + "source": "https://github.com/facade/ignition-contracts/tree/1.0.2" + }, + "time": "2020-10-16T08:27:54+00:00" + }, { "name": "firebase/php-jwt", "version": "v5.5.1", @@ -4379,6 +4432,139 @@ ], "time": "2022-01-13T09:43:27+00:00" }, + { + "name": "spatie/laravel-model-states", + "version": "2.1.4", + "source": { + "type": "git", + "url": "https://github.com/spatie/laravel-model-states.git", + "reference": "c9c4865abd2b5ec534214aede784631366bed7d4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/laravel-model-states/zipball/c9c4865abd2b5ec534214aede784631366bed7d4", + "reference": "c9c4865abd2b5ec534214aede784631366bed7d4", + "shasum": "" + }, + "require": { + "ext-json": "*", + "facade/ignition-contracts": "^1.0", + "illuminate/contracts": "^8.73 | ^9.0", + "illuminate/database": "^8.73 | ^9.0", + "illuminate/support": "^8.73 | ^9.0", + "php": "^7.4|^8.0", + "spatie/laravel-package-tools": "^1.9" + }, + "require-dev": { + "orchestra/testbench": "^6.23 | ^7.0", + "phpunit/phpunit": "^9.4", + "symfony/var-dumper": "^5.3 | ^6.0" + }, + "type": "library", + "extra": { + "laravel": { + "providers": [ + "Spatie\\ModelStates\\ModelStatesServiceProvider" + ] + } + }, + "autoload": { + "psr-4": { + "Spatie\\ModelStates\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Brent Roose", + "email": "brent@spatie.be", + "homepage": "https://spatie.be", + "role": "Developer" + } + ], + "description": "State support for Eloquent models", + "homepage": "https://github.com/spatie/laravel-model-states", + "keywords": [ + "spatie", + "state" + ], + "support": { + "source": "https://github.com/spatie/laravel-model-states/tree/2.1.4" + }, + "funding": [ + { + "url": "https://spatie.be/open-source/support-us", + "type": "custom" + }, + { + "url": "https://github.com/spatie", + "type": "github" + } + ], + "time": "2022-01-19T19:57:35+00:00" + }, + { + "name": "spatie/laravel-package-tools", + "version": "1.11.1", + "source": { + "type": "git", + "url": "https://github.com/spatie/laravel-package-tools.git", + "reference": "e933f14dae0b31b1f6a45aa769dbd97ce781031a" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/spatie/laravel-package-tools/zipball/e933f14dae0b31b1f6a45aa769dbd97ce781031a", + "reference": "e933f14dae0b31b1f6a45aa769dbd97ce781031a", + "shasum": "" + }, + "require": { + "illuminate/contracts": "^7.0|^8.0|^9.0", + "php": "^7.4|^8.0" + }, + "require-dev": { + "mockery/mockery": "^1.4", + "orchestra/testbench": "^5.0|^6.23|^7.0", + "phpunit/phpunit": "^9.4", + "spatie/test-time": "^1.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Spatie\\LaravelPackageTools\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Freek Van der Herten", + "email": "freek@spatie.be", + "role": "Developer" + } + ], + "description": "Tools for creating Laravel packages", + "homepage": "https://github.com/spatie/laravel-package-tools", + "keywords": [ + "laravel-package-tools", + "spatie" + ], + "support": { + "issues": "https://github.com/spatie/laravel-package-tools/issues", + "source": "https://github.com/spatie/laravel-package-tools/tree/1.11.1" + }, + "funding": [ + { + "url": "https://github.com/spatie", + "type": "github" + } + ], + "time": "2022-02-16T11:14:09+00:00" + }, { "name": "symfony/console", "version": "v6.0.3", @@ -6851,59 +7037,6 @@ ], "time": "2020-11-10T18:47:58+00:00" }, - { - "name": "facade/ignition-contracts", - "version": "1.0.2", - "source": { - "type": "git", - "url": "https://github.com/facade/ignition-contracts.git", - "reference": "3c921a1cdba35b68a7f0ccffc6dffc1995b18267" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/facade/ignition-contracts/zipball/3c921a1cdba35b68a7f0ccffc6dffc1995b18267", - "reference": "3c921a1cdba35b68a7f0ccffc6dffc1995b18267", - "shasum": "" - }, - "require": { - "php": "^7.3|^8.0" - }, - "require-dev": { - "friendsofphp/php-cs-fixer": "^v2.15.8", - "phpunit/phpunit": "^9.3.11", - "vimeo/psalm": "^3.17.1" - }, - "type": "library", - "autoload": { - "psr-4": { - "Facade\\IgnitionContracts\\": "src" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "authors": [ - { - "name": "Freek Van der Herten", - "email": "freek@spatie.be", - "homepage": "https://flareapp.io", - "role": "Developer" - } - ], - "description": "Solution contracts for Ignition", - "homepage": "https://github.com/facade/ignition-contracts", - "keywords": [ - "contracts", - "flare", - "ignition" - ], - "support": { - "issues": "https://github.com/facade/ignition-contracts/issues", - "source": "https://github.com/facade/ignition-contracts/tree/1.0.2" - }, - "time": "2020-10-16T08:27:54+00:00" - }, { "name": "fakerphp/faker", "version": "v1.19.0", @@ -9571,5 +9704,5 @@ "ext-pdo": "*" }, "platform-dev": [], - "plugin-api-version": "2.1.0" + "plugin-api-version": "2.2.0" } diff --git a/config/model-states.php b/config/model-states.php new file mode 100644 index 0000000..8d058b4 --- /dev/null +++ b/config/model-states.php @@ -0,0 +1,7 @@ + Spatie\ModelStates\DefaultTransition::class, +]; diff --git a/database/factories/VacationRequestFactory.php b/database/factories/VacationRequestFactory.php index 4816781..fbf130b 100644 --- a/database/factories/VacationRequestFactory.php +++ b/database/factories/VacationRequestFactory.php @@ -6,8 +6,8 @@ namespace Database\Factories; use Carbon\CarbonImmutable; use Illuminate\Database\Eloquent\Factories\Factory; -use Toby\Domain\Enums\VacationRequestState; use Toby\Domain\Enums\VacationType; +use Toby\Domain\VacationRequestStatesRetriever; use Toby\Eloquent\Models\User; use Toby\Eloquent\Models\VacationRequest; use Toby\Eloquent\Models\YearPeriod; @@ -27,7 +27,7 @@ class VacationRequestFactory extends Factory "year_period_id" => YearPeriod::factory(), "name" => fn(array $attributes) => $this->generateName($attributes), "type" => $this->faker->randomElement(VacationType::cases()), - "state" => $this->faker->randomElement(VacationRequestState::cases()), + "state" => $this->faker->randomElement(VacationRequestStatesRetriever::all()), "from" => $from, "to" => $from->addDays($days), "comment" => $this->faker->boolean ? $this->faker->paragraph() : null, diff --git a/public/avatars b/public/avatars deleted file mode 120000 index c6a773f..0000000 --- a/public/avatars +++ /dev/null @@ -1 +0,0 @@ -/application/storage/app/avatars \ No newline at end of file diff --git a/resources/js/Pages/VacationRequest/Show.vue b/resources/js/Pages/VacationRequest/Show.vue index 1e46a04..aa3cb6f 100644 --- a/resources/js/Pages/VacationRequest/Show.vue +++ b/resources/js/Pages/VacationRequest/Show.vue @@ -110,7 +110,10 @@ -
+

Zaakceptuj wniosek jako osoba techniczna @@ -134,7 +137,10 @@

-
+

Zaakceptuj wniosek jako osoba administracyjna @@ -157,7 +163,10 @@

-
+

Odrzuć wniosek @@ -180,7 +189,10 @@

-
+

Anuluj wniosek @@ -246,6 +258,10 @@ export default { type: Object, default: () => null, }, + can: { + type: Object, + default: () => null, + }, activities: { type: Object, default: () => null, diff --git a/tests/Feature/VacationRequestTest.php b/tests/Feature/VacationRequestTest.php index 0841d1e..0118b80 100644 --- a/tests/Feature/VacationRequestTest.php +++ b/tests/Feature/VacationRequestTest.php @@ -9,9 +9,12 @@ use Illuminate\Support\Carbon; use Illuminate\Support\Facades\Bus; use Inertia\Testing\AssertableInertia as Assert; use Tests\FeatureTestCase; -use Toby\Domain\Enums\VacationRequestState; use Toby\Domain\Enums\VacationType; use Toby\Domain\PolishHolidaysRetriever; +use Toby\Domain\States\VacationRequest\Approved; +use Toby\Domain\States\VacationRequest\Rejected; +use Toby\Domain\States\VacationRequest\WaitingForAdministrative; +use Toby\Domain\States\VacationRequest\WaitingForTechnical; use Toby\Eloquent\Models\User; use Toby\Eloquent\Models\VacationLimit; use Toby\Eloquent\Models\VacationRequest; @@ -81,7 +84,7 @@ class VacationRequestTest extends FeatureTestCase "year_period_id" => $currentYearPeriod->id, "name" => "1/" . $currentYearPeriod->year, "type" => VacationType::Vacation->value, - "state" => VacationRequestState::WaitingForTechnical, + "state" => WaitingForTechnical::$name, "from" => Carbon::create($currentYearPeriod->year, 2, 7)->toDateString(), "to" => Carbon::create($currentYearPeriod->year, 2, 11)->toDateString(), "comment" => "Comment for the vacation request.", @@ -95,7 +98,7 @@ class VacationRequestTest extends FeatureTestCase $currentYearPeriod = YearPeriod::current(); $vacationRequest = VacationRequest::factory([ - "state" => VacationRequestState::WaitingForTechnical, + "state" => WaitingForTechnical::class, "type" => VacationType::Vacation, ]) ->for($user) @@ -107,7 +110,7 @@ class VacationRequestTest extends FeatureTestCase ->assertSessionHasNoErrors(); $this->assertDatabaseHas("vacation_requests", [ - "state" => VacationRequestState::WaitingForAdministrative, + "state" => WaitingForAdministrative::$name, ]); } @@ -119,7 +122,7 @@ class VacationRequestTest extends FeatureTestCase $currentYearPeriod = YearPeriod::current(); $vacationRequest = VacationRequest::factory([ - "state" => VacationRequestState::WaitingForAdministrative, + "state" => WaitingForAdministrative::class, ]) ->for($user) ->for($currentYearPeriod) @@ -130,7 +133,7 @@ class VacationRequestTest extends FeatureTestCase ->assertSessionHasNoErrors(); $this->assertDatabaseHas("vacation_requests", [ - "state" => VacationRequestState::Approved, + "state" => Approved::$name, ]); Bus::assertDispatched(SendVacationRequestDaysToGoogleCalendar::class); @@ -142,7 +145,7 @@ class VacationRequestTest extends FeatureTestCase $technicalApprover = User::factory()->createQuietly(); $currentYearPeriod = YearPeriod::current(); - $vacationLimit = VacationLimit::factory([ + VacationLimit::factory([ "days" => 20, ]) ->for($user) @@ -150,7 +153,7 @@ class VacationRequestTest extends FeatureTestCase ->create(); $vacationRequest = VacationRequest::factory([ - "state" => VacationRequestState::WaitingForTechnical, + "state" => WaitingForTechnical::class, "type" => VacationType::Vacation, ]) ->for($user) @@ -162,7 +165,7 @@ class VacationRequestTest extends FeatureTestCase ->assertSessionHasNoErrors(); $this->assertDatabaseHas("vacation_requests", [ - "state" => VacationRequestState::Rejected, + "state" => Rejected::$name, ]); } @@ -259,7 +262,7 @@ class VacationRequestTest extends FeatureTestCase VacationRequest::factory([ "type" => VacationType::Vacation->value, - "state" => VacationRequestState::WaitingForTechnical, + "state" => WaitingForTechnical::class, "from" => Carbon::create($currentYearPeriod->year, 2, 1)->toDateString(), "to" => Carbon::create($currentYearPeriod->year, 2, 4)->toDateString(), "comment" => "Comment for the vacation request.", @@ -286,7 +289,7 @@ class VacationRequestTest extends FeatureTestCase $user = User::factory()->createQuietly(); $currentYearPeriod = YearPeriod::current(); - $vacationLimit = VacationLimit::factory([ + VacationLimit::factory([ "days" => 20, ]) ->for($user) @@ -295,7 +298,7 @@ class VacationRequestTest extends FeatureTestCase VacationRequest::factory([ "type" => VacationType::Vacation->value, - "state" => VacationRequestState::Approved, + "state" => Approved::class, "from" => Carbon::create($currentYearPeriod->year, 2, 2)->toDateString(), "to" => Carbon::create($currentYearPeriod->year, 2, 4)->toDateString(), "comment" => "Comment for the vacation request.", diff --git a/tests/Unit/VacationRequestStatesTest.php b/tests/Unit/VacationRequestStatesTest.php index ed943d6..bdb10f4 100644 --- a/tests/Unit/VacationRequestStatesTest.php +++ b/tests/Unit/VacationRequestStatesTest.php @@ -8,8 +8,10 @@ use Illuminate\Foundation\Testing\DatabaseMigrations; use Illuminate\Support\Carbon; use Tests\TestCase; use Tests\Traits\InteractsWithYearPeriods; -use Toby\Domain\Enums\VacationRequestState; use Toby\Domain\Enums\VacationType; +use Toby\Domain\States\VacationRequest\Approved; +use Toby\Domain\States\VacationRequest\Created; +use Toby\Domain\States\VacationRequest\WaitingForTechnical; use Toby\Domain\VacationRequestStateManager; use Toby\Eloquent\Models\User; use Toby\Eloquent\Models\VacationRequest; @@ -40,7 +42,7 @@ class VacationRequestStatesTest extends TestCase /** @var VacationRequest $vacationRequest */ $vacationRequest = VacationRequest::factory([ "type" => VacationType::Vacation->value, - "state" => VacationRequestState::Created, + "state" => Created::class, "from" => Carbon::create($currentYearPeriod->year, 2, 1)->toDateString(), "to" => Carbon::create($currentYearPeriod->year, 2, 4)->toDateString(), "comment" => "Comment for the vacation request.", @@ -51,7 +53,7 @@ class VacationRequestStatesTest extends TestCase $this->stateManager->waitForTechnical($vacationRequest); - $this->assertEquals(VacationRequestState::WaitingForTechnical, $vacationRequest->state); + $this->assertTrue($vacationRequest->state->equals(WaitingForTechnical::class)); } public function testAfterCreatingVacationRequestOfTypeSickVacationItTransitsToProperState(): void @@ -63,7 +65,7 @@ class VacationRequestStatesTest extends TestCase /** @var VacationRequest $vacationRequest */ $vacationRequest = VacationRequest::factory([ "type" => VacationType::Sick->value, - "state" => VacationRequestState::Created, + "state" => Created::class, "from" => Carbon::create($currentYearPeriod->year, 2, 1)->toDateString(), "to" => Carbon::create($currentYearPeriod->year, 2, 4)->toDateString(), ]) @@ -73,7 +75,7 @@ class VacationRequestStatesTest extends TestCase $this->stateManager->approve($vacationRequest); - $this->assertEquals(VacationRequestState::Approved, $vacationRequest->state); + $this->assertTrue($vacationRequest->state->equals(Approved::class)); } public function testAfterCreatingVacationRequestOfTypeTimeInLieuItTransitsToProperState(): void @@ -85,7 +87,7 @@ class VacationRequestStatesTest extends TestCase /** @var VacationRequest $vacationRequest */ $vacationRequest = VacationRequest::factory([ "type" => VacationType::TimeInLieu->value, - "state" => VacationRequestState::Created, + "state" => Created::class, "from" => Carbon::create($currentYearPeriod->year, 2, 2)->toDateString(), "to" => Carbon::create($currentYearPeriod->year, 2, 2)->toDateString(), ]) @@ -95,6 +97,6 @@ class VacationRequestStatesTest extends TestCase $this->stateManager->approve($vacationRequest); - $this->assertEquals(VacationRequestState::Approved, $vacationRequest->state); + $this->assertTrue($vacationRequest->state->equals(Approved::class)); } }