This commit is contained in:
Adrian Hopek 2022-04-26 14:12:25 +02:00
parent eb5dcf39c6
commit 62a0a21835
4 changed files with 99 additions and 216 deletions

View File

@ -0,0 +1,63 @@
<?php
declare(strict_types=1);
namespace Toby\Domain\Notifications;
use Illuminate\Bus\Queueable;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Notifications\Notification;
use Illuminate\Support\Carbon;
use Illuminate\Support\Collection;
use Toby\Eloquent\Models\User;
class VacationRequestsSummaryNotification extends Notification
{
use Queueable;
public function __construct(
protected Carbon $day,
protected Collection $vacationRequests,
) {
}
public function via(): array
{
return ["mail"];
}
public function toMail($notifiable): MailMessage
{
$url = route(
"vacation.requests.indexForApprovers",
[
"status" => "waiting_for_action",
],
);
return $this->buildMailMessage($notifiable, $url);
}
protected function buildMailMessage(User $user, string $url): MailMessage
{
$user = $user->profile->first_name;
$message = (new MailMessage())
->greeting(
__("Hi :user!", [
"user" => $user,
])
)
->line("Lista wniosków oczekujących na Twoją akcję - stan na dzień {$this->day->toDisplayString()}:")
->subject("Wnioski oczekujące na akcje - stan na dzień {$this->day->toDisplayString()}");
foreach ($this->vacationRequests as $request) {
$message->line(
"Wniosek nr {$request->name} użytkownika {$request->user->profile->full_name} ({$request->from->toDisplayString()} - {$request->to->toDisplayString()})"
);
}
return $message
->action("Przejdź do wniosków", $url);
}
}

View File

@ -1,78 +0,0 @@
<?php
declare(strict_types=1);
namespace Toby\Infrastructure\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Carbon;
use Toby\Domain\Enums\Role;
use Toby\Domain\Enums\VacationType;
use Toby\Domain\Notifications\VacationRequestWaitsForApprovalNotification;
use Toby\Domain\States\VacationRequest\WaitingForAdministrative;
use Toby\Domain\States\VacationRequest\WaitingForTechnical;
use Toby\Domain\VacationTypeConfigRetriever;
use Toby\Domain\WorkDaysCalculator;
use Toby\Eloquent\Models\User;
use Toby\Eloquent\Models\VacationRequest;
class SendVacationRequestRemindersToApprovers extends Command
{
public const REMINDER_INTERVAL = 3;
protected $signature = "toby:send-vacation-request-reminders";
protected $description = "Sends vacation request reminders to approvers if they didn't approve";
public function handle(VacationTypeConfigRetriever $configRetriever, WorkDaysCalculator $daysCalculator): void
{
$vacationRequests = VacationRequest::query()
->type(VacationType::all()->filter(fn(VacationType $type) => $configRetriever->isVacation($type))->all())
->get();
/** @var VacationRequest $vacationRequest */
foreach ($vacationRequests as $vacationRequest) {
if (!$this->shouldNotify($vacationRequest, $daysCalculator)) {
continue;
}
if ($vacationRequest->state->equals(WaitingForTechnical::class)) {
$this->notifyTechnicalApprovers($vacationRequest);
}
if ($vacationRequest->state->equals(WaitingForAdministrative::class)) {
$this->notifyAdminApprovers($vacationRequest);
}
}
}
protected function shouldNotify(VacationRequest $vacationRequest, WorkDaysCalculator $daysCalculator): bool
{
$days = $daysCalculator
->calculateDays($vacationRequest->updated_at->addDay(), Carbon::today())
->count();
return $days >= static::REMINDER_INTERVAL && ($days % static::REMINDER_INTERVAL === 0);
}
protected function notifyAdminApprovers(VacationRequest $vacationRequest): void
{
$users = User::query()
->whereIn("role", [Role::AdministrativeApprover, Role::Administrator])
->get();
foreach ($users as $user) {
$user->notify(new VacationRequestWaitsForApprovalNotification($vacationRequest, $user));
}
}
protected function notifyTechnicalApprovers(VacationRequest $vacationRequest): void
{
$users = User::query()
->whereIn("role", [Role::TechnicalApprover, Role::Administrator])
->get();
foreach ($users as $user) {
$user->notify(new VacationRequestWaitsForApprovalNotification($vacationRequest, $user));
}
}
}

View File

