#63 - permissions (#67)

* wip

* fix

* wip

* #63 - permissions

Co-authored-by: EwelinaLasowy <ewelina.lasowy@blumilk.pl>
This commit is contained in:
Adrian Hopek 2022-03-02 09:52:50 +01:00 committed by GitHub
parent 5cb46d2fc4
commit d825dd727f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
47 changed files with 1027 additions and 411 deletions

View File

@ -5,13 +5,31 @@ declare(strict_types=1);
namespace Toby\Architecture\Providers; namespace Toby\Architecture\Providers;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider; use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Gate;
use Toby\Domain\Enums\Role;
use Toby\Domain\Policies\VacationRequestPolicy;
use Toby\Eloquent\Models\User;
use Toby\Eloquent\Models\VacationRequest;
class AuthServiceProvider extends ServiceProvider class AuthServiceProvider extends ServiceProvider
{ {
protected $policies = []; protected $policies = [
VacationRequest::class => VacationRequestPolicy::class,
];
public function boot(): void public function boot(): void
{ {
$this->registerPolicies(); $this->registerPolicies();
Gate::before(function (User $user) {
if ($user->role === Role::Administrator) {
return true;
}
});
Gate::define("manageUsers", fn(User $user) => $user->role === Role::AdministrativeApprover);
Gate::define("manageHolidays", fn(User $user) => $user->role === Role::AdministrativeApprover);
Gate::define("manageVacationLimits", fn(User $user) => $user->role === Role::AdministrativeApprover);
Gate::define("generateTimesheet", fn(User $user) => $user->role === Role::AdministrativeApprover);
} }
} }

View File

@ -5,9 +5,9 @@ declare(strict_types=1);
namespace Toby\Domain; namespace Toby\Domain;
use Carbon\CarbonPeriod; use Carbon\CarbonPeriod;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Carbon; use Illuminate\Support\Carbon;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Toby\Domain\Enums\VacationRequestState;
use Toby\Eloquent\Helpers\YearPeriodRetriever; use Toby\Eloquent\Helpers\YearPeriodRetriever;
use Toby\Eloquent\Models\Vacation; use Toby\Eloquent\Models\Vacation;
use Toby\Eloquent\Models\YearPeriod; use Toby\Eloquent\Models\YearPeriod;
@ -55,7 +55,7 @@ class CalendarGenerator
{ {
return Vacation::query() return Vacation::query()
->whereBetween("date", [$period->start, $period->end]) ->whereBetween("date", [$period->start, $period->end])
->whereRelation("vacationRequest", "state", VacationRequestState::Approved->value) ->whereRelation("vacationRequest", fn(Builder $query) => $query->states(VacationRequestStatesRetriever::successStates()))
->get() ->get()
->groupBy(fn(Vacation $vacation) => $vacation->date->toDateString()); ->groupBy(fn(Vacation $vacation) => $vacation->date->toDateString());
} }

View File

@ -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(),
};
}
}

View File

@ -6,7 +6,7 @@ namespace Toby\Domain\Events;
use Illuminate\Foundation\Events\Dispatchable; use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels; use Illuminate\Queue\SerializesModels;
use Toby\Domain\Enums\VacationRequestState; use Toby\Domain\States\VacationRequest\VacationRequestState;
use Toby\Eloquent\Models\User; use Toby\Eloquent\Models\User;
use Toby\Eloquent\Models\VacationRequest; use Toby\Eloquent\Models\VacationRequest;

View 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);
}
}

View File

@ -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";
}

View 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";
}

View File

@ -0,0 +1,10 @@
<?php
declare(strict_types=1);
namespace Toby\Domain\States\VacationRequest;
class Approved extends VacationRequestState
{
public static string $name = "approved";
}

View File

@ -0,0 +1,10 @@
<?php
declare(strict_types=1);
namespace Toby\Domain\States\VacationRequest;
class Cancelled extends VacationRequestState
{
public static string $name = "cancelled";
}

View File

@ -0,0 +1,10 @@
<?php
declare(strict_types=1);
namespace Toby\Domain\States\VacationRequest;
class Created extends VacationRequestState
{
public static string $name = "created";
}

View File

@ -0,0 +1,10 @@
<?php
declare(strict_types=1);
namespace Toby\Domain\States\VacationRequest;
class Rejected extends VacationRequestState
{
public static string $name = "rejected";
}

View 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);
}
}

View File

@ -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";
}

View 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";
}

View File

@ -6,15 +6,24 @@ namespace Toby\Domain;
use Illuminate\Contracts\Auth\Factory as Auth; use Illuminate\Contracts\Auth\Factory as Auth;
use Illuminate\Contracts\Events\Dispatcher; use Illuminate\Contracts\Events\Dispatcher;
use Toby\Domain\Enums\VacationRequestState;
use Toby\Domain\Events\VacationRequestAcceptedByAdministrative; use Toby\Domain\Events\VacationRequestAcceptedByAdministrative;
use Toby\Domain\Events\VacationRequestAcceptedByTechnical; use Toby\Domain\Events\VacationRequestAcceptedByTechnical;
use Toby\Domain\Events\VacationRequestApproved; use Toby\Domain\Events\VacationRequestApproved;
use Toby\Domain\Events\VacationRequestCancelled; use Toby\Domain\Events\VacationRequestCancelled;
use Toby\Domain\Events\VacationRequestCreated; use Toby\Domain\Events\VacationRequestCreated;
use Toby\Domain\Events\VacationRequestRejected; use Toby\Domain\Events\VacationRequestRejected;
use Toby\Domain\Events\VacationRequestStateChanged;
use Toby\Domain\Events\VacationRequestWaitsForAdminApproval; use Toby\Domain\Events\VacationRequestWaitsForAdminApproval;
use Toby\Domain\Events\VacationRequestWaitsForTechApproval; 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; use Toby\Eloquent\Models\VacationRequest;
class VacationRequestStateManager class VacationRequestStateManager
@ -25,64 +34,77 @@ class VacationRequestStateManager
) { ) {
} }
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)); $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)); $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)); $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)); $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)); $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)); $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)); $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)); $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);
} }
} }

View 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(),
};
}
}

View File

@ -6,9 +6,9 @@ namespace Toby\Domain\Validation\Rules;
use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Collection;
use Toby\Domain\Enums\VacationRequestState;
use Toby\Domain\Enums\VacationType; use Toby\Domain\Enums\VacationType;
use Toby\Domain\VacationDaysCalculator; use Toby\Domain\VacationDaysCalculator;
use Toby\Domain\VacationRequestStatesRetriever;
use Toby\Domain\VacationTypeConfigRetriever; use Toby\Domain\VacationTypeConfigRetriever;
use Toby\Eloquent\Models\User; use Toby\Eloquent\Models\User;
use Toby\Eloquent\Models\VacationRequest; use Toby\Eloquent\Models\VacationRequest;
@ -53,7 +53,7 @@ class DoesNotExceedLimitRule implements VacationRequestRule
"vacationRequest", "vacationRequest",
fn(Builder $query) => $query fn(Builder $query) => $query
->whereIn("type", $this->getLimitableVacationTypes()) ->whereIn("type", $this->getLimitableVacationTypes())
->noStates(VacationRequestState::failedStates()), ->noStates(VacationRequestStatesRetriever::failedStates()),
) )
->count(); ->count();
} }

View File

@ -4,7 +4,7 @@ declare(strict_types=1);
namespace Toby\Domain\Validation\Rules; namespace Toby\Domain\Validation\Rules;
use Toby\Domain\Enums\VacationRequestState; use Toby\Domain\VacationRequestStatesRetriever;
use Toby\Eloquent\Models\VacationRequest; use Toby\Eloquent\Models\VacationRequest;
class NoApprovedVacationRequestsInRange implements VacationRequestRule class NoApprovedVacationRequestsInRange implements VacationRequestRule
@ -15,7 +15,7 @@ class NoApprovedVacationRequestsInRange implements VacationRequestRule
->user ->user
->vacationRequests() ->vacationRequests()
->overlapsWith($vacationRequest) ->overlapsWith($vacationRequest)
->states(VacationRequestState::successStates()) ->states(VacationRequestStatesRetriever::successStates())
->exists(); ->exists();
} }

View File

