Refactored shift entry deletion: Use event for notification and worklog creation
This commit is contained in:
parent
870a92efd5
commit
7cd4befdfa
|
@ -64,11 +64,16 @@ return [
|
|||
// a list of
|
||||
// 'Class@method' or 'Class' (which uses @handle),
|
||||
// ['Class', 'method'],
|
||||
// callable like [$instance, 'method] or 'function'
|
||||
// callable like [$instance, 'method'] or 'function'
|
||||
// or $function
|
||||
// ]
|
||||
'news.created' => \Engelsystem\Events\Listener\News::class . '@created',
|
||||
|
||||
'oauth2.login' => \Engelsystem\Events\Listener\OAuth2::class . '@login',
|
||||
|
||||
'shift.entry.deleting' => [
|
||||
\Engelsystem\Events\Listener\Shift::class . '@deletedEntryCreateWorklog',
|
||||
\Engelsystem\Events\Listener\Shift::class . '@deletedEntrySendEmail',
|
||||
],
|
||||
],
|
||||
];
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
<?php
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Engelsystem\Helpers\Carbon;
|
||||
use Engelsystem\Http\Exceptions\HttpForbidden;
|
||||
use Engelsystem\Models\Room;
|
||||
use Engelsystem\Models\Shifts\ScheduleShift;
|
||||
use Engelsystem\Models\User\User;
|
||||
use Engelsystem\ShiftSignupState;
|
||||
|
||||
/**
|
||||
|
@ -236,7 +237,21 @@ function shift_delete_controller()
|
|||
|
||||
// Schicht löschen bestätigt
|
||||
if ($request->hasPostData('delete')) {
|
||||
UserWorkLog_from_shift($shift_id);
|
||||
$room = Room::find($shift['RID']);
|
||||
foreach ($shift['ShiftEntry'] as $entry) {
|
||||
$type = AngelType($entry['TID']);
|
||||
event('shift.entry.deleting', [
|
||||
'user' => User::find($entry['user_id']),
|
||||
'start' => Carbon::createFromTimestamp($shift['start']),
|
||||
'end' => Carbon::createFromTimestamp($shift['end']),
|
||||
'name' => $shift['name'],
|
||||
'title' => $shift['title'],
|
||||
'type' => $type['name'],
|
||||
'room' => $room,
|
||||
'freeloaded' => (bool)$entry['freeloaded'],
|
||||
]);
|
||||
}
|
||||
|
||||
Shift_delete($shift_id);
|
||||
|
||||
engelsystem_log(
|
||||
|
|
|
@ -0,0 +1,129 @@
|
|||
<?php
|
||||
|
||||
namespace Engelsystem\Events\Listener;
|
||||
|
||||
use Engelsystem\Helpers\Carbon;
|
||||
use Engelsystem\Helpers\Shifts;
|
||||
use Engelsystem\Mail\EngelsystemMailer;
|
||||
use Engelsystem\Models\Room;
|
||||
use Engelsystem\Models\User\User;
|
||||
use Engelsystem\Models\Worklog;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Symfony\Component\Mailer\Exception\TransportException;
|
||||
|
||||
class Shift
|
||||
{
|
||||
/** @var LoggerInterface */
|
||||
protected LoggerInterface $log;
|
||||
|
||||
/** @var EngelsystemMailer */
|
||||
protected EngelsystemMailer $mailer;
|
||||
|
||||
/**
|
||||
* @param LoggerInterface $log
|
||||
* @param EngelsystemMailer $mailer
|
||||
*/
|
||||
public function __construct(
|
||||
LoggerInterface $log,
|
||||
EngelsystemMailer $mailer
|
||||
) {
|
||||
$this->log = $log;
|
||||
$this->mailer = $mailer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param string $name
|
||||
* @param string $title
|
||||
* @param string $type
|
||||
* @param Room $room
|
||||
* @return void
|
||||
*/
|
||||
public function deletedEntryCreateWorklog(
|
||||
User $user,
|
||||
Carbon $start,
|
||||
Carbon $end,
|
||||
string $name,
|
||||
string $title,
|
||||
string $type,
|
||||
Room $room,
|
||||
bool $freeloaded
|
||||
): void {
|
||||
if ($freeloaded || $start > Carbon::now()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$workLog = new Worklog();
|
||||
$workLog->user()->associate($user);
|
||||
$workLog->creator()->associate(auth()->user());
|
||||
$workLog->worked_at = $start->copy()->startOfDay();
|
||||
$workLog->hours =
|
||||
(($end->timestamp - $start->timestamp) / 60 / 60)
|
||||
* Shifts::getNightShiftMultiplier($start, $end);
|
||||
$workLog->comment = sprintf(
|
||||
'%s (%s as %s) in %s, %s - %s',
|
||||
$name,
|
||||
$title,
|
||||
$type,
|
||||
$room->name,
|
||||
$start->format('Y-m-d H:i'),
|
||||
$end->format('Y-m-d H:i')
|
||||
);
|
||||
$workLog->save();
|
||||
|
||||
$this->log->info(
|
||||
'Created worklog entry from shift for {user} ({uid}): {worklog})',
|
||||
['user' => $workLog->user->name, 'uid' => $workLog->user->id, 'worklog' => $workLog->comment]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
* @param Carbon $start
|
||||
* @param Carbon $end
|
||||
* @param string $name
|
||||
* @param string $title
|
||||
* @param string $type
|
||||
* @param Room $room
|
||||
* @return void
|
||||
*/
|
||||
public function deletedEntrySendEmail(
|
||||
User $user,
|
||||
Carbon $start,
|
||||
Carbon $end,
|
||||
string $name,
|
||||
string $title,
|
||||
string $type,
|
||||
Room $room,
|
||||
bool $freeloaded
|
||||
): void {
|
||||
if (!$user->settings->email_shiftinfo) {
|
||||
return;
|
||||
}
|
||||
|
||||
$subject = 'notification.shift.deleted';
|
||||
try {
|
||||
$this->mailer->sendViewTranslated(
|
||||
$user,
|
||||
$subject,
|
||||
'emails/worklog-from-shift',
|
||||
[
|
||||
'name' => $name,
|
||||
'title' => $title,
|
||||
'start' => $start,
|
||||
'end' => $end,
|
||||
'room' => $room,
|
||||
'freeloaded' => $freeloaded,
|
||||
'username' => $user->name,
|
||||
]
|
||||
);
|
||||
} catch (TransportException $e) {
|
||||
$this->log->error(
|
||||
'Unable to send email "{title}" to user {user} with {exception}',
|
||||
['title' => $subject, 'user' => $user->name, 'exception' => $e]
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -59,6 +59,7 @@ $includeFiles = [
|
|||
__DIR__ . '/../includes/helper/message_helper.php',
|
||||
__DIR__ . '/../includes/helper/email_helper.php',
|
||||
__DIR__ . '/../includes/helper/oauth_helper.php',
|
||||
__DIR__ . '/../includes/helper/shift_helper.php',
|
||||
|
||||
__DIR__ . '/../includes/mailer/shifts_mailer.php',
|
||||
__DIR__ . '/../includes/mailer/users_mailer.php',
|
||||
|
|
|
@ -78,34 +78,6 @@ function mail_shift_change($old_shift, $new_shift)
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $shift
|
||||
*/
|
||||
function mail_shift_delete($shift)
|
||||
{
|
||||
$users = ShiftEntries_by_shift($shift['SID']);
|
||||
$room = Room::find($shift['RID']);
|
||||
|
||||
$message = __('A Shift you are registered on was deleted:') . "\n";
|
||||
|
||||
$message .= $shift['name'] . "\n";
|
||||
$message .= $shift['title'] . "\n";
|
||||
$message .= date('Y-m-d H:i', $shift['start']) . ' - ' . date('H:i', $shift['end']) . "\n";
|
||||
$message .= $room->name . "\n";
|
||||
|
||||
foreach ($users as $user) {
|
||||
$user = (new User())->forceFill($user);
|
||||
if ($user->settings->email_shiftinfo) {
|
||||
$userMessage = $message;
|
||||
if ($shift['start'] < time() && !$user['freeloaded']) {
|
||||
$userMessage .= "\n" . __('Since the deleted shift was already done, we added a worklog entry instead, to keep your work hours correct.') . "\n";
|
||||
}
|
||||
|
||||
engelsystem_email_to_user($user, __('Your Shift was deleted'), $userMessage, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $user
|
||||
* @param array $shift
|
||||
|
|
|
@ -512,7 +512,6 @@ function Shift_signup_allowed(
|
|||
*/
|
||||
function Shift_delete($shift_id)
|
||||
{
|
||||
mail_shift_delete(Shift($shift_id));
|
||||
Db::delete('DELETE FROM `Shifts` WHERE `SID`=?', [$shift_id]);
|
||||
}
|
||||
|
||||
|
@ -657,7 +656,9 @@ function Shift($shift_id)
|
|||
}
|
||||
|
||||
$shiftsEntry_source = Db::select('
|
||||
SELECT `ShiftEntry`.`id`, `ShiftEntry`.`TID` , `ShiftEntry`.`UID` , `ShiftEntry`.`freeloaded`, `users`.`name` AS `username`
|
||||
SELECT
|
||||
`ShiftEntry`.`id`, `ShiftEntry`.`TID` , `ShiftEntry`.`UID` , `ShiftEntry`.`freeloaded`,
|
||||
`users`.`name` AS `username`, `users`.`id` AS `user_id`
|
||||
FROM `ShiftEntry`
|
||||
LEFT JOIN `users` ON (`users`.`id` = `ShiftEntry`.`UID`)
|
||||
WHERE `SID`=?', [$shift_id]);
|
||||
|
|
|
@ -66,45 +66,6 @@ function UserWorkLog_create(Worklog $worklog)
|
|||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array|int $shift
|
||||
*/
|
||||
function UserWorkLog_from_shift($shift)
|
||||
{
|
||||
$shift = is_array($shift) ? $shift : Shift($shift);
|
||||
if ($shift['start'] > time()) {
|
||||
return;
|
||||
}
|
||||
|
||||
$room = Room::find($shift['RID']);
|
||||
foreach ($shift['ShiftEntry'] as $entry) {
|
||||
if ($entry['freeloaded']) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$type = AngelType($entry['TID']);
|
||||
|
||||
$shiftStart = Carbon::createFromTimestamp($shift['start']);
|
||||
$shiftEnd = Carbon::createFromTimestamp($shift['end']);
|
||||
$nightShiftMultiplier = Shifts::getNightShiftMultiplier($shiftStart, $shiftEnd);
|
||||
|
||||
$worklog = UserWorkLog_new($entry['UID']);
|
||||
$worklog->hours = (($shift['end'] - $shift['start']) / 60 / 60) * $nightShiftMultiplier;
|
||||
$worklog->comment = sprintf(
|
||||
'%s (%s as %s) in %s, %s-%s',
|
||||
$shift['name'],
|
||||
$shift['title'],
|
||||
$type['name'],
|
||||
$room->name,
|
||||
Carbon::createFromTimestamp($shift['start'])->format(__('m/d/Y h:i a')),
|
||||
Carbon::createFromTimestamp($shift['end'])->format(__('m/d/Y h:i a'))
|
||||
);
|
||||
$worklog->worked_at = Carbon::createFromTimestamp($shift['start']);
|
||||
|
||||
UserWorkLog_create($worklog);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* New user work log entry
|
||||
*
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
<?php
|
||||
|
||||
use Engelsystem\Helpers\Carbon;
|
||||
use Engelsystem\Models\Room;
|
||||
use Engelsystem\Models\User\User;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
|
@ -180,9 +182,19 @@ function admin_rooms()
|
|||
$shifts = Shifts_by_room($room);
|
||||
foreach ($shifts as $shift) {
|
||||
$shift = Shift($shift['SID']);
|
||||
|
||||
UserWorkLog_from_shift($shift);
|
||||
mail_shift_delete($shift);
|
||||
foreach ($shift['ShiftEntry'] as $entry) {
|
||||
$type = AngelType($entry['TID']);
|
||||
event('shift.entry.deleting', [
|
||||
'user' => User::find($entry['user_id']),
|
||||
'start' => Carbon::createFromTimestamp($shift['start']),
|
||||
'end' => Carbon::createFromTimestamp($shift['end']),
|
||||
'name' => $shift['name'],
|
||||
'title' => $shift['title'],
|
||||
'type' => $type['name'],
|
||||
'room' => $room,
|
||||
'freeloaded' => (bool)$entry['freeloaded'],
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
Room_delete($room);
|
||||
|
|
|
@ -536,7 +536,21 @@ function admin_shifts_history(): string
|
|||
|
||||
foreach ($shifts as $shift) {
|
||||
$shift = Shift($shift['SID']);
|
||||
UserWorkLog_from_shift($shift);
|
||||
$room = Room::find($shift['RID']);
|
||||
foreach ($shift['ShiftEntry'] as $entry) {
|
||||
$type = AngelType($entry['TID']);
|
||||
event('shift.entry.deleting', [
|
||||
'user' => User::find($entry['user_id']),
|
||||
'start' => Carbon::createFromTimestamp($shift['start']),
|
||||
'end' => Carbon::createFromTimestamp($shift['end']),
|
||||
'name' => $shift['name'],
|
||||
'title' => $shift['title'],
|
||||
'type' => $type['name'],
|
||||
'room' => $room,
|
||||
'freeloaded' => (bool)$entry['freeloaded'],
|
||||
]);
|
||||
}
|
||||
|
||||
shift_delete($shift['SID']);
|
||||
|
||||
engelsystem_log(
|
||||
|
|
|
@ -4,7 +4,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace Engelsystem\Controllers\Admin\Schedule;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Engelsystem\Helpers\Carbon;
|
||||
use DateTimeInterface;
|
||||
use Engelsystem\Controllers\BaseController;
|
||||
use Engelsystem\Controllers\HasUserNotifications;
|
||||
|
@ -17,6 +17,7 @@ use Engelsystem\Http\Response;
|
|||
use Engelsystem\Models\Room as RoomModel;
|
||||
use Engelsystem\Models\Shifts\Schedule as ScheduleUrl;
|
||||
use Engelsystem\Models\Shifts\ScheduleShift;
|
||||
use Engelsystem\Models\User\User;
|
||||
use ErrorException;
|
||||
use GuzzleHttp\Client as GuzzleClient;
|
||||
use Illuminate\Database\Connection as DatabaseConnection;
|
||||
|
@ -267,6 +268,7 @@ class ImportSchedule extends BaseController
|
|||
}
|
||||
|
||||
foreach ($deleteEvents as $event) {
|
||||
$this->fireDeleteShiftEntryEvents($event);
|
||||
$this->deleteEvent($event);
|
||||
}
|
||||
|
||||
|
@ -289,6 +291,39 @@ class ImportSchedule extends BaseController
|
|||
$this->log('Created schedule room "{room}"', ['room' => $room->getName()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Event $event
|
||||
*/
|
||||
protected function fireDeleteShiftEntryEvents(Event $event): void
|
||||
{
|
||||
$shiftEntries = $this->db
|
||||
->table('ShiftEntry')
|
||||
->select([
|
||||
'ShiftTypes.name', 'Shifts.title', 'AngelTypes.name AS type', 'rooms.id AS room_id',
|
||||
'Shifts.start', 'Shifts.end', 'ShiftEntry.UID as user_id', 'ShiftEntry.freeloaded'
|
||||
])
|
||||
->join('Shifts', 'Shifts.SID', 'ShiftEntry.SID')
|
||||
->join('schedule_shift', 'Shifts.SID', 'schedule_shift.shift_id')
|
||||
->join('rooms', 'rooms.id', 'Shifts.RID')
|
||||
->join('AngelTypes', 'AngelTypes.id', 'ShiftEntry.TID')
|
||||
->join('ShiftTypes', 'ShiftTypes.id', 'Shifts.shifttype_id')
|
||||
->where('schedule_shift.guid', $event->getGuid())
|
||||
->get();
|
||||
|
||||
foreach ($shiftEntries as $shiftEntry) {
|
||||
event('shift.entry.deleting', [
|
||||
'user' => User::find($shiftEntry->user_id),
|
||||
'start' => Carbon::createFromTimestamp($shiftEntry->start),
|
||||
'end' => Carbon::createFromTimestamp($shiftEntry->end),
|
||||
'name' => $shiftEntry->name,
|
||||
'title' => $shiftEntry->title,
|
||||
'type' => $shiftEntry->type,
|
||||
'room' => RoomModel::find($shiftEntry->room_id),
|
||||
'freeloaded' => $shiftEntry->freeloaded,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Event $shift
|
||||
* @param int $shiftTypeId
|
||||
|
|
|
@ -152,6 +152,17 @@ msgstr "Du wurdest von einem Supporter als %1$s hinzugefügt."
|
|||
msgid "notification.angeltype.added.text"
|
||||
msgstr "Eine Beschreibung findest du unter %2$s"
|
||||
|
||||
msgid "notification.shift.deleted"
|
||||
msgstr "Deine Schicht wurde gelöscht"
|
||||
|
||||
msgid "notification.shift.deleted.introduction"
|
||||
msgstr "Eine deiner Schichten wurde gelöscht:"
|
||||
|
||||
msgid "notification.shift.deleted.worklog"
|
||||
msgstr ""
|
||||
"Da die gelöschte Schicht bereits vergangen ist, "
|
||||
"haben wir einen entsprechenden Arbeitseinsatz hinzugefügt."
|
||||
|
||||
msgid "user.edit.success"
|
||||
msgstr "Benutzer erfolgreich bearbeitet."
|
||||
|
||||
|
|
|
@ -150,6 +150,17 @@ msgstr "You have been added as an %1$s by a supporter."
|
|||
msgid "notification.angeltype.added.text"
|
||||
msgstr "You can find a description at %2$s"
|
||||
|
||||
msgid "notification.shift.deleted"
|
||||
msgstr "Your Shift was deleted"
|
||||
|
||||
msgid "notification.shift.deleted.introduction"
|
||||
msgstr "A Shift you are registered on was deleted:"
|
||||
|
||||
msgid "notification.shift.deleted.worklog"
|
||||
msgstr ""
|
||||
"Since the deleted shift was already done, "
|
||||
"we added a worklog entry instead, to keep your work hours correct."
|
||||
|
||||
msgid "user.edit.success"
|
||||
msgstr "User edited successfully."
|
||||
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
{% extends "emails/mail.twig" %}
|
||||
|
||||
{% block introduction %}
|
||||
{{ __('notification.shift.deleted.introduction') }}
|
||||
{% endblock %}
|
||||
|
||||
{% block message %}
|
||||
{{ name }}
|
||||
{{ title }}
|
||||
{{ start.format(__('Y-m-d H:i')) }} - {{ end.format(__('Y-m-d H:i')) }}
|
||||
{{ room.name }}
|
||||
|
||||
{% if start <= date() and not freeloaded %}
|
||||
{{ __('notification.shift.deleted.worklog') }}
|
||||
{% endif %}
|
||||
{% endblock %}
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
namespace Engelsystem\Helpers;
|
||||
|
||||
use \Carbon\Carbon;
|
||||
use Carbon\Carbon;
|
||||
|
||||
// Should be moved to the shift model if it's available
|
||||
class Shifts
|
||||
|
|
|
@ -47,7 +47,7 @@ class EngelsystemMailer extends Mailer
|
|||
): void {
|
||||
if ($to instanceof User) {
|
||||
$locale = $locale ?: $to->settings->language;
|
||||
$to = $to->contact->email ? $to->contact->email : $to->email;
|
||||
$to = $to->contact->email ?: $to->email;
|
||||
}
|
||||
|
||||
$activeLocale = null;
|
||||
|
|
|
@ -14,7 +14,7 @@ class ShiftsTest extends TestCase
|
|||
/**
|
||||
* @covers \Engelsystem\Helpers\Shifts::isNightShift
|
||||
*/
|
||||
public function testIsNightShift()
|
||||
public function testIsNightShiftDisabled()
|
||||
{
|
||||
$config = new Config(['night_shifts' => [
|
||||
'enabled' => false,
|
||||
|
@ -29,38 +29,43 @@ class ShiftsTest extends TestCase
|
|||
new Carbon('2042-01-01 04:00'),
|
||||
new Carbon('2042-01-01 05:00')
|
||||
));
|
||||
}
|
||||
|
||||
$config->set('night_shifts', array_merge($config->get('night_shifts'), ['enabled' => true]));
|
||||
|
||||
/**
|
||||
* @return array[][]
|
||||
*/
|
||||
public function nightShiftData(): array
|
||||
{
|
||||
// $start, $end, $isNightShift
|
||||
return [
|
||||
// Is night shift
|
||||
$this->assertTrue(Shifts::isNightShift(
|
||||
new Carbon('2042-01-01 04:00'),
|
||||
new Carbon('2042-01-01 05:00')
|
||||
));
|
||||
|
||||
[new Carbon('2042-01-01 04:00'), new Carbon('2042-01-01 05:00'), true],
|
||||
// Starts as night shift
|
||||
$this->assertTrue(Shifts::isNightShift(
|
||||
new Carbon('2042-01-01 05:45'),
|
||||
new Carbon('2042-01-01 07:00')
|
||||
));
|
||||
|
||||
[new Carbon('2042-01-01 05:45'), new Carbon('2042-01-01 07:00'), true],
|
||||
// Ends as night shift
|
||||
$this->assertTrue(Shifts::isNightShift(
|
||||
new Carbon('2042-01-01 00:00'),
|
||||
new Carbon('2042-01-01 02:15')
|
||||
));
|
||||
|
||||
[new Carbon('2042-01-01 00:00'), new Carbon('2042-01-01 02:15'), true],
|
||||
// Too early
|
||||
$this->assertFalse(Shifts::isNightShift(
|
||||
new Carbon('2042-01-01 00:00'),
|
||||
new Carbon('2042-01-01 01:59')
|
||||
));
|
||||
|
||||
[new Carbon('2042-01-01 00:00'), new Carbon('2042-01-01 01:59'), false],
|
||||
// Too late
|
||||
$this->assertFalse(Shifts::isNightShift(
|
||||
new Carbon('2042-01-01 06:00'),
|
||||
new Carbon('2042-01-01 09:59')
|
||||
));
|
||||
[new Carbon('2042-01-01 06:00'), new Carbon('2042-01-01 09:59'), false],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Engelsystem\Helpers\Shifts::isNightShift
|
||||
* @dataProvider nightShiftData
|
||||
*/
|
||||
public function testIsNightShiftEnabled($start, $end, $isNightShift)
|
||||
{
|
||||
$config = new Config(['night_shifts' => [
|
||||
'enabled' => true,
|
||||
'start' => 2,
|
||||
'end' => 6,
|
||||
'multiplier' => 2,
|
||||
]]);
|
||||
$this->app->instance('config', $config);
|
||||
|
||||
$this->assertEquals($isNightShift, Shifts::isNightShift($start, $end));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue