From 092ecc938aabf8c323934d0539998072942d7e86 Mon Sep 17 00:00:00 2001 From: Kamil Date: Tue, 16 Jul 2024 14:34:07 +0200 Subject: [PATCH 1/5] #465 - feat: added employee notification about upcoming medical exam or ohs training --- ...nAboutUpcomingMedicalExamsForEmployees.php | 35 ++++++++++++++++++ ...onAboutUpcomingOhsTrainingForEmployees.php | 35 ++++++++++++++++++ ...mingMedicalExamForEmployeeNotification.php | 37 +++++++++++++++++++ ...mingOhsTrainingForEmployeeNotification.php | 37 +++++++++++++++++++ lang/pl.json | 2 + 5 files changed, 146 insertions(+) create mode 100644 app/Console/Commands/SendNotificationAboutUpcomingMedicalExamsForEmployees.php create mode 100644 app/Console/Commands/SendNotificationAboutUpcomingOhsTrainingForEmployees.php create mode 100644 app/Notifications/UpcomingMedicalExamForEmployeeNotification.php create mode 100644 app/Notifications/UpcomingOhsTrainingForEmployeeNotification.php diff --git a/app/Console/Commands/SendNotificationAboutUpcomingMedicalExamsForEmployees.php b/app/Console/Commands/SendNotificationAboutUpcomingMedicalExamsForEmployees.php new file mode 100644 index 00000000..b71134cf --- /dev/null +++ b/app/Console/Commands/SendNotificationAboutUpcomingMedicalExamsForEmployees.php @@ -0,0 +1,35 @@ +whereRelation("histories", function ($query): void { + $query->where("type", UserHistoryType::MedicalExam) + ->where("to", ">", Carbon::now()) + ->where("to", "<=", Carbon::now()->addMonth()); + })->get(); + + if ($usersUpcomingMedicalExams->isEmpty()) { + return; + } + + foreach ($usersUpcomingMedicalExams as $user) { + $user->notify(new UpcomingMedicalExamForEmployeeNotification($user)); + } + } +} diff --git a/app/Console/Commands/SendNotificationAboutUpcomingOhsTrainingForEmployees.php b/app/Console/Commands/SendNotificationAboutUpcomingOhsTrainingForEmployees.php new file mode 100644 index 00000000..65cf2ed4 --- /dev/null +++ b/app/Console/Commands/SendNotificationAboutUpcomingOhsTrainingForEmployees.php @@ -0,0 +1,35 @@ +whereRelation("histories", function ($query): void { + $query->where("type", UserHistoryType::OhsTraining) + ->where("to", ">", Carbon::now()) + ->where("to", "<=", Carbon::now()->addMonth()); + })->get(); + + if ($usersUpcomingOhsTrainings->isEmpty()) { + return; + } + + foreach ($usersUpcomingOhsTrainings as $user) { + $user->notify(new UpcomingOhsTrainingForEmployeeNotification($user)); + } + } +} diff --git a/app/Notifications/UpcomingMedicalExamForEmployeeNotification.php b/app/Notifications/UpcomingMedicalExamForEmployeeNotification.php new file mode 100644 index 00000000..abe6f2a6 --- /dev/null +++ b/app/Notifications/UpcomingMedicalExamForEmployeeNotification.php @@ -0,0 +1,37 @@ +user->lastMedicalExam(); + + return (new SlackMessage()) + ->text(__("The deadline for occupational health examinations for you is about to expire - :date (overdue :difference days)", [ + "date" => $lastMedicalExamDate->to->toDisplayString(), + "difference" => (int)$lastMedicalExamDate->to->diffInDays(Carbon::today(), true), + ])); + } +} diff --git a/app/Notifications/UpcomingOhsTrainingForEmployeeNotification.php b/app/Notifications/UpcomingOhsTrainingForEmployeeNotification.php new file mode 100644 index 00000000..0ac9532d --- /dev/null +++ b/app/Notifications/UpcomingOhsTrainingForEmployeeNotification.php @@ -0,0 +1,37 @@ +user->lastOhsTraining(); + + return (new SlackMessage()) + ->text(__("The deadline for occupational ohs training for you is about to expire - :date (overdue :difference days)", [ + "date" => $lastOhsTrainingDate->to->toDisplayString(), + "difference" => (int)$lastOhsTrainingDate->to->diffInDays(Carbon::today(), true), + ])); + } +} diff --git a/lang/pl.json b/lang/pl.json index 5e28ac3d..7cb1295c 100644 --- a/lang/pl.json +++ b/lang/pl.json @@ -75,6 +75,8 @@ "The request :title is waiting for your administrative approval.\nUser: :requester\nDate: :date (number of days: :days)": "Wniosek :title czeka na Twoją akceptację administracyjną.\nPracownik: :requester\nData: :date (liczba dni: :days)", "The request :title has been approved by you as a technical approver.\nUser: :requester\nDate: :date (number of days: :days)": "Wniosek :title został zaakceptowany przez Ciebie jako przełożonego technicznego.\nPracownik: :requester\nData: :date (liczba dni: :days)", "The request :title has been approved by you as an administrative approver.\nUser: :requester\nDate: :date (number of days: :days)": "Wniosek :title został zaakceptowany przez Ciebie jako przełożonego administracyjnego.\nPracownik: :requester\nData: :date (liczba dni: :days)", + "The deadline for occupational ohs training for you is about to expire - :date (overdue :difference days)": "Niedługo mija termin szkolenia BHP dla Ciebie - :date (przeterminowane za :difference dni)", + "The deadline for occupational health examinations for you is about to expire - :date (overdue :difference days)": "Niedługo mija termin badań lekarskich z medycyny pracy dla Ciebie - :date (przeterminowane za :difference dni)", "Request :title has been :status": "Wniosek :title został :status", "Request :title in :application": "Wniosek :title w aplikacji :application", "The request :title from user :requester has been :status.": "Wniosek :title użytkownika :requester został :status.", From 86b71121de13d021efbe23a9a45ccf1b26d30aab Mon Sep 17 00:00:00 2001 From: Kamil Date: Tue, 16 Jul 2024 14:44:01 +0200 Subject: [PATCH 2/5] #465 - fix: fixed channel --- .../UpcomingMedicalExamForEmployeeNotification.php | 2 +- .../UpcomingOhsTrainingForEmployeeNotification.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Notifications/UpcomingMedicalExamForEmployeeNotification.php b/app/Notifications/UpcomingMedicalExamForEmployeeNotification.php index abe6f2a6..d64e5fcc 100644 --- a/app/Notifications/UpcomingMedicalExamForEmployeeNotification.php +++ b/app/Notifications/UpcomingMedicalExamForEmployeeNotification.php @@ -21,7 +21,7 @@ public function __construct( public function via(): array { - return [Channels::MAIL]; + return [Channels::SLACK]; } public function toSlack(): SlackMessage diff --git a/app/Notifications/UpcomingOhsTrainingForEmployeeNotification.php b/app/Notifications/UpcomingOhsTrainingForEmployeeNotification.php index 0ac9532d..45c9ff7a 100644 --- a/app/Notifications/UpcomingOhsTrainingForEmployeeNotification.php +++ b/app/Notifications/UpcomingOhsTrainingForEmployeeNotification.php @@ -21,7 +21,7 @@ public function __construct( public function via(): array { - return [Channels::MAIL]; + return [Channels::SLACK]; } public function toSlack(): SlackMessage From 20dfb29c783763895e807d76d63ce36bcb605514 Mon Sep 17 00:00:00 2001 From: Kamil Date: Tue, 16 Jul 2024 14:58:23 +0200 Subject: [PATCH 3/5] #465 - fix: fixed slack messages --- lang/pl.json | 4 ++-- routes/console.php | 10 ++++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/lang/pl.json b/lang/pl.json index 7cb1295c..f7d39d88 100644 --- a/lang/pl.json +++ b/lang/pl.json @@ -75,8 +75,8 @@ "The request :title is waiting for your administrative approval.\nUser: :requester\nDate: :date (number of days: :days)": "Wniosek :title czeka na Twoją akceptację administracyjną.\nPracownik: :requester\nData: :date (liczba dni: :days)", "The request :title has been approved by you as a technical approver.\nUser: :requester\nDate: :date (number of days: :days)": "Wniosek :title został zaakceptowany przez Ciebie jako przełożonego technicznego.\nPracownik: :requester\nData: :date (liczba dni: :days)", "The request :title has been approved by you as an administrative approver.\nUser: :requester\nDate: :date (number of days: :days)": "Wniosek :title został zaakceptowany przez Ciebie jako przełożonego administracyjnego.\nPracownik: :requester\nData: :date (liczba dni: :days)", - "The deadline for occupational ohs training for you is about to expire - :date (overdue :difference days)": "Niedługo mija termin szkolenia BHP dla Ciebie - :date (przeterminowane za :difference dni)", - "The deadline for occupational health examinations for you is about to expire - :date (overdue :difference days)": "Niedługo mija termin badań lekarskich z medycyny pracy dla Ciebie - :date (przeterminowane za :difference dni)", + "The deadline for occupational ohs training for you is about to expire - :date (:difference days)": "Niedługo mija termin Twojego szkolenia BHP - :date (:difference dni)", + "The deadline for occupational health examinations for you is about to expire - :date (:difference days)": "Niedługo mija termin Twojego badania lekarskiego z medycyny pracy - :date (:difference dni)", "Request :title has been :status": "Wniosek :title został :status", "Request :title in :application": "Wniosek :title w aplikacji :application", "The request :title from user :requester has been :status.": "Wniosek :title użytkownika :requester został :status.", diff --git a/routes/console.php b/routes/console.php index c659305b..a1c181d0 100644 --- a/routes/console.php +++ b/routes/console.php @@ -9,6 +9,8 @@ use Toby\Console\Commands\SendNotificationAboutBenefitsReportCreation; use Toby\Console\Commands\SendNotificationAboutUpcomingAndOverdueMedicalExams; use Toby\Console\Commands\SendNotificationAboutUpcomingAndOverdueOhsTraining; +use Toby\Console\Commands\SendNotificationAboutUpcomingMedicalExamsForEmployees; +use Toby\Console\Commands\SendNotificationAboutUpcomingOhsTrainingForEmployees; use Toby\Console\Commands\SendOvertimeRequestSummariesToApprovers; use Toby\Console\Commands\SendVacationRequestSummariesToApprovers; use Toby\Jobs\CheckYearPeriod; @@ -49,6 +51,14 @@ ->hourly() ->onOneServer(); +Schedule::command(SendNotificationAboutUpcomingMedicalExamsForEmployees::class) + ->weeklyOn(1, "08:30") + ->onOneServer(); + +Schedule::command(SendNotificationAboutUpcomingOhsTrainingForEmployees::class) + ->weeklyOn(1, "08:30") + ->onOneServer(); + $scheduledTask = Schedule::command(BackupPostgresDatabase::class) ->dailyAt(time: "05:00") ->withoutOverlapping() From f958997169011213f8a233971c32ce9d7246ff14 Mon Sep 17 00:00:00 2001 From: Kamil Date: Wed, 17 Jul 2024 07:37:59 +0200 Subject: [PATCH 4/5] #465 - feat: added some tests --- ...AboutUpcomingOhsTrainingsForEmployees.php} | 4 +- routes/console.php | 4 +- ...onAboutUpcomingMedicalExamsToSlackTest.php | 59 +++++++++++++++++ ...onAboutUpcomingOhsTrainingsToSlackTest.php | 66 +++++++++++++++++++ 4 files changed, 129 insertions(+), 4 deletions(-) rename app/Console/Commands/{SendNotificationAboutUpcomingOhsTrainingForEmployees.php => SendNotificationAboutUpcomingOhsTrainingsForEmployees.php} (91%) create mode 100644 tests/Unit/SendNotificationAboutUpcomingMedicalExamsToSlackTest.php create mode 100644 tests/Unit/SendNotificationAboutUpcomingOhsTrainingsToSlackTest.php diff --git a/app/Console/Commands/SendNotificationAboutUpcomingOhsTrainingForEmployees.php b/app/Console/Commands/SendNotificationAboutUpcomingOhsTrainingsForEmployees.php similarity index 91% rename from app/Console/Commands/SendNotificationAboutUpcomingOhsTrainingForEmployees.php rename to app/Console/Commands/SendNotificationAboutUpcomingOhsTrainingsForEmployees.php index 65cf2ed4..65c2259b 100644 --- a/app/Console/Commands/SendNotificationAboutUpcomingOhsTrainingForEmployees.php +++ b/app/Console/Commands/SendNotificationAboutUpcomingOhsTrainingsForEmployees.php @@ -10,9 +10,9 @@ use Toby\Models\User; use Toby\Notifications\UpcomingOhsTrainingForEmployeeNotification; -class SendNotificationAboutUpcomingOhsTrainingForEmployees extends Command +class SendNotificationAboutUpcomingOhsTrainingsForEmployees extends Command { - protected $signature = "toby:send-notification-about-ohs-training-for-employees"; + protected $signature = "toby:send-notification-about-ohs-trainings-for-employees"; protected $description = "Send notifications about upcoming ohs trainings."; public function handle(): void diff --git a/routes/console.php b/routes/console.php index a1c181d0..ccfa9a82 100644 --- a/routes/console.php +++ b/routes/console.php @@ -10,7 +10,7 @@ use Toby\Console\Commands\SendNotificationAboutUpcomingAndOverdueMedicalExams; use Toby\Console\Commands\SendNotificationAboutUpcomingAndOverdueOhsTraining; use Toby\Console\Commands\SendNotificationAboutUpcomingMedicalExamsForEmployees; -use Toby\Console\Commands\SendNotificationAboutUpcomingOhsTrainingForEmployees; +use Toby\Console\Commands\SendNotificationAboutUpcomingOhsTrainingsForEmployees; use Toby\Console\Commands\SendOvertimeRequestSummariesToApprovers; use Toby\Console\Commands\SendVacationRequestSummariesToApprovers; use Toby\Jobs\CheckYearPeriod; @@ -55,7 +55,7 @@ ->weeklyOn(1, "08:30") ->onOneServer(); -Schedule::command(SendNotificationAboutUpcomingOhsTrainingForEmployees::class) +Schedule::command(SendNotificationAboutUpcomingOhsTrainingsForEmployees::class) ->weeklyOn(1, "08:30") ->onOneServer(); diff --git a/tests/Unit/SendNotificationAboutUpcomingMedicalExamsToSlackTest.php b/tests/Unit/SendNotificationAboutUpcomingMedicalExamsToSlackTest.php new file mode 100644 index 00000000..b6655d80 --- /dev/null +++ b/tests/Unit/SendNotificationAboutUpcomingMedicalExamsToSlackTest.php @@ -0,0 +1,59 @@ +createCurrentYearPeriod(); + $this->user = User::factory()->employee()->create(); + } + + public function testNotificationIsSentToUserWithUpcomingMedicalExams(): void + { + $this->user->histories()->create([ + "from" => Carbon::createFromDate(2022, 1, 1), + "to" => Carbon::now()->addDays(14), + "type" => "medical_exam", + ]); + + $this->artisan(SendNotificationAboutUpcomingMedicalExamsForEmployees::class) + ->execute(); + + Notification::assertSentTo($this->user, UpcomingMedicalExamForEmployeeNotification::class); + } + + public function testNotificationIsNotSentToUserWithoutUpcomingMedicalExams(): void + { + $this->user->histories()->create([ + "from" => Carbon::createFromDate(2022, 1, 1), + "to" => Carbon::now()->addYear(), + "type" => "medical_exam", + ]); + + $this->artisan(SendNotificationAboutUpcomingMedicalExamsForEmployees::class) + ->execute(); + + Notification::assertNothingSent(); + } +} diff --git a/tests/Unit/SendNotificationAboutUpcomingOhsTrainingsToSlackTest.php b/tests/Unit/SendNotificationAboutUpcomingOhsTrainingsToSlackTest.php new file mode 100644 index 00000000..0c6442c1 --- /dev/null +++ b/tests/Unit/SendNotificationAboutUpcomingOhsTrainingsToSlackTest.php @@ -0,0 +1,66 @@ +createCurrentYearPeriod(); + Http::fake(fn(): array => [ + "channel" => Str::random(8), + "message" => ["ts" => Carbon::now()->toDateTimeString()], + ]); + + $this->user = User::factory()->employee()->create(); + } + + public function testNotificationIsSentToUserWithUpcomingMedicalExams(): void + { + $this->user->histories()->create([ + "from" => Carbon::createFromDate(2022, 1, 1), + "to" => Carbon::now()->addDays(14), + "type" => "ohs_training", + ]); + + $this->artisan(SendNotificationAboutUpcomingOhsTrainingsForEmployees::class) + ->execute(); + + Notification::assertSentTo($this->user, UpcomingOhsTrainingForEmployeeNotification::class); + } + + public function testNotificationIsNotSentToUserWithoutUpcomingMedicalExams(): void + { + $this->user->histories()->create([ + "from" => Carbon::createFromDate(2022, 1, 1), + "to" => Carbon::now()->addYear(), + "type" => "ohs_training", + ]); + + $this->artisan(SendNotificationAboutUpcomingOhsTrainingsForEmployees::class) + ->execute(); + + Notification::assertNothingSent(); + } +} From ca15af9113763d86c8bf96f67a6915da8f6ba672 Mon Sep 17 00:00:00 2001 From: Kamil Date: Wed, 17 Jul 2024 08:50:20 +0200 Subject: [PATCH 5/5] #465 - fix: code review fixes --- .../UpcomingMedicalExamForEmployeeNotification.php | 2 +- .../UpcomingOhsTrainingForEmployeeNotification.php | 2 +- lang/pl.json | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/Notifications/UpcomingMedicalExamForEmployeeNotification.php b/app/Notifications/UpcomingMedicalExamForEmployeeNotification.php index d64e5fcc..69481ad4 100644 --- a/app/Notifications/UpcomingMedicalExamForEmployeeNotification.php +++ b/app/Notifications/UpcomingMedicalExamForEmployeeNotification.php @@ -29,7 +29,7 @@ public function toSlack(): SlackMessage $lastMedicalExamDate = $this->user->lastMedicalExam(); return (new SlackMessage()) - ->text(__("The deadline for occupational health examinations for you is about to expire - :date (overdue :difference days)", [ + ->text(__("The deadline for occupational medical examinations for you is about to expire - :date (:difference days)", [ "date" => $lastMedicalExamDate->to->toDisplayString(), "difference" => (int)$lastMedicalExamDate->to->diffInDays(Carbon::today(), true), ])); diff --git a/app/Notifications/UpcomingOhsTrainingForEmployeeNotification.php b/app/Notifications/UpcomingOhsTrainingForEmployeeNotification.php index 45c9ff7a..990f0c4c 100644 --- a/app/Notifications/UpcomingOhsTrainingForEmployeeNotification.php +++ b/app/Notifications/UpcomingOhsTrainingForEmployeeNotification.php @@ -29,7 +29,7 @@ public function toSlack(): SlackMessage $lastOhsTrainingDate = $this->user->lastOhsTraining(); return (new SlackMessage()) - ->text(__("The deadline for occupational ohs training for you is about to expire - :date (overdue :difference days)", [ + ->text(__("The deadline for occupational ohs training for you is about to expire - :date (:difference days)", [ "date" => $lastOhsTrainingDate->to->toDisplayString(), "difference" => (int)$lastOhsTrainingDate->to->diffInDays(Carbon::today(), true), ])); diff --git a/lang/pl.json b/lang/pl.json index f7d39d88..52045847 100644 --- a/lang/pl.json +++ b/lang/pl.json @@ -76,7 +76,7 @@ "The request :title has been approved by you as a technical approver.\nUser: :requester\nDate: :date (number of days: :days)": "Wniosek :title został zaakceptowany przez Ciebie jako przełożonego technicznego.\nPracownik: :requester\nData: :date (liczba dni: :days)", "The request :title has been approved by you as an administrative approver.\nUser: :requester\nDate: :date (number of days: :days)": "Wniosek :title został zaakceptowany przez Ciebie jako przełożonego administracyjnego.\nPracownik: :requester\nData: :date (liczba dni: :days)", "The deadline for occupational ohs training for you is about to expire - :date (:difference days)": "Niedługo mija termin Twojego szkolenia BHP - :date (:difference dni)", - "The deadline for occupational health examinations for you is about to expire - :date (:difference days)": "Niedługo mija termin Twojego badania lekarskiego z medycyny pracy - :date (:difference dni)", + "The deadline for occupational medical examinations for you is about to expire - :date (:difference days)": "Niedługo mija termin Twojego badania lekarskiego z medycyny pracy - :date (:difference dni)", "Request :title has been :status": "Wniosek :title został :status", "Request :title in :application": "Wniosek :title w aplikacji :application", "The request :title from user :requester has been :status.": "Wniosek :title użytkownika :requester został :status.",