@ -0,0 +1,36 @@
<?php
declare(strict_types=1);
namespace Toby\Infrastructure\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Carbon;
use Toby\Domain\Enums\Role;
use Toby\Domain\Notifications\VacationRequestsSummaryNotification;
use Toby\Domain\VacationRequestStatesRetriever;
use Toby\Eloquent\Models\User;
use Toby\Eloquent\Models\VacationRequest;
class SendVacationRequestSummariesToApprovers extends Command
{
protected $signature = "toby:send-vacation-request-reminders";
protected $description = "Sends vacation request reminders to approvers if they didn't approve";
public function handle(): void
{
$users = User::query()
->whereIn("role", [Role::AdministrativeApprover, Role::TechnicalApprover, Role::Administrator])
->get();
foreach ($users as $user) {
$vacationRequests = VacationRequest::query()
->states(VacationRequestStatesRetriever::waitingForUserActionStates($user))
->get();
if ($vacationRequests->isNotEmpty()) {
$user->notify(new VacationRequestsSummaryNotification(Carbon::today(), $vacationRequests));
}
}
}
}

View File

@ -1,138 +0,0 @@
<?php
declare(strict_types=1);
namespace Tests\Unit;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Notification;
use Tests\TestCase;
use Tests\Traits\InteractsWithYearPeriods;
use Toby\Domain\Enums\VacationType;
use Toby\Domain\Notifications\VacationRequestWaitsForApprovalNotification;
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\YearPeriod;
use Toby\Infrastructure\Console\Commands\SendVacationRequestRemindersToApprovers;
class SendVacationRequestRemindersTest extends TestCase
{
use DatabaseMigrations;
use InteractsWithYearPeriods;
protected function setUp(): void
{
parent::setUp();
$this->createCurrentYearPeriod();
Notification::fake();
}
public function testReminderIsSentIfItsBeenThreeWorkDaysSinceTheUpdate(): void
{
$currentYearPeriod = YearPeriod::current();
$this->travelTo(Carbon::create(2022, 4, 20));
$user = User::factory()->create();
$technicalApprover = User::factory()
->technicalApprover()
->create();
VacationRequest::factory([
"type" => VacationType::Vacation->value,
"state" => WaitingForTechnical::class,
])
->for($user)
->for($currentYearPeriod)
->create();
$this->travelTo(Carbon::create(2022, 4, 25));
$this->artisan(SendVacationRequestRemindersToApprovers::class);
Notification::assertSentTo([$technicalApprover], VacationRequestWaitsForApprovalNotification::class);
}
public function testReminderIsSentIfItsBeenAnotherThreeWorkDaysSinceTheUpdate(): void
{
$currentYearPeriod = YearPeriod::current();
$this->travelTo(Carbon::create(2022, 4, 20));
$user = User::factory()->create();
$technicalApprover = User::factory()
->technicalApprover()
->create();
VacationRequest::factory([
"type" => VacationType::Vacation->value,
"state" => WaitingForTechnical::class,
])
->for($user)
->for($currentYearPeriod)
->create();
$this->travelTo(Carbon::create(2022, 4, 28));
$this->artisan(SendVacationRequestRemindersToApprovers::class);
Notification::assertSentTo([$technicalApprover], VacationRequestWaitsForApprovalNotification::class);
}
public function testReminderIsNotSentIfItHasntBeenThreeWorkDays(): void
{
$currentYearPeriod = YearPeriod::current();
$this->travelTo(Carbon::create(2022, 4, 20));
$user = User::factory()->create();
$technicalApprover = User::factory()
->technicalApprover()
->create();
VacationRequest::factory([
"type" => VacationType::Vacation->value,
"state" => WaitingForTechnical::class,
])
->for($user)
->for($currentYearPeriod)
->create();
$this->travelTo(Carbon::create(2022, 4, 24));
$this->artisan(SendVacationRequestRemindersToApprovers::class);
Notification::assertNotSentTo([$technicalApprover], VacationRequestWaitsForApprovalNotification::class);
}
public function testReminderIsSentToProperApprover(): void
{
$currentYearPeriod = YearPeriod::current();
$this->travelTo(Carbon::create(2022, 4, 20));
$user = User::factory()->create();
$adminApprover = User::factory()
->administrativeApprover()
->create();
$technicalApprover = User::factory()
->technicalApprover()
->create();
VacationRequest::factory([
"type" => VacationType::Vacation->value,
"state" => WaitingForAdministrative::class,
])
->for($user)
->for($currentYearPeriod)
->create();
$this->travelTo(Carbon::create(2022, 4, 25));
$this->artisan(SendVacationRequestRemindersToApprovers::class);
Notification::assertSentTo([$adminApprover], VacationRequestWaitsForApprovalNotification::class);
Notification::assertNotSentTo([$technicalApprover, $user], VacationRequestWaitsForApprovalNotification::class);
}
}