Skip to content

Commit

Permalink
#444 - add notification to Slack about overtime (#463)
Browse files Browse the repository at this point in the history
* #444 - wip

* #444 - wip

* #444 - wip
  • Loading branch information
EwelinaSkrzypacz authored Jul 15, 2024
1 parent d01a022 commit cce3d5e
Show file tree
Hide file tree
Showing 17 changed files with 498 additions and 11 deletions.
17 changes: 16 additions & 1 deletion app/Actions/OvertimeRequest/WaitForTechApprovalAction.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@

namespace Toby\Actions\OvertimeRequest;

use Toby\Actions\VacationRequest\ApproveAction;
use Spatie\Permission\Models\Permission;
use Toby\Domain\OvertimeRequestStateManager;
use Toby\Models\OvertimeRequest;
use Toby\Notifications\OvertimeRequestsWaitsForApprovalNotification;

class WaitForTechApprovalAction
{
Expand All @@ -18,5 +19,19 @@ public function __construct(
public function execute(OvertimeRequest $overtimeRequest): void
{
$this->stateManager->waitForTechnical($overtimeRequest);

$this->notifyAuthorizedUsers($overtimeRequest);
}

protected function notifyAuthorizedUsers(OvertimeRequest $overtimeRequest): void
{
$users = Permission::findByName("manageOvertimeAsTechnicalApprover")
->users()
->with("permissions")
->get();

foreach ($users as $user) {
$user->notify(new OvertimeRequestsWaitsForApprovalNotification($overtimeRequest, $user));
}
}
}
69 changes: 69 additions & 0 deletions app/Console/Commands/SendOvertimeRequestSummariesToApprovers.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
<?php

declare(strict_types=1);

namespace Toby\Console\Commands;

use Carbon\CarbonInterface;
use Illuminate\Console\Command;
use Illuminate\Support\Carbon;
use Spatie\Permission\Models\Permission;
use Toby\Domain\OvertimeRequestStatesRetriever;
use Toby\Models\Holiday;
use Toby\Models\OvertimeRequest;
use Toby\Models\User;
use Toby\Notifications\OvertimeRequestsSummaryNotification;

class SendOvertimeRequestSummariesToApprovers extends Command
{
protected $signature = "toby:send-overtime-request-reminders {--f|force}";
protected $description = "Sends overtime request reminders to approvers if they didn't approve";

public function handle(): void
{
$now = Carbon::today();

if (!$this->option("force") && !$this->shouldHandle($now)) {
return;
}

$users = Permission::findByName("receiveOvertimeRequestsSummaryNotification")->users()->get();

foreach ($users as $user) {
$overtimeRequests = OvertimeRequest::query()
->states(OvertimeRequestStatesRetriever::waitingForUserActionStates($user))
->orderByDesc("updated_at")
->get();

if ($overtimeRequests->isNotEmpty() && $this->worksToday($user, $now)) {
$user->notify(new OvertimeRequestsSummaryNotification(Carbon::today(), $overtimeRequests));
}
}
}

protected function shouldHandle(CarbonInterface $day): bool
{
$holidays = Holiday::query()->whereDate("date", $day)->pluck("date");

if ($day->isWeekend()) {
return false;
}

if ($holidays->contains($day)) {
return false;
}

return true;
}

protected function worksToday(User $user, Carbon $date): bool
{
$count = $user->overtimeRequests()
->whereDate("from", "<=", $date)
->whereDate("to", ">=", $date)
->states(OvertimeRequestStatesRetriever::successStates())
->count();

return $count === 0;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ public function handle(VacationTypeConfigRetriever $configRetriever): void
foreach ($users as $user) {
$vacationRequests = VacationRequest::query()
->states(VacationRequestStatesRetriever::waitingForUserActionStates($user))
->orderByDesc("updated_at")
->get();

if ($vacationRequests->isNotEmpty() && $this->worksToday($user, $now, $configRetriever)) {
Expand Down
38 changes: 38 additions & 0 deletions app/Notifications/OvertimeRequestNotification.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php

declare(strict_types=1);

namespace Toby\Notifications;

use Illuminate\Bus\Queueable;
use Toby\Models\OvertimeRequest;
use Toby\Models\User;
use Toby\Slack\Elements\SlackMessage;

abstract class OvertimeRequestNotification extends QueuedNotification
{
use Queueable;

public function __construct(
protected OvertimeRequest $overtimeRequest,
protected User $user,
) {
parent::__construct();
}

public function via(): array
{
return [Channels::SLACK];
}

public function toSlack(): SlackMessage
{
$url = route("overtime.requests.show", ["overtimeRequest" => $this->overtimeRequest->id]);
$seeDetails = __("See details");

return (new SlackMessage())
->text("{$this->buildDescription()}\n <{$url}|{$seeDetails}>");
}

abstract protected function buildDescription(): string;
}
42 changes: 42 additions & 0 deletions app/Notifications/OvertimeRequestsSummaryNotification.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<?php

declare(strict_types=1);

namespace Toby\Notifications;

use Illuminate\Bus\Queueable;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Support\Carbon;
use Toby\Slack\Elements\OvertimeRequestsAttachment;
use Toby\Slack\Elements\SlackMessage;

class OvertimeRequestsSummaryNotification extends QueuedNotification
{
use Queueable;

public function __construct(
protected Carbon $day,
protected Collection $overtimeRequests,
) {
parent::__construct();
}

public function via(): array
{
return [Channels::SLACK];
}

public function toSlack(): SlackMessage
{
$this->loadRelations();

return (new SlackMessage())
->text(__("Requests wait for your approval - status for day :date:", ["date" => $this->day->toDisplayString()]))
->withAttachment(new OvertimeRequestsAttachment($this->overtimeRequests));
}

protected function loadRelations(): void
{
$this->overtimeRequests->load(["user"]);
}
}
55 changes: 55 additions & 0 deletions app/Notifications/OvertimeRequestsWaitsForApprovalNotification.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<?php

declare(strict_types=1);

namespace Toby\Notifications;

use Spatie\SlashCommand\AttachmentAction;
use Toby\Helpers\DateFormats;
use Toby\Slack\Elements\Attachment;
use Toby\Slack\Elements\SlackMessage;

class OvertimeRequestsWaitsForApprovalNotification extends OvertimeRequestNotification
{
public function toSlack(): SlackMessage
{
$url = route("overtime.requests.show", ["overtimeRequest" => $this->overtimeRequest->id]);
$seeDetails = __("See details");

$actions = [
AttachmentAction::create("overtime_technical_approval", __("Approve"), "button")
->setValue("overtime_technical_approval")
->setStyle("primary"),
AttachmentAction::create("overtime_reject", __("Reject"), "button")
->setValue("overtime_reject")
->setStyle("danger"),
];

$attachment = Attachment::create()
->setCallbackId("overtime:{$this->overtimeRequest->id}")
->setText(__("Available actions:"))
->setActions($actions);

return (new SlackMessage())
->text("{$this->buildDescription()}\n <{$url}|{$seeDetails}>")
->withAttachment($attachment);
}

protected function buildDescription(): string
{
$title = $this->overtimeRequest->name;
$requester = $this->overtimeRequest->user->profile->full_name;
$from = $this->overtimeRequest->from;
$to = $this->overtimeRequest->to;
$hours = $this->overtimeRequest->hours;

$date = "{$from->format(DateFormats::DATETIME_DISPLAY)} - {$to->format(DateFormats::DATETIME_DISPLAY)}";

return __("The request :title is waiting for your technical approval.\nUser: :requester\nDate: :date (number of hours: :hours)", [
"title" => $title,
"requester" => $requester,
"date" => $date,
"hours" => $hours,
]);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ public function toSlack(): SlackMessage
}

$attachment = Attachment::create()
->setCallbackId((string)$this->vacationRequest->id)
->setCallbackId("vacation:{$this->vacationRequest->id}")
->setText(__("Available actions:"))
->setActions($actions);

Expand Down
37 changes: 37 additions & 0 deletions app/Slack/Elements/OvertimeRequestsAttachment.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

declare(strict_types=1);

namespace Toby\Slack\Elements;

use Illuminate\Support\Collection;
use Toby\Helpers\DateFormats;
use Toby\Models\OvertimeRequest;

class OvertimeRequestsAttachment extends ListAttachment
{
public function __construct(Collection $overtimeRequests)
{
parent::__construct();

$this
->setColor("#527aba")
->setItems($this->mapOvertimeRequests($overtimeRequests));
}

protected function mapOvertimeRequests(Collection $overtimeRequests): Collection
{
return $overtimeRequests->map(function (OvertimeRequest $request): string {
$url = route("overtime.requests.show", ["overtimeRequest" => $request->id]);

$date = "{$request->from->format(DateFormats::DATETIME_DISPLAY)} - {$request->to->format(DateFormats::DATETIME_DISPLAY)}";

return __("<:url|:request> - :user (:date)", [
"url" => $url,
"request" => $request->name,
"user" => $request->user->profile->full_name,
"date" => $date,
]);
});
}
}
Loading

0 comments on commit cce3d5e

Please sign in to comment.