Recreated shifts history page
This commit is contained in:
parent
ac74ab489d
commit
bf83e6a300
|
@ -153,6 +153,15 @@ $route->addGroup(
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Shifts
|
||||||
|
$route->addGroup(
|
||||||
|
'/shifts',
|
||||||
|
function (RouteCollector $route): void {
|
||||||
|
$route->get('/history', 'Admin\\ShiftsController@history');
|
||||||
|
$route->post('/history', 'Admin\\ShiftsController@deleteTransaction');
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
// Questions
|
// Questions
|
||||||
$route->addGroup(
|
$route->addGroup(
|
||||||
'/questions',
|
'/questions',
|
||||||
|
|
|
@ -219,7 +219,7 @@ function admin_arrive()
|
||||||
], $planned_arrival_at_day),
|
], $planned_arrival_at_day),
|
||||||
table([
|
table([
|
||||||
'day' => __('Date'),
|
'day' => __('Date'),
|
||||||
'count' => __('Count'),
|
'count' => __('general.count'),
|
||||||
'sum' => __('Sum'),
|
'sum' => __('Sum'),
|
||||||
], $planned_arrival_at_day),
|
], $planned_arrival_at_day),
|
||||||
]),
|
]),
|
||||||
|
@ -234,7 +234,7 @@ function admin_arrive()
|
||||||
], $arrival_at_day),
|
], $arrival_at_day),
|
||||||
table([
|
table([
|
||||||
'day' => __('Date'),
|
'day' => __('Date'),
|
||||||
'count' => __('Count'),
|
'count' => __('general.count'),
|
||||||
'sum' => __('Sum'),
|
'sum' => __('Sum'),
|
||||||
], $arrival_at_day),
|
], $arrival_at_day),
|
||||||
]),
|
]),
|
||||||
|
@ -249,7 +249,7 @@ function admin_arrive()
|
||||||
], $planned_departure_at_day),
|
], $planned_departure_at_day),
|
||||||
table([
|
table([
|
||||||
'day' => __('Date'),
|
'day' => __('Date'),
|
||||||
'count' => __('Count'),
|
'count' => __('general.count'),
|
||||||
'sum' => __('Sum'),
|
'sum' => __('Sum'),
|
||||||
], $planned_departure_at_day),
|
], $planned_departure_at_day),
|
||||||
]),
|
]),
|
||||||
|
|
|
@ -1,15 +1,11 @@
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
use Engelsystem\Database\Db;
|
|
||||||
use Engelsystem\Helpers\Carbon;
|
use Engelsystem\Helpers\Carbon;
|
||||||
use Engelsystem\Http\Exceptions\HttpForbidden;
|
|
||||||
use Engelsystem\Models\AngelType;
|
use Engelsystem\Models\AngelType;
|
||||||
use Engelsystem\Models\Location;
|
use Engelsystem\Models\Location;
|
||||||
use Engelsystem\Models\Shifts\NeededAngelType;
|
use Engelsystem\Models\Shifts\NeededAngelType;
|
||||||
use Engelsystem\Models\Shifts\Schedule;
|
|
||||||
use Engelsystem\Models\Shifts\Shift;
|
use Engelsystem\Models\Shifts\Shift;
|
||||||
use Engelsystem\Models\Shifts\ShiftType;
|
use Engelsystem\Models\Shifts\ShiftType;
|
||||||
use Engelsystem\Models\User\User;
|
|
||||||
use Illuminate\Database\Eloquent\Collection;
|
use Illuminate\Database\Eloquent\Collection;
|
||||||
use Illuminate\Support\Str;
|
use Illuminate\Support\Str;
|
||||||
|
|
||||||
|
@ -457,7 +453,7 @@ function admin_shifts()
|
||||||
return page_with_title(
|
return page_with_title(
|
||||||
$link . ' ' . admin_shifts_title() . ' ' . sprintf(
|
$link . ' ' . admin_shifts_title() . ' ' . sprintf(
|
||||||
'<a href="%s">%s</a>',
|
'<a href="%s">%s</a>',
|
||||||
url('/admin-shifts-history'),
|
url('/admin/shifts/history'),
|
||||||
icon('clock-history')
|
icon('clock-history')
|
||||||
),
|
),
|
||||||
[
|
[
|
||||||
|
@ -480,7 +476,7 @@ function admin_shifts()
|
||||||
div('col-lg-6', [
|
div('col-lg-6', [
|
||||||
form_datetime(
|
form_datetime(
|
||||||
'start',
|
'start',
|
||||||
__('Start'),
|
__('shifts.start'),
|
||||||
$request->has('start')
|
$request->has('start')
|
||||||
? Carbon::createFromDatetime($request->input('start'))
|
? Carbon::createFromDatetime($request->input('start'))
|
||||||
: $start
|
: $start
|
||||||
|
@ -489,7 +485,7 @@ function admin_shifts()
|
||||||
div('col-lg-6', [
|
div('col-lg-6', [
|
||||||
form_datetime(
|
form_datetime(
|
||||||
'end',
|
'end',
|
||||||
__('End'),
|
__('shifts.end'),
|
||||||
$request->has('end')
|
$request->has('end')
|
||||||
? Carbon::createFromDatetime($request->input('end'))
|
? Carbon::createFromDatetime($request->input('end'))
|
||||||
: $end
|
: $end
|
||||||
|
@ -565,99 +561,3 @@ function admin_shifts()
|
||||||
]
|
]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function admin_shifts_history_title(): string
|
|
||||||
{
|
|
||||||
return __('Shifts history');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Display shifts transaction history
|
|
||||||
*
|
|
||||||
* @return string
|
|
||||||
*/
|
|
||||||
function admin_shifts_history(): string
|
|
||||||
{
|
|
||||||
if (!auth()->can('admin_shifts')) {
|
|
||||||
throw new HttpForbidden();
|
|
||||||
}
|
|
||||||
|
|
||||||
$request = request();
|
|
||||||
$transactionId = $request->postData('transaction_id');
|
|
||||||
if ($request->hasPostData('delete') && $transactionId) {
|
|
||||||
$shifts = Shift::whereTransactionId($transactionId)->get();
|
|
||||||
|
|
||||||
engelsystem_log('Deleting ' . count($shifts) . ' shifts (transaction id ' . $transactionId . ')');
|
|
||||||
|
|
||||||
foreach ($shifts as $shift) {
|
|
||||||
$shift = Shift($shift);
|
|
||||||
foreach ($shift->shiftEntries as $entry) {
|
|
||||||
event('shift.entry.deleting', [
|
|
||||||
'user' => $entry->user,
|
|
||||||
'start' => $shift->start,
|
|
||||||
'end' => $shift->end,
|
|
||||||
'name' => $shift->shiftType->name,
|
|
||||||
'title' => $shift->title,
|
|
||||||
'type' => $entry->angelType->name,
|
|
||||||
'location' => $shift->location,
|
|
||||||
'freeloaded' => $entry->freeloaded,
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
$shift->delete();
|
|
||||||
|
|
||||||
engelsystem_log(
|
|
||||||
'Deleted shift ' . $shift->title . ' / ' . $shift->shiftType->name
|
|
||||||
. ' from ' . $shift->start->format('Y-m-d H:i')
|
|
||||||
. ' to ' . $shift->end->format('Y-m-d H:i')
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
success(sprintf(__('%s shifts deleted.'), count($shifts)));
|
|
||||||
throw_redirect(url('/admin-shifts-history'));
|
|
||||||
}
|
|
||||||
|
|
||||||
$schedules = Schedule::all()->pluck('name', 'id')->toArray();
|
|
||||||
$shiftsData = Db::select('
|
|
||||||
SELECT
|
|
||||||
s.transaction_id,
|
|
||||||
s.title,
|
|
||||||
schedule_shift.schedule_id,
|
|
||||||
COUNT(s.id) AS count,
|
|
||||||
MIN(s.start) AS start,
|
|
||||||
MAX(s.end) AS end,
|
|
||||||
s.created_by AS user_id,
|
|
||||||
MAX(s.created_at) AS created_at
|
|
||||||
FROM shifts AS s
|
|
||||||
LEFT JOIN schedule_shift on schedule_shift.shift_id = s.id
|
|
||||||
WHERE s.transaction_id IS NOT NULL
|
|
||||||
GROUP BY s.transaction_id
|
|
||||||
ORDER BY created_at DESC
|
|
||||||
');
|
|
||||||
|
|
||||||
foreach ($shiftsData as &$shiftData) {
|
|
||||||
$shiftData['title'] = $shiftData['schedule_id'] ? __('shifts_history.schedule', [$schedules[$shiftData['schedule_id']]]) : $shiftData['title'];
|
|
||||||
$shiftData['user'] = User_Nick_render(User::find($shiftData['user_id']));
|
|
||||||
$shiftData['start'] = Carbon::make($shiftData['start'])->format(__('Y-m-d H:i'));
|
|
||||||
$shiftData['end'] = Carbon::make($shiftData['end'])->format(__('Y-m-d H:i'));
|
|
||||||
$shiftData['created_at'] = Carbon::make($shiftData['created_at'])->format(__('Y-m-d H:i'));
|
|
||||||
$shiftData['actions'] = form([
|
|
||||||
form_hidden('transaction_id', $shiftData['transaction_id']),
|
|
||||||
form_submit('delete', icon('trash') . __('delete all'), 'btn-sm', true, 'danger'),
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
return page_with_title(admin_shifts_history_title(), [
|
|
||||||
msg(),
|
|
||||||
table([
|
|
||||||
'transaction_id' => __('ID'),
|
|
||||||
'title' => __('title.title'),
|
|
||||||
'count' => __('Count'),
|
|
||||||
'start' => __('Start'),
|
|
||||||
'end' => __('End'),
|
|
||||||
'user' => __('User'),
|
|
||||||
'created_at' => __('Created'),
|
|
||||||
'actions' => '',
|
|
||||||
], $shiftsData),
|
|
||||||
], true);
|
|
||||||
}
|
|
||||||
|
|
|
@ -99,7 +99,7 @@ function ShiftEntry_create_view_admin(
|
||||||
info(__('Do you want to sign up the following user for this shift?'), true),
|
info(__('Do you want to sign up the following user for this shift?'), true),
|
||||||
form([
|
form([
|
||||||
form_select('angeltype_id', __('Angeltype'), $angeltypes_select, $angeltype->id),
|
form_select('angeltype_id', __('Angeltype'), $angeltypes_select, $angeltype->id),
|
||||||
form_select('user_id', __('User'), $users_select, $signup_user->id),
|
form_select('user_id', __('general.user'), $users_select, $signup_user->id),
|
||||||
form_submit('submit', icon('check-lg') . __('form.save')),
|
form_submit('submit', icon('check-lg') . __('form.save')),
|
||||||
]),
|
]),
|
||||||
]
|
]
|
||||||
|
@ -134,7 +134,7 @@ function ShiftEntry_create_view_supporter(
|
||||||
$angeltype->name
|
$angeltype->name
|
||||||
), true),
|
), true),
|
||||||
form([
|
form([
|
||||||
form_select('user_id', __('User'), $users_select, $signup_user->id),
|
form_select('user_id', __('general.user'), $users_select, $signup_user->id),
|
||||||
form_submit('submit', icon('check-lg') . __('form.save')),
|
form_submit('submit', icon('check-lg') . __('form.save')),
|
||||||
]),
|
]),
|
||||||
]
|
]
|
||||||
|
|
|
@ -29,7 +29,7 @@ function Shift_view_header(Shift $shift, Location $location)
|
||||||
. '</p>',
|
. '</p>',
|
||||||
]),
|
]),
|
||||||
div('col-sm-3 col-xs-6', [
|
div('col-sm-3 col-xs-6', [
|
||||||
'<h4>' . __('Start') . '</h4>',
|
'<h4>' . __('shifts.start') . '</h4>',
|
||||||
'<p class="lead' . (time() >= $shift->start->timestamp ? ' text-success' : '') . '">',
|
'<p class="lead' . (time() >= $shift->start->timestamp ? ' text-success' : '') . '">',
|
||||||
icon('calendar-event') . $shift->start->format(__('Y-m-d')),
|
icon('calendar-event') . $shift->start->format(__('Y-m-d')),
|
||||||
'<br />',
|
'<br />',
|
||||||
|
@ -37,7 +37,7 @@ function Shift_view_header(Shift $shift, Location $location)
|
||||||
'</p>',
|
'</p>',
|
||||||
]),
|
]),
|
||||||
div('col-sm-3 col-xs-6', [
|
div('col-sm-3 col-xs-6', [
|
||||||
'<h4>' . __('End') . '</h4>',
|
'<h4>' . __('shifts.end') . '</h4>',
|
||||||
'<p class="lead' . (time() >= $shift->end->timestamp ? ' text-success' : '') . '">',
|
'<p class="lead' . (time() >= $shift->end->timestamp ? ' text-success' : '') . '">',
|
||||||
icon('calendar-event') . $shift->end->format(__('Y-m-d')),
|
icon('calendar-event') . $shift->end->format(__('Y-m-d')),
|
||||||
'<br />',
|
'<br />',
|
||||||
|
|
|
@ -153,7 +153,7 @@ function UserAngelType_add_view(AngelType $angeltype, $users_source, $user_id)
|
||||||
form([
|
form([
|
||||||
form_info(__('Angeltype'), $angeltype->name),
|
form_info(__('Angeltype'), $angeltype->name),
|
||||||
form_checkbox('auto_confirm_user', __('Confirm user'), true),
|
form_checkbox('auto_confirm_user', __('Confirm user'), true),
|
||||||
form_select('user_id', __('User'), $users, $user_id),
|
form_select('user_id', __('general.user'), $users, $user_id),
|
||||||
form_submit('submit', __('Add')),
|
form_submit('submit', __('Add')),
|
||||||
]),
|
]),
|
||||||
]);
|
]);
|
||||||
|
|
|
@ -280,3 +280,6 @@ msgstr "Die Registrierung ist deaktiviert."
|
||||||
|
|
||||||
msgid "registration.successful"
|
msgid "registration.successful"
|
||||||
msgstr "Registrierung erfolgreich. Du kannst dich jetzt anmelden!"
|
msgstr "Registrierung erfolgreich. Du kannst dich jetzt anmelden!"
|
||||||
|
|
||||||
|
msgid "shifts.history.delete.success"
|
||||||
|
msgstr "Schichten erfolgreich gelöscht."
|
||||||
|
|
|
@ -317,18 +317,6 @@ msgstr "Benötigte Engel"
|
||||||
msgid "Shift deleted."
|
msgid "Shift deleted."
|
||||||
msgstr "Schicht gelöscht."
|
msgstr "Schicht gelöscht."
|
||||||
|
|
||||||
msgid "Shifts history"
|
|
||||||
msgstr "Schichten Historie"
|
|
||||||
|
|
||||||
msgid "%s shifts deleted."
|
|
||||||
msgstr "%s Schichten gelöscht."
|
|
||||||
|
|
||||||
msgid "Created"
|
|
||||||
msgstr "Erstellt"
|
|
||||||
|
|
||||||
msgid "delete all"
|
|
||||||
msgstr "alle löschen"
|
|
||||||
|
|
||||||
msgid "Do you want to delete the shift %s from %s to %s?"
|
msgid "Do you want to delete the shift %s from %s to %s?"
|
||||||
msgstr "Möchtest Du die Schicht %s von %s bis %s löschen?"
|
msgstr "Möchtest Du die Schicht %s von %s bis %s löschen?"
|
||||||
|
|
||||||
|
@ -634,9 +622,6 @@ msgstr "Summe angekommen"
|
||||||
msgid "Date"
|
msgid "Date"
|
||||||
msgstr "Datum"
|
msgstr "Datum"
|
||||||
|
|
||||||
msgid "Count"
|
|
||||||
msgstr "Anzahl"
|
|
||||||
|
|
||||||
msgid "Arrival statistics"
|
msgid "Arrival statistics"
|
||||||
msgstr "Ankunfts-Statistik"
|
msgstr "Ankunfts-Statistik"
|
||||||
|
|
||||||
|
@ -673,12 +658,6 @@ msgstr "Gruppe bearbeiten"
|
||||||
msgid "Please select a shift type."
|
msgid "Please select a shift type."
|
||||||
msgstr "Bitte einen Schichttyp wählen."
|
msgstr "Bitte einen Schichttyp wählen."
|
||||||
|
|
||||||
msgid "Start"
|
|
||||||
msgstr "Beginn"
|
|
||||||
|
|
||||||
msgid "End"
|
|
||||||
msgstr "Ende"
|
|
||||||
|
|
||||||
msgid "Location"
|
msgid "Location"
|
||||||
msgstr "Ort"
|
msgstr "Ort"
|
||||||
|
|
||||||
|
@ -1112,9 +1091,6 @@ msgstr "Von Schicht austragen"
|
||||||
msgid "Do you want to sign up the following user for this shift?"
|
msgid "Do you want to sign up the following user for this shift?"
|
||||||
msgstr "Möchtest du den folgenden User für die Schicht eintragen?"
|
msgstr "Möchtest du den folgenden User für die Schicht eintragen?"
|
||||||
|
|
||||||
msgid "User"
|
|
||||||
msgstr "Benutzer"
|
|
||||||
|
|
||||||
msgid "Do you want to sign up the following user for this shift as %s?"
|
msgid "Do you want to sign up the following user for this shift as %s?"
|
||||||
msgstr "Möchtest du den folgenden User als %s in die Schicht eintragen?"
|
msgstr "Möchtest du den folgenden User als %s in die Schicht eintragen?"
|
||||||
|
|
||||||
|
@ -1542,9 +1518,6 @@ msgstr "Typ"
|
||||||
msgid "schedule.import.shift.location"
|
msgid "schedule.import.shift.location"
|
||||||
msgstr "Ort"
|
msgstr "Ort"
|
||||||
|
|
||||||
msgid "shifts_history.schedule"
|
|
||||||
msgstr "Programm: %s"
|
|
||||||
|
|
||||||
msgid "news.title"
|
msgid "news.title"
|
||||||
msgstr "News"
|
msgstr "News"
|
||||||
|
|
||||||
|
@ -2010,3 +1983,30 @@ msgstr "Registrieren"
|
||||||
|
|
||||||
msgid "confirmation.delete"
|
msgid "confirmation.delete"
|
||||||
msgstr "Möchtest du es wirklich löschen?"
|
msgstr "Möchtest du es wirklich löschen?"
|
||||||
|
|
||||||
|
msgid "general.id"
|
||||||
|
msgstr "ID"
|
||||||
|
|
||||||
|
msgid "general.user"
|
||||||
|
msgstr "Benutzer"
|
||||||
|
|
||||||
|
msgid "general.count"
|
||||||
|
msgstr "Anzahl"
|
||||||
|
|
||||||
|
msgid "general.created_at"
|
||||||
|
msgstr "Erstellt am"
|
||||||
|
|
||||||
|
msgid "shifts.history"
|
||||||
|
msgstr "Schichten Historie"
|
||||||
|
|
||||||
|
msgid "shifts.history.schedule"
|
||||||
|
msgstr "Programm: %s"
|
||||||
|
|
||||||
|
msgid "shifts.history.delete_all.title"
|
||||||
|
msgstr "%u Schichten löschen"
|
||||||
|
|
||||||
|
msgid "shifts.start"
|
||||||
|
msgstr "Start"
|
||||||
|
|
||||||
|
msgid "shifts.end"
|
||||||
|
msgstr "Ende"
|
||||||
|
|
|
@ -279,3 +279,6 @@ msgstr "The registration is disabled."
|
||||||
|
|
||||||
msgid "registration.successful"
|
msgid "registration.successful"
|
||||||
msgstr "Registration successful. You can now log in!"
|
msgstr "Registration successful. You can now log in!"
|
||||||
|
|
||||||
|
msgid "shifts.history.delete.success"
|
||||||
|
msgstr "Shifts deleted successfully."
|
||||||
|
|
|
@ -157,9 +157,6 @@ msgstr "Title"
|
||||||
msgid "schedule.import.shift.location"
|
msgid "schedule.import.shift.location"
|
||||||
msgstr "Location"
|
msgstr "Location"
|
||||||
|
|
||||||
msgid "shifts_history.schedule"
|
|
||||||
msgstr "Schedule: %s"
|
|
||||||
|
|
||||||
msgid "news.title"
|
msgid "news.title"
|
||||||
msgstr "News"
|
msgstr "News"
|
||||||
|
|
||||||
|
@ -662,3 +659,30 @@ msgstr "Please enter a mobile number in your settings!"
|
||||||
|
|
||||||
msgid "confirmation.delete"
|
msgid "confirmation.delete"
|
||||||
msgstr "Do you really want to delete it?"
|
msgstr "Do you really want to delete it?"
|
||||||
|
|
||||||
|
msgid "general.id"
|
||||||
|
msgstr "ID"
|
||||||
|
|
||||||
|
msgid "general.user"
|
||||||
|
msgstr "User"
|
||||||
|
|
||||||
|
msgid "general.count"
|
||||||
|
msgstr "Count"
|
||||||
|
|
||||||
|
msgid "general.created_at"
|
||||||
|
msgstr "Created at"
|
||||||
|
|
||||||
|
msgid "shifts.history"
|
||||||
|
msgstr "Shifts history"
|
||||||
|
|
||||||
|
msgid "shifts.history.schedule"
|
||||||
|
msgstr "Schedule: %s"
|
||||||
|
|
||||||
|
msgid "shifts.history.delete_all.title"
|
||||||
|
msgstr "Delete %u shifts"
|
||||||
|
|
||||||
|
msgid "shifts.start"
|
||||||
|
msgstr "Start"
|
||||||
|
|
||||||
|
msgid "shifts.end"
|
||||||
|
msgstr "End"
|
||||||
|
|
|
@ -0,0 +1,71 @@
|
||||||
|
{% extends 'layouts/app.twig' %}
|
||||||
|
{% import 'macros/base.twig' as m %}
|
||||||
|
{% import 'macros/form.twig' as f %}
|
||||||
|
|
||||||
|
{% set title %}{% block title %}{{ __('shifts.history') }}{% endblock %}{% endset %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div class="container">
|
||||||
|
<h1>
|
||||||
|
{{ m.button(m.icon('chevron-left'), url('/admin-shifts'), null, 'sm') }}
|
||||||
|
{% block content_title %}{{ title }}{% endblock %}
|
||||||
|
</h1>
|
||||||
|
|
||||||
|
{% include 'layouts/parts/messages.twig' %}
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
{% block row_content %}
|
||||||
|
<div class="col-md-12">
|
||||||
|
<div class="table-responsive">
|
||||||
|
<table class="table table-striped">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>{{ __('general.id') }}</th>
|
||||||
|
<th>{{ __('title.title') }}</th>
|
||||||
|
<th>{{ __('general.count') }}</th>
|
||||||
|
<th>{{ __('shifts.start') }}</th>
|
||||||
|
<th>{{ __('shifts.end') }}</th>
|
||||||
|
<th>{{ __('general.user') }}</th>
|
||||||
|
<th>{{ __('general.created_at') }}</th>
|
||||||
|
<th></th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
|
||||||
|
<tbody>
|
||||||
|
{% for shift in shifts %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ shift.transaction_id }}</td>
|
||||||
|
<td>
|
||||||
|
{% if shift.schedule %}
|
||||||
|
{{ __('shifts.history.schedule', [shift.schedule.name]) }}
|
||||||
|
{% else %}
|
||||||
|
{{ shift.title }}
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td>{{ shift.count }}</td>
|
||||||
|
<td>{{ shift.start.format(__('Y-m-d H:i')) }}</td>
|
||||||
|
<td>{{ shift.end.format(__('Y-m-d H:i')) }}</td>
|
||||||
|
<td>{{ m.user(shift.createdBy) }}</td>
|
||||||
|
<td>{{ shift.created_at.format(__('Y-m-d H:i')) }}</td>
|
||||||
|
<td>
|
||||||
|
<form method="post" class="ps-1">
|
||||||
|
{{ csrf() }}
|
||||||
|
{{ f.hidden('transaction_id', shift.transaction_id) }}
|
||||||
|
{{ f.delete(null, {
|
||||||
|
'size': 'sm',
|
||||||
|
'title': __('form.delete_all'),
|
||||||
|
'confirm_title': __('shifts.history.delete_all.title', [shift.count]),
|
||||||
|
'confirm_button_text': __('form.delete_all'),
|
||||||
|
}) }}
|
||||||
|
</form>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
|
@ -18,7 +18,7 @@
|
||||||
<div class="row g-2">
|
<div class="row g-2">
|
||||||
<div class="col-12">
|
<div class="col-12">
|
||||||
<div>
|
<div>
|
||||||
<label class="form-label">{{ __('User') }}</label>
|
<label class="form-label">{{ __('general.user') }}</label>
|
||||||
</div>
|
</div>
|
||||||
{{ m.user(user, {'pronoun': true}) }}
|
{{ m.user(user, {'pronoun': true}) }}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -0,0 +1,94 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Engelsystem\Controllers\Admin;
|
||||||
|
|
||||||
|
use Engelsystem\Controllers\BaseController;
|
||||||
|
use Engelsystem\Controllers\HasUserNotifications;
|
||||||
|
use Engelsystem\Http\Redirector;
|
||||||
|
use Engelsystem\Http\Request;
|
||||||
|
use Engelsystem\Http\Response;
|
||||||
|
use Engelsystem\Models\Shifts\Shift;
|
||||||
|
use Illuminate\Database\Eloquent\Collection;
|
||||||
|
use Psr\Log\LoggerInterface;
|
||||||
|
|
||||||
|
class ShiftsController extends BaseController
|
||||||
|
{
|
||||||
|
use HasUserNotifications;
|
||||||
|
|
||||||
|
/** @var array<string> */
|
||||||
|
protected array $permissions = [
|
||||||
|
'admin_shifts',
|
||||||
|
];
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
protected LoggerInterface $log,
|
||||||
|
protected Shift $shift,
|
||||||
|
protected Redirector $redirect,
|
||||||
|
protected Response $response
|
||||||
|
) {
|
||||||
|
}
|
||||||
|
|
||||||
|
public function history(): Response
|
||||||
|
{
|
||||||
|
$shifts = $this->shift
|
||||||
|
->select()
|
||||||
|
->selectRaw('MIN(start) AS start')
|
||||||
|
->selectRaw('MAX(end) AS end')
|
||||||
|
->selectRaw('COUNT(*) AS count')
|
||||||
|
->selectRaw('MIN(created_at) AS created_at')
|
||||||
|
->with(['schedule', 'createdBy'])
|
||||||
|
->whereNotNull('transaction_id')
|
||||||
|
->groupBy('transaction_id')
|
||||||
|
->orderByDesc('created_at')
|
||||||
|
->get();
|
||||||
|
return $this->response->withView('admin/shifts/history', ['shifts' => $shifts]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function deleteTransaction(Request $request): Response
|
||||||
|
{
|
||||||
|
$transactionId = $request->postData('transaction_id');
|
||||||
|
|
||||||
|
/** @var Shift[]|Collection $shifts */
|
||||||
|
$shifts = $this->shift->with([
|
||||||
|
'location',
|
||||||
|
'shiftEntries',
|
||||||
|
'shiftEntries.angelType',
|
||||||
|
'shiftEntries.user',
|
||||||
|
'shiftType',
|
||||||
|
])->where('transaction_id', $transactionId)->get();
|
||||||
|
|
||||||
|
$this->log->info(
|
||||||
|
'Deleting {count} shifts with transaction ID: {id}',
|
||||||
|
['count' => $shifts->count(), 'id' => $transactionId]
|
||||||
|
);
|
||||||
|
|
||||||
|
foreach ($shifts as $shift) {
|
||||||
|
foreach ($shift->shiftEntries as $entry) {
|
||||||
|
event('shift.entry.deleting', [
|
||||||
|
'user' => $entry->user,
|
||||||
|
'start' => $shift->start,
|
||||||
|
'end' => $shift->end,
|
||||||
|
'name' => $shift->shiftType->name,
|
||||||
|
'title' => $shift->title,
|
||||||
|
'type' => $entry->angelType->name,
|
||||||
|
'location' => $shift->location,
|
||||||
|
'freeloaded' => $entry->freeloaded,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
$shift->delete();
|
||||||
|
|
||||||
|
$this->log->info(
|
||||||
|
'Deleted shift ' . $shift->title . ' / ' . $shift->shiftType->name
|
||||||
|
. ' from ' . $shift->start->format('Y-m-d H:i')
|
||||||
|
. ' to ' . $shift->end->format('Y-m-d H:i')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->addNotification('shifts.history.delete.success');
|
||||||
|
|
||||||
|
return $this->redirect->back();
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,7 +24,6 @@ class LegacyMiddleware implements MiddlewareInterface
|
||||||
'shift_entries',
|
'shift_entries',
|
||||||
'shifts',
|
'shifts',
|
||||||
'users',
|
'users',
|
||||||
'admin_shifts_history',
|
|
||||||
];
|
];
|
||||||
|
|
||||||
public function __construct(protected ContainerInterface $container, protected Authenticator $auth)
|
public function __construct(protected ContainerInterface $container, protected Authenticator $auth)
|
||||||
|
@ -129,8 +128,6 @@ class LegacyMiddleware implements MiddlewareInterface
|
||||||
$title = admin_shifts_title();
|
$title = admin_shifts_title();
|
||||||
$content = admin_shifts();
|
$content = admin_shifts();
|
||||||
return [$title, $content];
|
return [$title, $content];
|
||||||
case 'admin_shifts_history':
|
|
||||||
return [admin_shifts_history_title(), admin_shifts_history()];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
throw_redirect(url('/login'));
|
throw_redirect(url('/login'));
|
||||||
|
|
|
@ -0,0 +1,83 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
namespace Engelsystem\Test\Unit\Controllers\Admin;
|
||||||
|
|
||||||
|
use Engelsystem\Controllers\Admin\ShiftsController;
|
||||||
|
use Engelsystem\Events\EventDispatcher;
|
||||||
|
use Engelsystem\Helpers\Uuid;
|
||||||
|
use Engelsystem\Http\Redirector;
|
||||||
|
use Engelsystem\Http\Request;
|
||||||
|
use Engelsystem\Models\Shifts\Shift;
|
||||||
|
use Engelsystem\Models\Shifts\ShiftEntry;
|
||||||
|
use Engelsystem\Test\Unit\Controllers\ControllerTest;
|
||||||
|
use PHPUnit\Framework\MockObject\MockObject;
|
||||||
|
|
||||||
|
class ShiftsControllerTest extends ControllerTest
|
||||||
|
{
|
||||||
|
protected Redirector|MockObject $redirect;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Controllers\Admin\ShiftsController::__construct
|
||||||
|
* @covers \Engelsystem\Controllers\Admin\ShiftsController::history
|
||||||
|
*/
|
||||||
|
public function testHistory(): void
|
||||||
|
{
|
||||||
|
$this->response->expects($this->once())
|
||||||
|
->method('withView')
|
||||||
|
->willReturnCallback(function (string $view, array $data) {
|
||||||
|
$this->assertEquals('admin/shifts/history', $view);
|
||||||
|
$this->assertCount(2, $data['shifts'] ?? []);
|
||||||
|
return $this->response;
|
||||||
|
});
|
||||||
|
|
||||||
|
/** @var ShiftsController $controller */
|
||||||
|
$controller = $this->app->make(ShiftsController::class);
|
||||||
|
$controller->history();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @covers \Engelsystem\Controllers\Admin\ShiftsController::deleteTransaction
|
||||||
|
*/
|
||||||
|
public function testDeleteTransaction(): void
|
||||||
|
{
|
||||||
|
$this->database->getConnection()->getRawPdo()->exec('PRAGMA foreign_keys = ON');
|
||||||
|
|
||||||
|
$this->redirect->expects($this->once())
|
||||||
|
->method('back')
|
||||||
|
->willReturn($this->response);
|
||||||
|
/** @var Shift $shift */
|
||||||
|
$shift = Shift::factory(3)->create(['transaction_id' => Uuid::uuid()])->last();
|
||||||
|
ShiftEntry::factory(2)->create(['shift_id' => $shift->id]);
|
||||||
|
|
||||||
|
/** @var EventDispatcher|MockObject $event */
|
||||||
|
$event = $this->createMock(EventDispatcher::class);
|
||||||
|
$this->app->instance('events.dispatcher', $event);
|
||||||
|
$this->setExpects($event, 'dispatch', ['shift.entry.deleting'], [], $this->exactly(2));
|
||||||
|
|
||||||
|
/** @var ShiftsController $controller */
|
||||||
|
$controller = $this->app->make(ShiftsController::class);
|
||||||
|
$controller->deleteTransaction(new Request([], ['transaction_id' => $shift->transaction_id]));
|
||||||
|
|
||||||
|
$this->assertCount(6, Shift::all());
|
||||||
|
$this->assertCount(3, ShiftEntry::all());
|
||||||
|
$this->log->hasInfoThatContains('Deleted shift');
|
||||||
|
$this->log->hasInfoThatContains('shifts with transaction ID');
|
||||||
|
$this->assertHasNotification('shifts.history.delete.success');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setUp(): void
|
||||||
|
{
|
||||||
|
parent::setUp();
|
||||||
|
|
||||||
|
$this->redirect = $this->createMock(Redirector::class);
|
||||||
|
$this->app->instance(Redirector::class, $this->redirect);
|
||||||
|
|
||||||
|
Shift::factory(1)->create(['transaction_id' => null]);
|
||||||
|
Shift::factory(4)->create(['transaction_id' => Uuid::uuid()]);
|
||||||
|
$shift = Shift::factory(1)->create(['transaction_id' => Uuid::uuid()])->first();
|
||||||
|
|
||||||
|
ShiftEntry::factory(3)->create(['shift_id' => $shift->id]);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue