#41 - wip
This commit is contained in:
parent
d026d41715
commit
a0b64e6cb3
@ -1,4 +1,4 @@
|
|||||||
APP_NAME="Toby HR applicaiton"
|
APP_NAME="Toby HR application"
|
||||||
APP_ENV=local
|
APP_ENV=local
|
||||||
APP_KEY=
|
APP_KEY=
|
||||||
APP_DEBUG=true
|
APP_DEBUG=true
|
||||||
|
67
app/Domain/Notifications/VacationRequestNotification.php
Normal file
67
app/Domain/Notifications/VacationRequestNotification.php
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Toby\Domain\Notifications;
|
||||||
|
|
||||||
|
use Illuminate\Bus\Queueable;
|
||||||
|
use Illuminate\Notifications\Messages\MailMessage;
|
||||||
|
use Illuminate\Notifications\Notification;
|
||||||
|
use InvalidArgumentException;
|
||||||
|
use Toby\Eloquent\Models\User;
|
||||||
|
use Toby\Eloquent\Models\VacationRequest;
|
||||||
|
|
||||||
|
class VacationRequestNotification extends Notification
|
||||||
|
{
|
||||||
|
use Queueable;
|
||||||
|
|
||||||
|
protected User $user;
|
||||||
|
protected VacationRequest $vacationRequest;
|
||||||
|
|
||||||
|
public function __construct(User $user, VacationRequest $vacationRequest)
|
||||||
|
{
|
||||||
|
$this->user = $user;
|
||||||
|
$this->vacationRequest = $vacationRequest;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function via(): array
|
||||||
|
{
|
||||||
|
return ["mail"];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws InvalidArgumentException
|
||||||
|
*/
|
||||||
|
public function toMail(): MailMessage
|
||||||
|
{
|
||||||
|
$url = route(
|
||||||
|
"vacation.requests.show",
|
||||||
|
[
|
||||||
|
"vacationRequest" => $this->vacationRequest,
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
return $this->buildMailMessage($url);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function buildMailMessage(string $url): MailMessage
|
||||||
|
{
|
||||||
|
$title = $this->vacationRequest->name;
|
||||||
|
$state = $this->vacationRequest->state->label();
|
||||||
|
|
||||||
|
$user = $this->user->getFullNameAttribute();
|
||||||
|
|
||||||
|
return (new MailMessage())
|
||||||
|
->greeting(__("Hi :user!", [
|
||||||
|
"user" => $user,
|
||||||
|
]))
|
||||||
|
->subject(__("Vacation request :title", [
|
||||||
|
"title" => $title,
|
||||||
|
]))
|
||||||
|
->line(__("The vacation request :title has changed state to :state.", [
|
||||||
|
"title" => $title,
|
||||||
|
"state" => $state,
|
||||||
|
]))
|
||||||
|
->action(__("Show vacation request"), $url);
|
||||||
|
}
|
||||||
|
}
|
31
app/Domain/VacationRequestNotificationSender.php
Normal file
31
app/Domain/VacationRequestNotificationSender.php
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Toby\Domain;
|
||||||
|
|
||||||
|
use Illuminate\Support\Collection;
|
||||||
|
use Toby\Domain\Enums\Role;
|
||||||
|
use Toby\Domain\Notifications\VacationRequestNotification;
|
||||||
|
use Toby\Eloquent\Models\User;
|
||||||
|
use Toby\Eloquent\Models\VacationRequest;
|
||||||
|
|
||||||
|
class VacationRequestNotificationSender
|
||||||
|
{
|
||||||
|
public function sendVacationRequestNotification(VacationRequest $vacationRequest): void
|
||||||
|
{
|
||||||
|
foreach ($this->getUsersForNotifications() as $user) {
|
||||||
|
$user->notify(new VacationRequestNotification($user, $vacationRequest));
|
||||||
|
}
|
||||||
|
|
||||||
|
$vacationRequest->user->notify(new VacationRequestNotification($vacationRequest->user, $vacationRequest));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected function getUsersForNotifications(): Collection
|
||||||
|
{
|
||||||
|
return User::query()
|
||||||
|
->where("role", Role::TECHNICAL_APPROVER)
|
||||||
|
->orWhere("role", Role::ADMINISTRATIVE_APPROVER)
|
||||||
|
->get();
|
||||||
|
}
|
||||||
|
}
|
@ -8,6 +8,7 @@ use Illuminate\Contracts\Auth\Factory as Auth;
|
|||||||
use Illuminate\Events\Dispatcher;
|
use Illuminate\Events\Dispatcher;
|
||||||
use Toby\Domain\Enums\VacationRequestState;
|
use Toby\Domain\Enums\VacationRequestState;
|
||||||
use Toby\Domain\Events\VacationRequestStateChanged;
|
use Toby\Domain\Events\VacationRequestStateChanged;
|
||||||
|
use Toby\Domain\VacationRequestNotificationSender;
|
||||||
use Toby\Eloquent\Models\User;
|
use Toby\Eloquent\Models\User;
|
||||||
use Toby\Eloquent\Models\VacationRequest;
|
use Toby\Eloquent\Models\VacationRequest;
|
||||||
|
|
||||||
@ -16,6 +17,7 @@ class VacationRequestObserver
|
|||||||
public function __construct(
|
public function __construct(
|
||||||
protected Auth $auth,
|
protected Auth $auth,
|
||||||
protected Dispatcher $dispatcher,
|
protected Dispatcher $dispatcher,
|
||||||
|
protected VacationRequestNotificationSender $vacationRequestNotificationSender,
|
||||||
) {
|
) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -39,6 +41,13 @@ class VacationRequestObserver
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function updated(VacationRequest $vacationRequest): void
|
||||||
|
{
|
||||||
|
if ($vacationRequest->state !== VacationRequestState::CREATED) {
|
||||||
|
$this->vacationRequestNotificationSender->sendVacationRequestNotification($vacationRequest);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected function fireStateChangedEvent(
|
protected function fireStateChangedEvent(
|
||||||
VacationRequest $vacationRequest,
|
VacationRequest $vacationRequest,
|
||||||
?VacationRequestState $from,
|
?VacationRequestState $from,
|
||||||
|
@ -35,7 +35,7 @@ return [
|
|||||||
"name" => env("MAIL_FROM_NAME", "Example"),
|
"name" => env("MAIL_FROM_NAME", "Example"),
|
||||||
],
|
],
|
||||||
"markdown" => [
|
"markdown" => [
|
||||||
"theme" => "default",
|
"theme" => "mail",
|
||||||
"paths" => [
|
"paths" => [
|
||||||
resource_path("views/vendor/mail"),
|
resource_path("views/vendor/mail"),
|
||||||
],
|
],
|
||||||
|
@ -30,5 +30,12 @@
|
|||||||
"You have approved vacation request in this range.": "Masz zaakceptowany wniosek urlopowy w tym zakresie dat.",
|
"You have approved vacation request in this range.": "Masz zaakceptowany wniosek urlopowy w tym zakresie dat.",
|
||||||
"You have exceeded your vacation limit.": "Przekroczyłeś/aś limit urlopu.",
|
"You have exceeded your vacation limit.": "Przekroczyłeś/aś limit urlopu.",
|
||||||
"Vacation needs minimum one day.": "Urlop musi być co najmniej na jeden dzień.",
|
"Vacation needs minimum one day.": "Urlop musi być co najmniej na jeden dzień.",
|
||||||
"The vacation request cannot be created at the turn of the year.": "Wniosek urlopowy nie może zostać złożony na przełomie roku."
|
"The vacation request cannot be created at the turn of the year.": "Wniosek urlopowy nie może zostać złożony na przełomie roku.",
|
||||||
|
"Hi :user!": "Cześć :user!",
|
||||||
|
"The vacation request :title has changed state to :state.": "Wniosek urlopowy :title zmienił status na :state.",
|
||||||
|
"Vacation request :title": "Wniosek urlopowy :title",
|
||||||
|
"Regards": "Z poważaniem",
|
||||||
|
"If you're having trouble clicking the \":actionText\" button, copy and paste the URL below\ninto your web browser:": "Jeżeli masz problemy z kliknięciem przycisku \":actionText\", skopiuj i wklej poniższy adres w pasek przeglądarki:",
|
||||||
|
"All rights reserved.": "Wszelkie prawa zastrzeżone",
|
||||||
|
"Show vacation request": "Pokaż wniosek"
|
||||||
}
|
}
|
||||||
|
286
resources/views/vendor/mail/html/themes/mail.css
vendored
Normal file
286
resources/views/vendor/mail/html/themes/mail.css
vendored
Normal file
@ -0,0 +1,286 @@
|
|||||||
|
/* Base */
|
||||||
|
|
||||||
|
body, body *:not(html):not(style):not(br):not(tr):not(code) {
|
||||||
|
font-family: Avenir, Helvetica, sans-serif;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background-color: #f5f8fa;
|
||||||
|
color: #74787e;
|
||||||
|
height: 100%;
|
||||||
|
hyphens: auto;
|
||||||
|
line-height: 1.4;
|
||||||
|
margin: 0;
|
||||||
|
-moz-hyphens: auto;
|
||||||
|
-ms-word-break: break-all;
|
||||||
|
width: 100% !important;
|
||||||
|
-webkit-hyphens: auto;
|
||||||
|
-webkit-text-size-adjust: none;
|
||||||
|
word-break: break-all;
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
p,
|
||||||
|
ul,
|
||||||
|
ol,
|
||||||
|
blockquote {
|
||||||
|
line-height: 1.4;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #3c5f97;
|
||||||
|
}
|
||||||
|
|
||||||
|
a img {
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Typography */
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
color: #2F3133;
|
||||||
|
font-size: 19px;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-top: 0;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
color: #2F3133;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-top: 0;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
color: #2F3133;
|
||||||
|
font-size: 14px;
|
||||||
|
font-weight: bold;
|
||||||
|
margin-top: 0;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
color: #74787e;
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: 1.5em;
|
||||||
|
margin-top: 0;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
p.sub {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Layout */
|
||||||
|
|
||||||
|
.wrapper {
|
||||||
|
background-color: #f5f8fa;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
width: 100%;
|
||||||
|
-premailer-cellpadding: 0;
|
||||||
|
-premailer-cellspacing: 0;
|
||||||
|
-premailer-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
width: 100%;
|
||||||
|
-premailer-cellpadding: 0;
|
||||||
|
-premailer-cellspacing: 0;
|
||||||
|
-premailer-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Header */
|
||||||
|
|
||||||
|
.header {
|
||||||
|
padding: 25px 0;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header a {
|
||||||
|
color: #3c5f97;
|
||||||
|
font-size: 19px;
|
||||||
|
font-weight: bold;
|
||||||
|
text-decoration: none;
|
||||||
|
text-shadow: 0 1px 0 #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Body */
|
||||||
|
|
||||||
|
.body {
|
||||||
|
background-color: #ffffff;
|
||||||
|
border-bottom: 1px solid #edeff2;
|
||||||
|
border-top: 1px solid #edeff2;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
width: 100%;
|
||||||
|
-premailer-cellpadding: 0;
|
||||||
|
-premailer-cellspacing: 0;
|
||||||
|
-premailer-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inner-body {
|
||||||
|
background-color: #ffffff;
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 0;
|
||||||
|
width: 570px;
|
||||||
|
-premailer-cellpadding: 0;
|
||||||
|
-premailer-cellspacing: 0;
|
||||||
|
-premailer-width: 570px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Subcopy */
|
||||||
|
|
||||||
|
.subcopy {
|
||||||
|
border-top: 1px solid #edeff2;
|
||||||
|
margin-top: 25px;
|
||||||
|
padding-top: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subcopy p {
|
||||||
|
font-size: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Footer */
|
||||||
|
|
||||||
|
.footer {
|
||||||
|
margin: 0 auto;
|
||||||
|
padding: 0;
|
||||||
|
text-align: center;
|
||||||
|
width: 570px;
|
||||||
|
-premailer-cellpadding: 0;
|
||||||
|
-premailer-cellspacing: 0;
|
||||||
|
-premailer-width: 570px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footer p {
|
||||||
|
color: #aeaeae;
|
||||||
|
font-size: 12px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tables */
|
||||||
|
|
||||||
|
.table table {
|
||||||
|
margin: 30px auto;
|
||||||
|
width: 100%;
|
||||||
|
-premailer-cellpadding: 0;
|
||||||
|
-premailer-cellspacing: 0;
|
||||||
|
-premailer-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table th {
|
||||||
|
color: #74787e;
|
||||||
|
border-bottom: 1px solid #edeff2;
|
||||||
|
padding-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.table td {
|
||||||
|
color: #74787e;
|
||||||
|
font-size: 15px;
|
||||||
|
line-height: 18px;
|
||||||
|
padding: 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-cell {
|
||||||
|
padding: 35px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Buttons */
|
||||||
|
|
||||||
|
.action {
|
||||||
|
margin: 30px auto;
|
||||||
|
padding: 0;
|
||||||
|
text-align: center;
|
||||||
|
width: 100%;
|
||||||
|
-premailer-cellpadding: 0;
|
||||||
|
-premailer-cellspacing: 0;
|
||||||
|
-premailer-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button {
|
||||||
|
border-radius: 3px;
|
||||||
|
box-shadow: 0 2px 3px rgba(0, 0, 0, 0.16);
|
||||||
|
color: #ffffff;
|
||||||
|
display: inline-block;
|
||||||
|
text-decoration: none;
|
||||||
|
-webkit-text-size-adjust: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-blue, .button-primary {
|
||||||
|
background-color: #3c5f97;
|
||||||
|
border-top: 10px solid #3c5f97;
|
||||||
|
border-right: 18px solid #3c5f97;
|
||||||
|
border-bottom: 10px solid #3c5f97;
|
||||||
|
border-left: 18px solid #3c5f97;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-green, .button-success {
|
||||||
|
background-color: #22c55e;
|
||||||
|
border-top: 10px solid #22c55e;
|
||||||
|
border-right: 18px solid #22c55e;
|
||||||
|
border-bottom: 10px solid #22c55e;
|
||||||
|
border-left: 18px solid #22c55e;
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-red, .button-error {
|
||||||
|
background-color: #ef4444;
|
||||||
|
border-top: 10px solid #ef4444;
|
||||||
|
border-right: 18px solid #ef4444;
|
||||||
|
border-bottom: 10px solid #ef4444;
|
||||||
|
border-left: 18px solid #ef4444;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Panels */
|
||||||
|
|
||||||
|
.panel {
|
||||||
|
margin: 0 0 21px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-content {
|
||||||
|
background-color: #edeff2;
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-item {
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.panel-item p:last-of-type {
|
||||||
|
margin-bottom: 0;
|
||||||
|
padding-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Promotions */
|
||||||
|
|
||||||
|
.promotion {
|
||||||
|
background-color: #FFFFFF;
|
||||||
|
border: 2px dashed #9BA2AB;
|
||||||
|
margin: 0;
|
||||||
|
margin-bottom: 25px;
|
||||||
|
margin-top: 25px;
|
||||||
|
padding: 24px;
|
||||||
|
width: 100%;
|
||||||
|
-premailer-cellpadding: 0;
|
||||||
|
-premailer-cellspacing: 0;
|
||||||
|
-premailer-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.promotion h1 {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.promotion p {
|
||||||
|
font-size: 15px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
94
tests/Unit/VacationRequestNotificationTest.php
Normal file
94
tests/Unit/VacationRequestNotificationTest.php
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Tests\Unit;
|
||||||
|
|
||||||
|
use Illuminate\Foundation\Testing\DatabaseMigrations;
|
||||||
|
use Illuminate\Support\Facades\Notification;
|
||||||
|
use Illuminate\Support\Carbon;
|
||||||
|
use Tests\TestCase;
|
||||||
|
use Tests\Traits\InteractsWithYearPeriods;
|
||||||
|
use Toby\Domain\Enums\Role;
|
||||||
|
use Toby\Domain\Enums\VacationRequestState;
|
||||||
|
use Toby\Domain\Enums\VacationType;
|
||||||
|
use Toby\Domain\Notifications\VacationRequestNotification;
|
||||||
|
use Toby\Domain\VacationRequestStateManager;
|
||||||
|
use Toby\Eloquent\Models\User;
|
||||||
|
use Toby\Eloquent\Models\VacationRequest;
|
||||||
|
use Toby\Eloquent\Models\YearPeriod;
|
||||||
|
|
||||||
|
class VacationRequestNotificationTest extends TestCase
|
||||||
|
{
|
||||||
|
use DatabaseMigrations;
|
||||||
|
use InteractsWithYearPeriods;
|
||||||
|
|
||||||
|
protected VacationRequestStateManager $stateManager;
|
||||||
|
|
||||||
|
protected function setUp(): void
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
$this->stateManager = $this->app->make(VacationRequestStateManager::class);
|
||||||
|
|
||||||
|
$this->createCurrentYearPeriod();
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAfterChangingVacationRequestStateNotificationAreSentToUsers() :void
|
||||||
|
{
|
||||||
|
Notification::fake();
|
||||||
|
|
||||||
|
$user = User::factory(["role" => Role::EMPLOYEE])->createQuietly();
|
||||||
|
$technicalApprover = User::factory(["role" => Role::TECHNICAL_APPROVER])->createQuietly();
|
||||||
|
$administrativeApprover = User::factory(["role" => Role::ADMINISTRATIVE_APPROVER])->createQuietly();
|
||||||
|
|
||||||
|
$currentYearPeriod = YearPeriod::current();
|
||||||
|
|
||||||
|
/** @var VacationRequest $vacationRequest */
|
||||||
|
$vacationRequest = VacationRequest::factory([
|
||||||
|
"type" => VacationType::VACATION->value,
|
||||||
|
"state" => VacationRequestState::CREATED,
|
||||||
|
"from" => Carbon::create($currentYearPeriod->year, 2, 1)->toDateString(),
|
||||||
|
"to" => Carbon::create($currentYearPeriod->year, 2, 4)->toDateString(),
|
||||||
|
"comment" => "Comment for the vacation request.",
|
||||||
|
])
|
||||||
|
->for($user)
|
||||||
|
->for($currentYearPeriod)
|
||||||
|
->create();
|
||||||
|
|
||||||
|
$this->stateManager->waitForTechnical($vacationRequest);
|
||||||
|
|
||||||
|
Notification::assertSentTo([$user, $technicalApprover, $administrativeApprover],VacationRequestNotification::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testAfterChangingVacationRequestStateNotificationIsNotSentToAnotherEmployee(): void {
|
||||||
|
Notification::fake();
|
||||||
|
|
||||||
|
$user = User::factory(["role" => Role::EMPLOYEE])->createQuietly();
|
||||||
|
$anotherUser = User::factory(["role" => Role::EMPLOYEE])->createQuietly();
|
||||||
|
$technicalApprover = User::factory(["role" => Role::TECHNICAL_APPROVER])->createQuietly();
|
||||||
|
$administrativeApprover = User::factory(["role" => Role::ADMINISTRATIVE_APPROVER])->createQuietly();
|
||||||
|
|
||||||
|
|
||||||
|
$currentYearPeriod = YearPeriod::current();
|
||||||
|
|
||||||
|
/** @var VacationRequest $vacationRequest */
|
||||||
|
$vacationRequest = VacationRequest::factory([
|
||||||
|
"type" => VacationType::VACATION->value,
|
||||||
|
"state" => VacationRequestState::CREATED,
|
||||||
|
"from" => Carbon::create($currentYearPeriod->year, 2, 1)->toDateString(),
|
||||||
|
"to" => Carbon::create($currentYearPeriod->year, 2, 4)->toDateString(),
|
||||||
|
"comment" => "Comment for the vacation request.",
|
||||||
|
])
|
||||||
|
->for($user)
|
||||||
|
->for($currentYearPeriod)
|
||||||
|
->create();
|
||||||
|
|
||||||
|
$this->stateManager->waitForTechnical($vacationRequest);
|
||||||
|
|
||||||
|
Notification::assertSentTo([$user, $technicalApprover, $administrativeApprover],VacationRequestNotification::class);
|
||||||
|
Notification::assertNotSentTo([$anotherUser],VacationRequestNotification::class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -5,11 +5,14 @@ declare(strict_types=1);
|
|||||||
namespace Tests\Unit;
|
namespace Tests\Unit;
|
||||||
|
|
||||||
use Illuminate\Foundation\Testing\DatabaseMigrations;
|
use Illuminate\Foundation\Testing\DatabaseMigrations;
|
||||||
|
use Illuminate\Support\Facades\Notification;
|
||||||
use Illuminate\Support\Carbon;
|
use Illuminate\Support\Carbon;
|
||||||
use Tests\TestCase;
|
use Tests\TestCase;
|
||||||
use Tests\Traits\InteractsWithYearPeriods;
|
use Tests\Traits\InteractsWithYearPeriods;
|
||||||
|
use Toby\Domain\Enums\Role;
|
||||||
use Toby\Domain\Enums\VacationRequestState;
|
use Toby\Domain\Enums\VacationRequestState;
|
||||||
use Toby\Domain\Enums\VacationType;
|
use Toby\Domain\Enums\VacationType;
|
||||||
|
use Toby\Domain\Notifications\VacationRequestNotification;
|
||||||
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;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user