@ -4,7 +4,7 @@ declare(strict_types=1);
namespace Toby\Domain\Validation\Rules; namespace Toby\Domain\Validation\Rules;
use Toby\Domain\Enums\VacationRequestState; use Toby\Domain\VacationRequestStatesRetriever;
use Toby\Eloquent\Models\VacationRequest; use Toby\Eloquent\Models\VacationRequest;
class NoPendingVacationRequestInRange implements VacationRequestRule class NoPendingVacationRequestInRange implements VacationRequestRule
@ -15,7 +15,7 @@ class NoPendingVacationRequestInRange implements VacationRequestRule
->user ->user
->vacationRequests() ->vacationRequests()
->overlapsWith($vacationRequest) ->overlapsWith($vacationRequest)
->states(VacationRequestState::pendingStates()) ->states(VacationRequestStatesRetriever::pendingStates())
->exists(); ->exists();
} }

View File

@ -12,8 +12,9 @@ use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Support\Carbon; use Illuminate\Support\Carbon;
use Illuminate\Support\Collection; use Illuminate\Support\Collection;
use Toby\Domain\Enums\VacationRequestState; use Spatie\ModelStates\HasStates;
use Toby\Domain\Enums\VacationType; use Toby\Domain\Enums\VacationType;
use Toby\Domain\States\VacationRequest\VacationRequestState;
/** /**
* @property int $id * @property int $id
@ -34,6 +35,7 @@ use Toby\Domain\Enums\VacationType;
class VacationRequest extends Model class VacationRequest extends Model
{ {
use HasFactory; use HasFactory;
use HasStates;
protected $guarded = []; protected $guarded = [];
@ -69,26 +71,14 @@ class VacationRequest extends Model
return $this->hasMany(Vacation::class); return $this->hasMany(Vacation::class);
} }
public function changeStateTo(VacationRequestState $state): void public function scopeStates(Builder $query, VacationRequestState|array $states): Builder
{ {
$this->state = $state; return $query->whereState("state", $states);
$this->save();
} }
public function hasFlowSkipped(): bool public function scopeNoStates(Builder $query, VacationRequestState|array $states): Builder
{ {
return $this->flow_skipped; return $query->whereNotState("state", $states);
}
public function scopeStates(Builder $query, array $states): Builder
{
return $query->whereIn("state", $states);
}
public function scopeNoStates(Builder $query, array $states): Builder
{
return $query->whereNotIn("state", $states);
} }
public function scopeOverlapsWith(Builder $query, self $vacationRequest): Builder public function scopeOverlapsWith(Builder $query, self $vacationRequest): Builder
@ -97,6 +87,11 @@ class VacationRequest extends Model
->where("to", ">=", $vacationRequest->from); ->where("to", ">=", $vacationRequest->from);
} }
public function hasFlowSkipped(): bool
{
return $this->flow_skipped;
}
protected static function newFactory(): VacationRequestFactory protected static function newFactory(): VacationRequestFactory
{ {
return VacationRequestFactory::new(); return VacationRequestFactory::new();

View File

@ -6,7 +6,7 @@ namespace Toby\Eloquent\Models;
use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Toby\Domain\Enums\VacationRequestState; use Toby\Domain\States\VacationRequest\VacationRequestState;
/** /**
* @property int $id * @property int $id

View File

@ -6,9 +6,6 @@ namespace Toby\Eloquent\Observers;
use Illuminate\Contracts\Auth\Factory as Auth; use Illuminate\Contracts\Auth\Factory as Auth;
use Illuminate\Contracts\Events\Dispatcher; use Illuminate\Contracts\Events\Dispatcher;
use Toby\Domain\Enums\VacationRequestState;
use Toby\Domain\Events\VacationRequestStateChanged;
use Toby\Eloquent\Models\User;
use Toby\Eloquent\Models\VacationRequest; use Toby\Eloquent\Models\VacationRequest;
class VacationRequestObserver class VacationRequestObserver
@ -29,31 +26,4 @@ class VacationRequestObserver
$vacationRequest->name = "{$vacationRequestNumber}/${year}"; $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;
}
} }

View File

@ -4,7 +4,9 @@ declare(strict_types=1);
namespace Toby\Infrastructure\Http\Controllers; namespace Toby\Infrastructure\Http\Controllers;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Http\RedirectResponse; use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Inertia\Response; use Inertia\Response;
use Toby\Eloquent\Models\Holiday; use Toby\Eloquent\Models\Holiday;
use Toby\Infrastructure\Http\Requests\HolidayRequest; use Toby\Infrastructure\Http\Requests\HolidayRequest;
@ -13,7 +15,7 @@ use Toby\Infrastructure\Http\Resources\HolidayResource;
class HolidayController extends Controller class HolidayController extends Controller
{ {
public function index(): Response public function index(Request $request): Response
{ {
$holidays = Holiday::query() $holidays = Holiday::query()
->orderBy("date") ->orderBy("date")
@ -21,16 +23,29 @@ class HolidayController extends Controller
return inertia("Holidays/Index", [ return inertia("Holidays/Index", [
"holidays" => HolidayResource::collection($holidays), "holidays" => HolidayResource::collection($holidays),
"can" => [
"manageHolidays" => $request->user()->can("manageHolidays"),
],
]); ]);
} }
/**
* @throws AuthorizationException
*/
public function create(): Response public function create(): Response
{ {
$this->authorize("manageHolidays");
return inertia("Holidays/Create"); return inertia("Holidays/Create");
} }
/**
* @throws AuthorizationException
*/
public function store(HolidayRequest $request): RedirectResponse public function store(HolidayRequest $request): RedirectResponse
{ {
$this->authorize("manageHolidays");
Holiday::query()->create($request->data()); Holiday::query()->create($request->data());
return redirect() return redirect()
@ -38,15 +53,25 @@ class HolidayController extends Controller
->with("success", __("Holiday has been created.")); ->with("success", __("Holiday has been created."));
} }
/**
* @throws AuthorizationException
*/
public function edit(Holiday $holiday): Response public function edit(Holiday $holiday): Response
{ {
$this->authorize("manageHolidays");
return inertia("Holidays/Edit", [ return inertia("Holidays/Edit", [
"holiday" => new HolidayFormDataResource($holiday), "holiday" => new HolidayFormDataResource($holiday),
]); ]);
} }
/**
* @throws AuthorizationException
*/
public function update(HolidayRequest $request, Holiday $holiday): RedirectResponse public function update(HolidayRequest $request, Holiday $holiday): RedirectResponse
{ {
$this->authorize("manageHolidays");
$holiday->update($request->data()); $holiday->update($request->data());
return redirect() return redirect()
@ -54,8 +79,13 @@ class HolidayController extends Controller
->with("success", __("Holiday has been updated.")); ->with("success", __("Holiday has been updated."));
} }
/**
* @throws AuthorizationException
*/
public function destroy(Holiday $holiday): RedirectResponse public function destroy(Holiday $holiday): RedirectResponse
{ {
$this->authorize("manageHolidays");
$holiday->delete(); $holiday->delete();
return redirect() return redirect()

View File

@ -16,6 +16,8 @@ class TimesheetController extends Controller
{ {
public function __invoke(Month $month, YearPeriodRetriever $yearPeriodRetriever): BinaryFileResponse public function __invoke(Month $month, YearPeriodRetriever $yearPeriodRetriever): BinaryFileResponse
{ {
$this->authorize("generateTimesheet");
$yearPeriod = $yearPeriodRetriever->selected(); $yearPeriod = $yearPeriodRetriever->selected();
$carbonMonth = Carbon::create($yearPeriod->year, $month->toCarbonNumber()); $carbonMonth = Carbon::create($yearPeriod->year, $month->toCarbonNumber());

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace Toby\Infrastructure\Http\Controllers; namespace Toby\Infrastructure\Http\Controllers;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Http\RedirectResponse; use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Inertia\Response; use Inertia\Response;
@ -16,8 +17,13 @@ use Toby\Infrastructure\Http\Resources\UserResource;
class UserController extends Controller class UserController extends Controller
{ {
/**
* @throws AuthorizationException
*/
public function index(Request $request): Response public function index(Request $request): Response
{ {
$this->authorize("manageUsers");
$users = User::query() $users = User::query()
->withTrashed() ->withTrashed()
->search($request->query("search")) ->search($request->query("search"))
@ -32,16 +38,26 @@ class UserController extends Controller
]); ]);
} }
/**
* @throws AuthorizationException
*/
public function create(): Response public function create(): Response
{ {
$this->authorize("manageUsers");
return inertia("Users/Create", [ return inertia("Users/Create", [
"employmentForms" => EmploymentForm::casesToSelect(), "employmentForms" => EmploymentForm::casesToSelect(),
"roles" => Role::casesToSelect(), "roles" => Role::casesToSelect(),
]); ]);
} }
/**
* @throws AuthorizationException
*/
public function store(UserRequest $request): RedirectResponse public function store(UserRequest $request): RedirectResponse
{ {
$this->authorize("manageUsers");
User::query()->create($request->data()); User::query()->create($request->data());
return redirect() return redirect()
@ -49,8 +65,13 @@ class UserController extends Controller
->with("success", __("User has been created.")); ->with("success", __("User has been created."));
} }
/**
* @throws AuthorizationException
*/
public function edit(User $user): Response public function edit(User $user): Response
{ {
$this->authorize("manageUsers");
return inertia("Users/Edit", [ return inertia("Users/Edit", [
"user" => new UserFormDataResource($user), "user" => new UserFormDataResource($user),
"employmentForms" => EmploymentForm::casesToSelect(), "employmentForms" => EmploymentForm::casesToSelect(),
@ -58,8 +79,13 @@ class UserController extends Controller
]); ]);
} }
/**
* @throws AuthorizationException
*/
public function update(UserRequest $request, User $user): RedirectResponse public function update(UserRequest $request, User $user): RedirectResponse
{ {
$this->authorize("manageUsers");
$user->update($request->data()); $user->update($request->data());
return redirect() return redirect()
@ -67,8 +93,13 @@ class UserController extends Controller
->with("success", __("User has been updated.")); ->with("success", __("User has been updated."));
} }
/**
* @throws AuthorizationException
*/
public function destroy(User $user): RedirectResponse public function destroy(User $user): RedirectResponse
{ {
$this->authorize("manageUsers");
$user->delete(); $user->delete();
return redirect() return redirect()
@ -76,8 +107,13 @@ class UserController extends Controller
->with("success", __("User has been deleted.")); ->with("success", __("User has been deleted."));
} }
/**
* @throws AuthorizationException
*/
public function restore(User $user): RedirectResponse public function restore(User $user): RedirectResponse
{ {
$this->authorize("manageUsers");
$user->restore(); $user->restore();
return redirect() return redirect()

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace Toby\Infrastructure\Http\Controllers; namespace Toby\Infrastructure\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon; use Illuminate\Support\Carbon;
use Inertia\Response; use Inertia\Response;
use Toby\Domain\CalendarGenerator; use Toby\Domain\CalendarGenerator;
@ -15,6 +16,7 @@ use Toby\Infrastructure\Http\Resources\UserResource;
class VacationCalendarController extends Controller class VacationCalendarController extends Controller
{ {
public function index( public function index(
Request $request,
YearPeriodRetriever $yearPeriodRetriever, YearPeriodRetriever $yearPeriodRetriever,
CalendarGenerator $calendarGenerator, CalendarGenerator $calendarGenerator,
?string $month = null, ?string $month = null,
@ -35,6 +37,9 @@ class VacationCalendarController extends Controller
"calendar" => $calendar, "calendar" => $calendar,
"currentMonth" => $month->value, "currentMonth" => $month->value,
"users" => UserResource::collection($users), "users" => UserResource::collection($users),
"can" => [
"generateTimesheet" => $request->user()->can("generateTimesheet"),
],
]); ]);
} }
} }

View File

@ -14,6 +14,8 @@ class VacationLimitController extends Controller
{ {
public function edit(): Response public function edit(): Response
{ {
$this->authorize("manageVacationLimits");
$limits = VacationLimit::query() $limits = VacationLimit::query()
->with("user") ->with("user")
->orderByUserField("last_name") ->orderByUserField("last_name")
@ -27,6 +29,8 @@ class VacationLimitController extends Controller
public function update(VacationLimitRequest $request): RedirectResponse public function update(VacationLimitRequest $request): RedirectResponse
{ {
$this->authorize("manageVacationLimits");
$data = $request->data(); $data = $request->data();
foreach ($request->vacationLimits() as $limit) { foreach ($request->vacationLimits() as $limit) {

View File

@ -5,14 +5,20 @@ declare(strict_types=1);
namespace Toby\Infrastructure\Http\Controllers; namespace Toby\Infrastructure\Http\Controllers;
use Barryvdh\DomPDF\Facade\Pdf; use Barryvdh\DomPDF\Facade\Pdf;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Http\RedirectResponse; use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request; use Illuminate\Http\Request;
use Illuminate\Http\Response as LaravelResponse; use Illuminate\Http\Response as LaravelResponse;
use Illuminate\Validation\ValidationException;
use Inertia\Response; use Inertia\Response;
use Toby\Domain\Enums\VacationRequestState;
use Toby\Domain\Enums\VacationType; 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\VacationDaysCalculator;
use Toby\Domain\VacationRequestStateManager; use Toby\Domain\VacationRequestStateManager;
use Toby\Domain\VacationRequestStatesRetriever;
use Toby\Domain\Validation\VacationRequestValidator; use Toby\Domain\Validation\VacationRequestValidator;
use Toby\Eloquent\Helpers\YearPeriodRetriever; use Toby\Eloquent\Helpers\YearPeriodRetriever;
use Toby\Eloquent\Models\User; use Toby\Eloquent\Models\User;
@ -33,7 +39,7 @@ class VacationRequestController extends Controller
->with("vacations") ->with("vacations")
->where("year_period_id", $yearPeriodRetriever->selected()->id) ->where("year_period_id", $yearPeriodRetriever->selected()->id)
->latest() ->latest()
->states(VacationRequestState::filterByStatus($status)) ->states(VacationRequestStatesRetriever::filterByStatus($status))
->paginate(); ->paginate();
return inertia("VacationRequest/Index", [ return inertia("VacationRequest/Index", [
@ -44,16 +50,37 @@ class VacationRequestController extends Controller
]); ]);
} }
public function show(VacationRequest $vacationRequest): Response /**
* @throws AuthorizationException
*/
public function show(Request $request, VacationRequest $vacationRequest): Response
{ {
$this->authorize("show", $vacationRequest);
$user = $request->user();
return inertia("VacationRequest/Show", [ return inertia("VacationRequest/Show", [
"request" => new VacationRequestResource($vacationRequest), "request" => new VacationRequestResource($vacationRequest),
"activities" => VacationRequestActivityResource::collection($vacationRequest->activities), "activities" => VacationRequestActivityResource::collection($vacationRequest->activities),
"can" => [
"acceptAsTechnical" => $vacationRequest->state->canTransitionTo(AcceptedByTechnical::class)
&& $user->can("acceptAsTechApprover", $vacationRequest),
"acceptAsAdministrative" => $vacationRequest->state->canTransitionTo(AcceptedByAdministrative::class)
&& $user->can("acceptAsAdminApprover", $vacationRequest),
"reject" => $vacationRequest->state->canTransitionTo(Rejected::class)
&& $user->can("reject", $vacationRequest),
"cancel" => $vacationRequest->state->canTransitionTo(Cancelled::class)
&& $user->can("cancel", $vacationRequest),
],
]); ]);
} }
/**
* @throws AuthorizationException
*/
public function download(VacationRequest $vacationRequest): LaravelResponse public function download(VacationRequest $vacationRequest): LaravelResponse
{ {
$this->authorize("show", $vacationRequest);
$pdf = PDF::loadView("pdf.vacation-request", [ $pdf = PDF::loadView("pdf.vacation-request", [
"vacationRequest" => $vacationRequest, "vacationRequest" => $vacationRequest,
]); ]);
@ -61,7 +88,7 @@ class VacationRequestController extends Controller
return $pdf->stream(); return $pdf->stream();
} }
public function create(): Response public function create(Request $request): Response
{ {
$users = User::query() $users = User::query()
->orderBy("last_name") ->orderBy("last_name")
@ -71,15 +98,31 @@ class VacationRequestController extends Controller
return inertia("VacationRequest/Create", [ return inertia("VacationRequest/Create", [
"vacationTypes" => VacationType::casesToSelect(), "vacationTypes" => VacationType::casesToSelect(),
"users" => UserResource::collection($users), "users" => UserResource::collection($users),
"can" => [
"createOnBehalfOfEmployee" => $request->user()->can("createOnBehalfOfEmployee", VacationRequest::class),
"skipFlow" => $request->user()->can("skipFlow", VacationRequest::class),
],
]); ]);
} }
/**
* @throws AuthorizationException
* @throws ValidationException
*/
public function store( public function store(
VacationRequestRequest $request, VacationRequestRequest $request,
VacationRequestValidator $vacationRequestValidator, VacationRequestValidator $vacationRequestValidator,
VacationRequestStateManager $stateManager, VacationRequestStateManager $stateManager,
VacationDaysCalculator $vacationDaysCalculator, VacationDaysCalculator $vacationDaysCalculator,
): RedirectResponse { ): RedirectResponse {
if ($request->createsOnBehalfOfEmployee()) {
$this->authorize("createOnBehalfOfEmployee", VacationRequest::class);
}
if ($request->wantsSkipFlow()) {
$this->authorize("skipFlow", VacationRequest::class);
}
/** @var VacationRequest $vacationRequest */ /** @var VacationRequest $vacationRequest */
$vacationRequest = $request->user()->createdVacationRequests()->make($request->data()); $vacationRequest = $request->user()->createdVacationRequests()->make($request->data());
$vacationRequestValidator->validate($vacationRequest); $vacationRequestValidator->validate($vacationRequest);
@ -100,48 +143,72 @@ class VacationRequestController extends Controller
]); ]);
} }
$stateManager->markAsCreated($vacationRequest); $stateManager->markAsCreated($vacationRequest, $request->user());
return redirect() return redirect()
->route("vacation.requests.show", $vacationRequest) ->route("vacation.requests.show", $vacationRequest)
->with("success", __("Vacation request has been created.")); ->with("success", __("Vacation request has been created."));
} }
/**
* @throws AuthorizationException
*/
public function reject( public function reject(
Request $request,
VacationRequest $vacationRequest, VacationRequest $vacationRequest,
VacationRequestStateManager $stateManager, VacationRequestStateManager $stateManager,
): RedirectResponse { ): RedirectResponse {
$stateManager->reject($vacationRequest); $this->authorize("reject", $vacationRequest);
$stateManager->reject($vacationRequest, $request->user());
return redirect()->back() return redirect()->back()
->with("success", __("Vacation request has been rejected.")); ->with("success", __("Vacation request has been rejected."));
} }
/**
* @throws AuthorizationException
*/
public function cancel( public function cancel(
Request $request,
VacationRequest $vacationRequest, VacationRequest $vacationRequest,
VacationRequestStateManager $stateManager, VacationRequestStateManager $stateManager,
): RedirectResponse { ): RedirectResponse {
$stateManager->cancel($vacationRequest); $this->authorize("cancel", $vacationRequest);
$stateManager->cancel($vacationRequest, $request->user());
return redirect()->back() return redirect()->back()
->with("success", __("Vacation request has been cancelled.")); ->with("success", __("Vacation request has been cancelled."));
} }
/**
* @throws AuthorizationException
*/
public function acceptAsTechnical( public function acceptAsTechnical(
Request $request,
VacationRequest $vacationRequest, VacationRequest $vacationRequest,
VacationRequestStateManager $stateManager, VacationRequestStateManager $stateManager,
): RedirectResponse { ): RedirectResponse {
$stateManager->acceptAsTechnical($vacationRequest); $this->authorize("acceptAsTechApprover", $vacationRequest);
$stateManager->acceptAsTechnical($vacationRequest, $request->user());
return redirect()->back() return redirect()->back()
->with("success", __("Vacation request has been accepted.")); ->with("success", __("Vacation request has been accepted."));
} }
/**
* @throws AuthorizationException
*/
public function acceptAsAdministrative( public function acceptAsAdministrative(
Request $request,
VacationRequest $vacationRequest, VacationRequest $vacationRequest,
VacationRequestStateManager $stateManager, VacationRequestStateManager $stateManager,
): RedirectResponse { ): RedirectResponse {
$stateManager->acceptAsAdministrative($vacationRequest); $this->authorize("acceptAsAdminApprover", $vacationRequest);
$stateManager->acceptAsAdministrative($vacationRequest, $request->user());
return redirect()->back() return redirect()->back()
->with("success", __("Vacation request has been accepted.")); ->with("success", __("Vacation request has been accepted."));

View File

@ -23,6 +23,10 @@ class HandleInertiaRequests extends Middleware
return array_merge(parent::share($request), [ return array_merge(parent::share($request), [
"auth" => fn() => [ "auth" => fn() => [
"user" => $user ? new UserResource($user) : null, "user" => $user ? new UserResource($user) : null,
"can" => [
"manageVacationLimits" => $user ? $user->can("manageVacationLimits") : false,
"manageUsers" => $user ? $user->can("manageUsers") : false,
],
], ],
"flash" => fn() => [ "flash" => fn() => [
"success" => $request->session()->get("success"), "success" => $request->session()->get("success"),

View File

@ -27,16 +27,29 @@ class VacationRequestRequest extends FormRequest
public function data(): array public function data(): array
{ {
$from = $this->get("from");
return [ return [
"user_id" => $this->get("user"), "user_id" => $this->get("user"),
"type" => $this->get("type"), "type" => $this->get("type"),
"from" => $from, "from" => $this->get("from"),
"to" => $this->get("to"), "to" => $this->get("to"),
"year_period_id" => YearPeriod::findByYear(Carbon::create($from)->year)->id, "year_period_id" => $this->yearPeriod()->id,
"comment" => $this->get("comment"), "comment" => $this->get("comment"),
"flow_skipped" => $this->boolean("flowSkipped"), "flow_skipped" => $this->boolean("flowSkipped"),
]; ];
} }
public function yearPeriod(): YearPeriod
{
return YearPeriod::findByYear(Carbon::create($this->get("from"))->year);
}
public function createsOnBehalfOfEmployee(): bool
{
return $this->user()->id !== $this->get("user");
}
public function wantsSkipFlow(): bool
{
return $this->boolean("flowSkipped");
}
} }

View File

@ -17,7 +17,6 @@ class VacationRequestActivityResource extends JsonResource
"time" => $this->created_at->format("H:i"), "time" => $this->created_at->format("H:i"),
"user" => $this->user ? $this->user->fullName : __("System"), "user" => $this->user ? $this->user->fullName : __("System"),
"state" => $this->to, "state" => $this->to,
"text" => $this->to->label(),
]; ];
} }
} }

View File

@ -18,8 +18,9 @@
"laravel/telescope": "^4.6", "laravel/telescope": "^4.6",
"laravel/tinker": "^2.5", "laravel/tinker": "^2.5",
"lasserafn/php-initial-avatar-generator": "^4.2", "lasserafn/php-initial-avatar-generator": "^4.2",
"maatwebsite/excel": "^3.1", "spatie/laravel-google-calendar": "^3.5",
"spatie/laravel-google-calendar": "^3.5" "spatie/laravel-model-states": "^2.1",
"maatwebsite/excel": "^3.1"
}, },
"require-dev": { "require-dev": {
"blumilksoftware/codestyle": "^0.9.0", "blumilksoftware/codestyle": "^0.9.0",

592
composer.lock generated

File diff suppressed because it is too large Load Diff

7
config/model-states.php Normal file
View File

@ -0,0 +1,7 @@
<?php
declare(strict_types=1);
return [
"default_transition" => Spatie\ModelStates\DefaultTransition::class,
];

View File

@ -28,4 +28,25 @@ class UserFactory extends Factory
"remember_token" => Str::random(10), "remember_token" => Str::random(10),
]; ];
} }
public function admin(): static
{
return $this->state([
"role" => Role::Administrator,
]);
}
public function technicalApprover(): static
{
return $this->state([
"role" => Role::TechnicalApprover,
]);
}
public function administrativeApprover(): static
{
return $this->state([
"role" => Role::AdministrativeApprover,
]);
}
} }

View File

@ -6,8 +6,8 @@ namespace Database\Factories;
use Carbon\CarbonImmutable; use Carbon\CarbonImmutable;
use Illuminate\Database\Eloquent\Factories\Factory; use Illuminate\Database\Eloquent\Factories\Factory;
use Toby\Domain\Enums\VacationRequestState;
use Toby\Domain\Enums\VacationType; use Toby\Domain\Enums\VacationType;
use Toby\Domain\VacationRequestStatesRetriever;
use Toby\Eloquent\Models\User; use Toby\Eloquent\Models\User;
use Toby\Eloquent\Models\VacationRequest; use Toby\Eloquent\Models\VacationRequest;
use Toby\Eloquent\Models\YearPeriod; use Toby\Eloquent\Models\YearPeriod;
@ -28,7 +28,7 @@ class VacationRequestFactory extends Factory
"year_period_id" => YearPeriod::factory(), "year_period_id" => YearPeriod::factory(),
"name" => fn(array $attributes): string => $this->generateName($attributes), "name" => fn(array $attributes): string => $this->generateName($attributes),
"type" => $this->faker->randomElement(VacationType::cases()), "type" => $this->faker->randomElement(VacationType::cases()),
"state" => $this->faker->randomElement(VacationRequestState::cases()), "state" => $this->faker->randomElement(VacationRequestStatesRetriever::all()),
"from" => $from, "from" => $from,
"to" => $from->addDays($days), "to" => $from->addDays($days),
"comment" => $this->faker->boolean ? $this->faker->paragraph() : null, "comment" => $this->faker->boolean ? $this->faker->paragraph() : null,

View File

@ -7,7 +7,7 @@
Kalendarz urlopów Kalendarz urlopów
</h2> </h2>
</div> </div>
<div> <div v-if="can.generateTimesheet">
<a <a
:href="`/timesheet/${selectedMonth.value}`" :href="`/timesheet/${selectedMonth.value}`"
class="inline-flex items-center px-4 py-3 border border-transparent text-sm leading-4 font-medium rounded-md shadow-sm text-white bg-blumilk-600 hover:bg-blumilk-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blumilk-500" class="inline-flex items-center px-4 py-3 border border-transparent text-sm leading-4 font-medium rounded-md shadow-sm text-white bg-blumilk-600 hover:bg-blumilk-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blumilk-500"
@ -164,6 +164,10 @@ export default {
type: Object, type: Object,
default: () => null, default: () => null,
}, },
can: {
type: Object,
default: () => null,
},
}, },
setup(props) { setup(props) {
const {getMonths, findMonth} = useMonthInfo() const {getMonths, findMonth} = useMonthInfo()

View File

@ -10,7 +10,7 @@
Lista dni wolnych od pracy w danym roku Lista dni wolnych od pracy w danym roku
</p> </p>
</div> </div>
<div> <div v-if="can.manageHolidays">
<InertiaLink <InertiaLink
href="holidays/create" href="holidays/create"
class="inline-flex items-center px-4 py-3 border border-transparent text-sm leading-4 font-medium rounded-md shadow-sm text-white bg-blumilk-600 hover:bg-blumilk-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blumilk-500" class="inline-flex items-center px-4 py-3 border border-transparent text-sm leading-4 font-medium rounded-md shadow-sm text-white bg-blumilk-600 hover:bg-blumilk-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blumilk-500"
@ -65,6 +65,7 @@
</td> </td>
<td class="px-4 py-4 whitespace-nowrap text-sm text-gray-500 text-right"> <td class="px-4 py-4 whitespace-nowrap text-sm text-gray-500 text-right">
<Menu <Menu
v-if="can.manageHolidays"
as="div" as="div"
class="relative inline-block text-left" class="relative inline-block text-left"
> >
@ -159,6 +160,10 @@ export default {
type: Object, type: Object,
default: () => null, default: () => null,
}, },
can: {
type: Object,
default: () => null,
},
}, },
setup() { setup() {
return {} return {}

View File

@ -29,6 +29,7 @@
</div> </div>
</div> </div>
<Listbox <Listbox
v-if="can.createOnBehalfOfEmployee"
v-model="form.user" v-model="form.user"
as="div" as="div"
class="sm:grid sm:grid-cols-3 py-4 items-center" class="sm:grid sm:grid-cols-3 py-4 items-center"
@ -231,7 +232,10 @@
/> />
</div> </div>
</div> </div>
<div class="sm:grid sm:grid-cols-3 py-4 items-center"> <div
v-if="can.skipFlow"
class="sm:grid sm:grid-cols-3 py-4 items-center"
>
<label <label
for="flowSkipped" for="flowSkipped"
class="block text-sm font-medium text-gray-700" class="block text-sm font-medium text-gray-700"
@ -311,10 +315,16 @@ export default {
type: Object, type: Object,
default: () => null, default: () => null,
}, },
can: {
type: Object,
default: () => null,
},
}, },
setup(props) { setup(props) {
const form = useForm({ const form = useForm({
user: props.users.data.find(user => user.id === props.auth.user.id), user: props.can.createOnBehalfOfEmployee
? props.users.data.find(user => user.id === props.auth.user.id)
: props.auth.user,
from: null, from: null,
to: null, to: null,
type: props.vacationTypes[0], type: props.vacationTypes[0],

View File

@ -110,7 +110,10 @@
</dl> </dl>
</div> </div>
</div> </div>
<div class="bg-white shadow"> <div
v-if="can.acceptAsTechnical"
class="bg-white shadow"
>
<div class="px-4 py-5 sm:p-6"> <div class="px-4 py-5 sm:p-6">
<h3 class="text-lg leading-6 font-medium text-gray-900"> <h3 class="text-lg leading-6 font-medium text-gray-900">
Zaakceptuj wniosek jako osoba techniczna Zaakceptuj wniosek jako osoba techniczna
@ -134,7 +137,10 @@
</div> </div>
</div> </div>
</div> </div>
<div class="bg-white shadow"> <div
v-if="can.acceptAsAdministrative"
class="bg-white shadow"
>
<div class="px-4 py-5 sm:p-6"> <div class="px-4 py-5 sm:p-6">
<h3 class="text-lg leading-6 font-medium text-gray-900"> <h3 class="text-lg leading-6 font-medium text-gray-900">
Zaakceptuj wniosek jako osoba administracyjna Zaakceptuj wniosek jako osoba administracyjna
@ -157,7 +163,10 @@
</div> </div>
</div> </div>
</div> </div>
<div class="bg-white shadow"> <div
v-if="can.reject"
class="bg-white shadow"
>
<div class="px-4 py-5 sm:p-6"> <div class="px-4 py-5 sm:p-6">
<h3 class="text-lg leading-6 font-medium text-gray-900"> <h3 class="text-lg leading-6 font-medium text-gray-900">
Odrzuć wniosek Odrzuć wniosek
@ -180,7 +189,10 @@
</div> </div>
</div> </div>
</div> </div>
<div class="bg-white shadow border border-red-500"> <div
v-if="can.cancel"
class="bg-white shadow border border-red-500"
>
<div class="px-4 py-5 sm:p-6"> <div class="px-4 py-5 sm:p-6">
<h3 class="text-lg leading-6 font-medium text-gray-900"> <h3 class="text-lg leading-6 font-medium text-gray-900">
Anuluj wniosek Anuluj wniosek
@ -246,6 +258,10 @@ export default {
type: Object, type: Object,
default: () => null, default: () => null,
}, },
can: {
type: Object,
default: () => null,
},
activities: { activities: {
type: Object, type: Object,
default: () => null, default: () => null,

View File

@ -213,12 +213,12 @@
> >
<img <img
class="h-8 w-8 rounded-full" class="h-8 w-8 rounded-full"
:src="user.avatar" :src="auth.user.avatar"
alt="Avatar" alt="Avatar"
> >
<span class="hidden ml-3 text-gray-700 text-sm font-medium lg:block"> <span class="hidden ml-3 text-gray-700 text-sm font-medium lg:block">
<span class="sr-only">Open user menu for </span> <span class="sr-only">Open user menu for </span>
{{ user.name }} {{ auth.user.name }}
</span> </span>
<ChevronDownIcon <ChevronDownIcon
class="hidden flex-shrink-0 ml-1 h-5 w-5 text-gray-400 lg:block" class="hidden flex-shrink-0 ml-1 h-5 w-5 text-gray-400 lg:block"
@ -324,16 +324,17 @@ export default {
setup() { setup() {
const sidebarOpen = ref(false) const sidebarOpen = ref(false)
const user = computed(() => usePage().props.value.auth.user) const auth = computed(() => usePage().props.value.auth)
const years = computed(() => usePage().props.value.years) const years = computed(() => usePage().props.value.years)
const navigation = [ const navigation = computed(() =>
{name: 'Wnioski urlopowe', href: '/vacation-requests', icon: CollectionIcon}, [
{name: 'Kalendarz urlopów', href: '/vacation-calendar', icon: CalendarIcon}, {name: 'Wnioski urlopowe', href: '/vacation-requests', icon: CollectionIcon, can: true},
{name: 'Dni wolne', href: '/holidays', icon: StarIcon}, {name: 'Kalendarz urlopów', href: '/vacation-calendar', icon: CalendarIcon, can: true},
{name: 'Limity urlopów', href: '/vacation-limits', icon: SunIcon}, {name: 'Dni wolne', href: '/holidays', icon: StarIcon, can: true},
{name: 'Użytkownicy', href: '/users', icon: UserGroupIcon}, {name: 'Limity urlopów', href: '/vacation-limits', icon: SunIcon, can: auth.value.can.manageVacationLimits},
] {name: 'Użytkownicy', href: '/users', icon: UserGroupIcon, can: auth.value.can.manageUsers},
].filter(item => item.can))
const userNavigation = [ const userNavigation = [
{name: 'Your Profile', href: '#'}, {name: 'Your Profile', href: '#'},
@ -342,7 +343,7 @@ export default {
] ]
return { return {
user, auth,
years, years,
navigation, navigation,
userNavigation, userNavigation,

View File

@ -34,7 +34,8 @@ class HolidayTest extends FeatureTestCase
public function testAdminCanCreateHoliday(): void public function testAdminCanCreateHoliday(): void
{ {
$admin = User::factory()->create(); $admin = User::factory()->admin()->create();
$currentYearPeriod = YearPeriod::current(); $currentYearPeriod = YearPeriod::current();
$this->actingAs($admin) $this->actingAs($admin)
@ -53,7 +54,8 @@ class HolidayTest extends FeatureTestCase
public function testAdminCannotCreateHolidayForYearPeriodThatDoesntExist(): void public function testAdminCannotCreateHolidayForYearPeriodThatDoesntExist(): void
{ {
$admin = User::factory()->create(); $admin = User::factory()->admin()->create();
$year = YearPeriod::query()->max("year") + 1; $year = YearPeriod::query()->max("year") + 1;
$this->actingAs($admin) $this->actingAs($admin)
@ -66,7 +68,8 @@ class HolidayTest extends FeatureTestCase
public function testAdminCannotCreateHolidayIfGivenDataIsUsed(): void public function testAdminCannotCreateHolidayIfGivenDataIsUsed(): void
{ {
$admin = User::factory()->create(); $admin = User::factory()->admin()->create();
$currentYearPeriod = YearPeriod::current(); $currentYearPeriod = YearPeriod::current();
$sameDate = Carbon::create($currentYearPeriod->year, 5, 20)->toDateString(); $sameDate = Carbon::create($currentYearPeriod->year, 5, 20)->toDateString();
@ -85,7 +88,8 @@ class HolidayTest extends FeatureTestCase
public function testAdminCanEditHoliday(): void public function testAdminCanEditHoliday(): void
{ {
$admin = User::factory()->create(); $admin = User::factory()->admin()->create();
$currentYearPeriod = YearPeriod::current(); $currentYearPeriod = YearPeriod::current();
$holiday = Holiday::factory()->create([ $holiday = Holiday::factory()->create([
@ -115,7 +119,8 @@ class HolidayTest extends FeatureTestCase
public function testAdminCanDeleteHoliday(): void public function testAdminCanDeleteHoliday(): void
{ {
$admin = User::factory()->create(); $admin = User::factory()->admin()->create();
$holiday = Holiday::factory()->create(); $holiday = Holiday::factory()->create();
$this->actingAs($admin) $this->actingAs($admin)

View File

@ -19,7 +19,7 @@ class UserTest extends FeatureTestCase
public function testAdminCanSeeUsersList(): void public function testAdminCanSeeUsersList(): void
{ {
User::factory()->count(10)->create(); User::factory()->count(10)->create();
$admin = User::factory()->create(); $admin = User::factory()->admin()->create();
$this->assertDatabaseCount("users", 11); $this->assertDatabaseCount("users", 11);
@ -38,18 +38,21 @@ class UserTest extends FeatureTestCase
"first_name" => "Test", "first_name" => "Test",
"last_name" => "User1", "last_name" => "User1",
])->create(); ])->create();
User::factory([ User::factory([
"first_name" => "Test", "first_name" => "Test",
"last_name" => "User2", "last_name" => "User2",
])->create(); ])->create();
User::factory([ User::factory([
"first_name" => "Test", "first_name" => "Test",
"last_name" => "User3", "last_name" => "User3",
])->create(); ])->create();
$admin = User::factory([ $admin = User::factory([
"first_name" => "John", "first_name" => "John",
"last_name" => "Doe", "last_name" => "Doe",
])->create(); ])->admin()->create();
$this->assertDatabaseCount("users", 4); $this->assertDatabaseCount("users", 4);
@ -66,7 +69,7 @@ class UserTest extends FeatureTestCase
public function testUserListIsPaginated(): void public function testUserListIsPaginated(): void
{ {
User::factory()->count(15)->create(); User::factory()->count(15)->create();
$admin = User::factory()->create(); $admin = User::factory()->admin()->create();
$this->assertDatabaseCount("users", 16); $this->assertDatabaseCount("users", 16);
@ -81,7 +84,7 @@ class UserTest extends FeatureTestCase
public function testAdminCanCreateUser(): void public function testAdminCanCreateUser(): void
{ {
$admin = User::factory()->create(); $admin = User::factory()->admin()->create();
Carbon::setTestNow(Carbon::now()); Carbon::setTestNow(Carbon::now());
$this->actingAs($admin) $this->actingAs($admin)
@ -109,7 +112,8 @@ class UserTest extends FeatureTestCase
public function testAdminCanEditUser(): void public function testAdminCanEditUser(): void
{ {
$admin = User::factory()->create(); $admin = User::factory()->admin()->create();
$user = User::factory()->create(); $user = User::factory()->create();
Carbon::setTestNow(); Carbon::setTestNow();
@ -147,7 +151,8 @@ class UserTest extends FeatureTestCase
public function testAdminCanDeleteUser(): void public function testAdminCanDeleteUser(): void
{ {
$admin = User::factory()->create(); $admin = User::factory()->admin()->create();
$user = User::factory()->create(); $user = User::factory()->create();
$this->actingAs($admin) $this->actingAs($admin)
@ -159,7 +164,8 @@ class UserTest extends FeatureTestCase
public function testAdminCanRestoreUser(): void public function testAdminCanRestoreUser(): void
{ {
$admin = User::factory()->create(); $admin = User::factory()->admin()->create();
$user = User::factory()->create(); $user = User::factory()->create();
$user->delete(); $user->delete();

View File

@ -16,7 +16,7 @@ class VacationLimitTest extends FeatureTestCase
public function testAdminCanSeeVacationLimits(): void public function testAdminCanSeeVacationLimits(): void
{ {
$admin = User::factory()->createQuietly(); $admin = User::factory()->admin()->createQuietly();
User::factory(10)->create(); User::factory(10)->create();
@ -32,7 +32,7 @@ class VacationLimitTest extends FeatureTestCase
public function testAdminCanUpdateVacationLimits(): void public function testAdminCanUpdateVacationLimits(): void
{ {
$admin = User::factory()->createQuietly(); $admin = User::factory()->admin()->createQuietly();
User::factory(3)->create(); User::factory(3)->create();

View File

@ -9,13 +9,16 @@ use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Event; use Illuminate\Support\Facades\Event;
use Inertia\Testing\AssertableInertia as Assert; use Inertia\Testing\AssertableInertia as Assert;
use Tests\FeatureTestCase; use Tests\FeatureTestCase;
use Toby\Domain\Enums\VacationRequestState;
use Toby\Domain\Enums\VacationType; use Toby\Domain\Enums\VacationType;
use Toby\Domain\Events\VacationRequestAcceptedByAdministrative; use Toby\Domain\Events\VacationRequestAcceptedByAdministrative;
use Toby\Domain\Events\VacationRequestAcceptedByTechnical; use Toby\Domain\Events\VacationRequestAcceptedByTechnical;
use Toby\Domain\Events\VacationRequestApproved; use Toby\Domain\Events\VacationRequestApproved;
use Toby\Domain\Events\VacationRequestRejected; use Toby\Domain\Events\VacationRequestRejected;
use Toby\Domain\PolishHolidaysRetriever; 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\User;
use Toby\Eloquent\Models\VacationLimit; use Toby\Eloquent\Models\VacationLimit;
use Toby\Eloquent\Models\VacationRequest; use Toby\Eloquent\Models\VacationRequest;
@ -83,7 +86,7 @@ class VacationRequestTest extends FeatureTestCase
"year_period_id" => $currentYearPeriod->id, "year_period_id" => $currentYearPeriod->id,
"name" => "1/" . $currentYearPeriod->year, "name" => "1/" . $currentYearPeriod->year,
"type" => VacationType::Vacation->value, "type" => VacationType::Vacation->value,
"state" => VacationRequestState::WaitingForTechnical, "state" => WaitingForTechnical::$name,
"from" => Carbon::create($currentYearPeriod->year, 2, 7)->toDateString(), "from" => Carbon::create($currentYearPeriod->year, 2, 7)->toDateString(),
"to" => Carbon::create($currentYearPeriod->year, 2, 11)->toDateString(), "to" => Carbon::create($currentYearPeriod->year, 2, 11)->toDateString(),
"comment" => "Comment for the vacation request.", "comment" => "Comment for the vacation request.",
@ -92,7 +95,7 @@ class VacationRequestTest extends FeatureTestCase
public function testUserCanCreateVacationRequestOnEmployeeBehalf(): void public function testUserCanCreateVacationRequestOnEmployeeBehalf(): void
{ {
$creator = User::factory()->createQuietly(); $creator = User::factory()->admin()->createQuietly();
$user = User::factory()->createQuietly(); $user = User::factory()->createQuietly();
$currentYearPeriod = YearPeriod::current(); $currentYearPeriod = YearPeriod::current();
@ -120,7 +123,7 @@ class VacationRequestTest extends FeatureTestCase
"year_period_id" => $currentYearPeriod->id, "year_period_id" => $currentYearPeriod->id,
"name" => "1/" . $currentYearPeriod->year, "name" => "1/" . $currentYearPeriod->year,
"type" => VacationType::Vacation->value, "type" => VacationType::Vacation->value,
"state" => VacationRequestState::WaitingForTechnical, "state" => WaitingForTechnical::$name,
"from" => Carbon::create($currentYearPeriod->year, 2, 7)->toDateString(), "from" => Carbon::create($currentYearPeriod->year, 2, 7)->toDateString(),
"to" => Carbon::create($currentYearPeriod->year, 2, 11)->toDateString(), "to" => Carbon::create($currentYearPeriod->year, 2, 11)->toDateString(),
"comment" => "Comment for the vacation request.", "comment" => "Comment for the vacation request.",
@ -131,7 +134,7 @@ class VacationRequestTest extends FeatureTestCase
{ {
Event::fake(VacationRequestApproved::class); Event::fake(VacationRequestApproved::class);
$creator = User::factory()->createQuietly(); $creator = User::factory()->admin()->createQuietly();
$user = User::factory()->createQuietly(); $user = User::factory()->createQuietly();
$currentYearPeriod = YearPeriod::current(); $currentYearPeriod = YearPeriod::current();
@ -160,7 +163,7 @@ class VacationRequestTest extends FeatureTestCase
"year_period_id" => $currentYearPeriod->id, "year_period_id" => $currentYearPeriod->id,
"name" => "1/" . $currentYearPeriod->year, "name" => "1/" . $currentYearPeriod->year,
"type" => VacationType::Vacation->value, "type" => VacationType::Vacation->value,
"state" => VacationRequestState::Approved, "state" => Approved::$name,
"from" => Carbon::create($currentYearPeriod->year, 2, 7)->toDateString(), "from" => Carbon::create($currentYearPeriod->year, 2, 7)->toDateString(),
"to" => Carbon::create($currentYearPeriod->year, 2, 11)->toDateString(), "to" => Carbon::create($currentYearPeriod->year, 2, 11)->toDateString(),
"comment" => "Comment for the vacation request.", "comment" => "Comment for the vacation request.",
@ -172,11 +175,11 @@ class VacationRequestTest extends FeatureTestCase
Event::fake(VacationRequestAcceptedByTechnical::class); Event::fake(VacationRequestAcceptedByTechnical::class);
$user = User::factory()->createQuietly(); $user = User::factory()->createQuietly();
$technicalApprover = User::factory()->createQuietly(); $technicalApprover = User::factory()->technicalApprover()->createQuietly();
$currentYearPeriod = YearPeriod::current(); $currentYearPeriod = YearPeriod::current();
$vacationRequest = VacationRequest::factory([ $vacationRequest = VacationRequest::factory([
"state" => VacationRequestState::WaitingForTechnical, "state" => WaitingForTechnical::class,
"type" => VacationType::Vacation, "type" => VacationType::Vacation,
]) ])
->for($user) ->for($user)
@ -195,12 +198,12 @@ class VacationRequestTest extends FeatureTestCase
Event::fake(VacationRequestAcceptedByAdministrative::class); Event::fake(VacationRequestAcceptedByAdministrative::class);
$user = User::factory()->createQuietly(); $user = User::factory()->createQuietly();
$administrativeApprover = User::factory()->createQuietly(); $administrativeApprover = User::factory()->administrativeApprover()->createQuietly();
$currentYearPeriod = YearPeriod::current(); $currentYearPeriod = YearPeriod::current();
$vacationRequest = VacationRequest::factory([ $vacationRequest = VacationRequest::factory([
"state" => VacationRequestState::WaitingForAdministrative, "state" => WaitingForAdministrative::class,
]) ])
->for($user) ->for($user)
->for($currentYearPeriod) ->for($currentYearPeriod)
@ -218,7 +221,7 @@ class VacationRequestTest extends FeatureTestCase
Event::fake(VacationRequestRejected::class); Event::fake(VacationRequestRejected::class);
$user = User::factory()->createQuietly(); $user = User::factory()->createQuietly();
$technicalApprover = User::factory()->createQuietly(); $technicalApprover = User::factory()->technicalApprover()->createQuietly();
$currentYearPeriod = YearPeriod::current(); $currentYearPeriod = YearPeriod::current();
VacationLimit::factory([ VacationLimit::factory([
@ -229,7 +232,7 @@ class VacationRequestTest extends FeatureTestCase
->create(); ->create();
$vacationRequest = VacationRequest::factory([ $vacationRequest = VacationRequest::factory([
"state" => VacationRequestState::WaitingForTechnical, "state" => WaitingForTechnical::class,
"type" => VacationType::Vacation, "type" => VacationType::Vacation,
]) ])
->for($user) ->for($user)
@ -241,6 +244,9 @@ class VacationRequestTest extends FeatureTestCase
->assertSessionHasNoErrors(); ->assertSessionHasNoErrors();
Event::assertDispatched(VacationRequestRejected::class); Event::assertDispatched(VacationRequestRejected::class);
$this->assertDatabaseHas("vacation_requests", [
"state" => Rejected::$name,
]);
} }
public function testUserCannotCreateVacationRequestIfHeExceedsHisVacationLimit(): void public function testUserCannotCreateVacationRequestIfHeExceedsHisVacationLimit(): void
@ -339,7 +345,7 @@ class VacationRequestTest extends FeatureTestCase
VacationRequest::factory([ VacationRequest::factory([
"type" => VacationType::Vacation->value, "type" => VacationType::Vacation->value,
"state" => VacationRequestState::WaitingForTechnical, "state" => WaitingForTechnical::class,
"from" => Carbon::create($currentYearPeriod->year, 2, 1)->toDateString(), "from" => Carbon::create($currentYearPeriod->year, 2, 1)->toDateString(),
"to" => Carbon::create($currentYearPeriod->year, 2, 4)->toDateString(), "to" => Carbon::create($currentYearPeriod->year, 2, 4)->toDateString(),
"comment" => "Comment for the vacation request.", "comment" => "Comment for the vacation request.",
@ -358,8 +364,7 @@ class VacationRequestTest extends FeatureTestCase
]) ])
->assertSessionHasErrors([ ->assertSessionHasErrors([
"vacationRequest" => __("You have pending vacation request in this range."), "vacationRequest" => __("You have pending vacation request in this range."),
]) ]);
;
} }
public function testUserCannotCreateVacationRequestIfHeHasApprovedVacationRequestInThisRange(): void public function testUserCannotCreateVacationRequestIfHeHasApprovedVacationRequestInThisRange(): void
@ -367,7 +372,7 @@ class VacationRequestTest extends FeatureTestCase
$user = User::factory()->createQuietly(); $user = User::factory()->createQuietly();
$currentYearPeriod = YearPeriod::current(); $currentYearPeriod = YearPeriod::current();
$vacationLimit = VacationLimit::factory([ VacationLimit::factory([
"days" => 20, "days" => 20,
]) ])
->for($user) ->for($user)
@ -376,7 +381,7 @@ class VacationRequestTest extends FeatureTestCase
VacationRequest::factory([ VacationRequest::factory([
"type" => VacationType::Vacation->value, "type" => VacationType::Vacation->value,
"state" => VacationRequestState::Approved, "state" => Approved::class,
"from" => Carbon::create($currentYearPeriod->year, 2, 2)->toDateString(), "from" => Carbon::create($currentYearPeriod->year, 2, 2)->toDateString(),
"to" => Carbon::create($currentYearPeriod->year, 2, 4)->toDateString(), "to" => Carbon::create($currentYearPeriod->year, 2, 4)->toDateString(),
"comment" => "Comment for the vacation request.", "comment" => "Comment for the vacation request.",

View File

@ -10,9 +10,9 @@ use Illuminate\Support\Facades\Notification;
use Tests\TestCase; use Tests\TestCase;
use Tests\Traits\InteractsWithYearPeriods; use Tests\Traits\InteractsWithYearPeriods;
use Toby\Domain\Enums\Role; use Toby\Domain\Enums\Role;
use Toby\Domain\Enums\VacationRequestState;
use Toby\Domain\Enums\VacationType; use Toby\Domain\Enums\VacationType;
use Toby\Domain\Notifications\VacationRequestWaitsForTechApprovalNotification; use Toby\Domain\Notifications\VacationRequestWaitsForTechApprovalNotification;
use Toby\Domain\States\VacationRequest\Created;
use Toby\Domain\VacationRequestStateManager; use Toby\Domain\VacationRequestStateManager;
use Toby\Eloquent\Models\User; use Toby\Eloquent\Models\User;
use Toby\Eloquent\Models\VacationRequest; use Toby\Eloquent\Models\VacationRequest;
@ -53,7 +53,7 @@ class VacationRequestNotificationTest extends TestCase
/** @var VacationRequest $vacationRequest */ /** @var VacationRequest $vacationRequest */
$vacationRequest = VacationRequest::factory([ $vacationRequest = VacationRequest::factory([
"type" => VacationType::Vacation->value, "type" => VacationType::Vacation->value,
"state" => VacationRequestState::Created, "state" => Created::class,
"from" => Carbon::create($currentYearPeriod->year, 2, 1)->toDateString(), "from" => Carbon::create($currentYearPeriod->year, 2, 1)->toDateString(),
"to" => Carbon::create($currentYearPeriod->year, 2, 4)->toDateString(), "to" => Carbon::create($currentYearPeriod->year, 2, 4)->toDateString(),
"comment" => "Comment for the vacation request.", "comment" => "Comment for the vacation request.",

View File

@ -9,8 +9,10 @@ use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Notification; use Illuminate\Support\Facades\Notification;
use Tests\TestCase; use Tests\TestCase;
use Tests\Traits\InteractsWithYearPeriods; use Tests\Traits\InteractsWithYearPeriods;
use Toby\Domain\Enums\VacationRequestState;
use Toby\Domain\Enums\VacationType; 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\Domain\VacationRequestStateManager;
use Toby\Eloquent\Models\User; use Toby\Eloquent\Models\User;
use Toby\Eloquent\Models\VacationRequest; use Toby\Eloquent\Models\VacationRequest;
@ -43,7 +45,7 @@ class VacationRequestStatesTest extends TestCase
/** @var VacationRequest $vacationRequest */ /** @var VacationRequest $vacationRequest */
$vacationRequest = VacationRequest::factory([ $vacationRequest = VacationRequest::factory([
"type" => VacationType::Vacation->value, "type" => VacationType::Vacation->value,
"state" => VacationRequestState::Created, "state" => Created::class,
"from" => Carbon::create($currentYearPeriod->year, 2, 1)->toDateString(), "from" => Carbon::create($currentYearPeriod->year, 2, 1)->toDateString(),
"to" => Carbon::create($currentYearPeriod->year, 2, 4)->toDateString(), "to" => Carbon::create($currentYearPeriod->year, 2, 4)->toDateString(),
"comment" => "Comment for the vacation request.", "comment" => "Comment for the vacation request.",
@ -54,7 +56,7 @@ class VacationRequestStatesTest extends TestCase
$this->stateManager->waitForTechnical($vacationRequest); $this->stateManager->waitForTechnical($vacationRequest);
$this->assertEquals(VacationRequestState::WaitingForTechnical, $vacationRequest->state); $this->assertTrue($vacationRequest->state->equals(WaitingForTechnical::class));
} }
public function testAfterCreatingVacationRequestOfTypeSickVacationItTransitsToProperState(): void public function testAfterCreatingVacationRequestOfTypeSickVacationItTransitsToProperState(): void
@ -66,7 +68,7 @@ class VacationRequestStatesTest extends TestCase
/** @var VacationRequest $vacationRequest */ /** @var VacationRequest $vacationRequest */
$vacationRequest = VacationRequest::factory([ $vacationRequest = VacationRequest::factory([
"type" => VacationType::Sick->value, "type" => VacationType::Sick->value,
"state" => VacationRequestState::Created, "state" => Created::class,
"from" => Carbon::create($currentYearPeriod->year, 2, 1)->toDateString(), "from" => Carbon::create($currentYearPeriod->year, 2, 1)->toDateString(),
"to" => Carbon::create($currentYearPeriod->year, 2, 4)->toDateString(), "to" => Carbon::create($currentYearPeriod->year, 2, 4)->toDateString(),
]) ])
@ -76,7 +78,7 @@ class VacationRequestStatesTest extends TestCase
$this->stateManager->approve($vacationRequest); $this->stateManager->approve($vacationRequest);
$this->assertEquals(VacationRequestState::Approved, $vacationRequest->state); $this->assertTrue($vacationRequest->state->equals(Approved::class));
} }
public function testAfterCreatingVacationRequestOfTypeTimeInLieuItTransitsToProperState(): void public function testAfterCreatingVacationRequestOfTypeTimeInLieuItTransitsToProperState(): void
@ -88,7 +90,7 @@ class VacationRequestStatesTest extends TestCase
/** @var VacationRequest $vacationRequest */ /** @var VacationRequest $vacationRequest */
$vacationRequest = VacationRequest::factory([ $vacationRequest = VacationRequest::factory([
"type" => VacationType::TimeInLieu->value, "type" => VacationType::TimeInLieu->value,
"state" => VacationRequestState::Created, "state" => Created::class,
"from" => Carbon::create($currentYearPeriod->year, 2, 2)->toDateString(), "from" => Carbon::create($currentYearPeriod->year, 2, 2)->toDateString(),
"to" => Carbon::create($currentYearPeriod->year, 2, 2)->toDateString(), "to" => Carbon::create($currentYearPeriod->year, 2, 2)->toDateString(),
]) ])
@ -98,6 +100,6 @@ class VacationRequestStatesTest extends TestCase
$this->stateManager->approve($vacationRequest); $this->stateManager->approve($vacationRequest);
$this->assertEquals(VacationRequestState::Approved, $vacationRequest->state); $this->assertTrue($vacationRequest->state->equals(Approved::class));
} }
} }