Add ShiftEntry model
This commit is contained in:
parent
89f9b423b1
commit
89dc85c3d5
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
|
||||
namespace Database\Factories\Engelsystem\Models\Shifts;
|
||||
|
||||
use Engelsystem\Models\AngelType;
|
||||
use Engelsystem\Models\Shifts\Shift;
|
||||
use Engelsystem\Models\Shifts\ShiftEntry;
|
||||
use Engelsystem\Models\User\User;
|
||||
use Illuminate\Database\Eloquent\Factories\Factory;
|
||||
|
||||
class ShiftEntryFactory extends Factory
|
||||
{
|
||||
/** @var string */
|
||||
protected $model = ShiftEntry::class; // phpcs:ignore
|
||||
|
||||
public function definition(): array
|
||||
{
|
||||
$freeloaded = $this->faker->optional(.01, false)->boolean();
|
||||
|
||||
return [
|
||||
'shift_id' => Shift::factory(),
|
||||
'angel_type_id' => AngelType::factory(),
|
||||
'user_id' => User::factory(),
|
||||
'user_comment' => $this->faker->optional(.05, '')->text(),
|
||||
'freeloaded' => $freeloaded,
|
||||
'freeloaded_comment' => $freeloaded ? $this->faker->text() : '',
|
||||
];
|
||||
}
|
||||
}
|
|
@ -0,0 +1,114 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Engelsystem\Migrations;
|
||||
|
||||
use Engelsystem\Database\Migration\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use stdClass;
|
||||
|
||||
class CreateShiftEntriesTable extends Migration
|
||||
{
|
||||
use ChangesReferences;
|
||||
use Reference;
|
||||
|
||||
/**
|
||||
* Creates the new table, copies the data and drops the old one
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
$connection = $this->schema->getConnection();
|
||||
$previous = $this->schema->hasTable('ShiftEntry');
|
||||
|
||||
$this->schema->create('shift_entries', function (Blueprint $table): void {
|
||||
$table->increments('id');
|
||||
$this->references($table, 'shifts');
|
||||
$this->references($table, 'angel_types');
|
||||
$this->referencesUser($table);
|
||||
|
||||
$table->mediumText('user_comment')->default('');
|
||||
|
||||
$table->boolean('freeloaded')->default(false)->index();
|
||||
$table->mediumText('freeloaded_comment')->default('');
|
||||
|
||||
$table->index(['angel_type_id', 'shift_id']);
|
||||
});
|
||||
|
||||
if (!$previous) {
|
||||
return;
|
||||
}
|
||||
|
||||
/** @var stdClass[] $records */
|
||||
$records = $connection
|
||||
->table('ShiftEntry')
|
||||
->get();
|
||||
foreach ($records as $record) {
|
||||
$connection->table('shift_entries')->insert([
|
||||
'id' => $record->id,
|
||||
'shift_id' => $record->SID,
|
||||
'angel_type_id' => $record->TID,
|
||||
'user_id' => $record->UID,
|
||||
'user_comment' => $record->Comment,
|
||||
'freeloaded' => (bool) $record->freeloaded,
|
||||
'freeloaded_comment' => $record->freeload_comment,
|
||||
]);
|
||||
}
|
||||
|
||||
$this->changeReferences(
|
||||
'ShiftEntry',
|
||||
'id',
|
||||
'shift_entries',
|
||||
'id'
|
||||
);
|
||||
|
||||
$this->schema->drop('ShiftEntry');
|
||||
}
|
||||
|
||||
/**
|
||||
* Recreates the previous table, copies the data and drops the new one
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
$connection = $this->schema->getConnection();
|
||||
|
||||
$this->schema->create('ShiftEntry', function (Blueprint $table): void {
|
||||
$table->increments('id');
|
||||
$this->references($table, 'shifts', 'SID')->default(0);
|
||||
$this->references($table, 'angel_types', 'TID')->default(0);
|
||||
$this->references($table, 'users', 'UID')->default(0);
|
||||
|
||||
$table->mediumText('Comment')->nullable();
|
||||
|
||||
$table->mediumText('freeload_comment')->nullable()->default(null);
|
||||
$table->boolean('freeloaded')->index();
|
||||
|
||||
$table->index(['SID', 'TID']);
|
||||
});
|
||||
|
||||
/** @var stdClass[] $records */
|
||||
$records = $connection
|
||||
->table('shift_entries')
|
||||
->get();
|
||||
foreach ($records as $record) {
|
||||
$connection->table('ShiftEntry')->insert([
|
||||
'id' => $record->id,
|
||||
'SID' => $record->shift_id,
|
||||
'TID' => $record->angel_type_id,
|
||||
'UID' => $record->user_id,
|
||||
'Comment' => $record->user_comment,
|
||||
'freeloaded' => (bool) $record->freeloaded,
|
||||
'freeload_comment' => $record->freeloaded_comment,
|
||||
]);
|
||||
}
|
||||
|
||||
$this->changeReferences(
|
||||
'shift_entries',
|
||||
'id',
|
||||
'ShiftEntry',
|
||||
'id'
|
||||
);
|
||||
|
||||
$this->schema->drop('shift_entries');
|
||||
}
|
||||
}
|
|
@ -107,8 +107,8 @@ function public_dashboard_needed_angels($needed_angels, ShiftsFilter $filter = n
|
|||
$result = [];
|
||||
foreach ($needed_angels as $needed_angel) {
|
||||
$need = $needed_angel['count'] - $needed_angel['taken'];
|
||||
if ($need > 0 && (!$filter || in_array($needed_angel['TID'], $filter->getTypes()))) {
|
||||
$angeltype = AngelType::find($needed_angel['TID']);
|
||||
if ($need > 0 && (!$filter || in_array($needed_angel['angel_type_id'], $filter->getTypes()))) {
|
||||
$angeltype = AngelType::find($needed_angel['angel_type_id']);
|
||||
if ($angeltype->show_on_dashboard) {
|
||||
$result[] = [
|
||||
'need' => $need,
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
use Engelsystem\Models\AngelType;
|
||||
use Engelsystem\Models\Shifts\Shift;
|
||||
use Engelsystem\Models\Shifts\ShiftEntry;
|
||||
use Engelsystem\Models\User\User;
|
||||
use Engelsystem\Models\UserAngelType;
|
||||
use Engelsystem\ShiftSignupState;
|
||||
|
@ -41,7 +42,7 @@ function shift_entry_create_controller(): array
|
|||
$user = auth()->user();
|
||||
$request = request();
|
||||
|
||||
if (User_is_freeloader($user)) {
|
||||
if ($user->isFreeloader()) {
|
||||
throw_redirect(page_link_to('user_myshifts'));
|
||||
}
|
||||
|
||||
|
@ -99,14 +100,12 @@ function shift_entry_create_controller_admin(Shift $shift, ?AngelType $angeltype
|
|||
}
|
||||
|
||||
if ($request->hasPostData('submit')) {
|
||||
ShiftEntry_create([
|
||||
'SID' => $shift->id,
|
||||
'TID' => $angeltype->id,
|
||||
'UID' => $signup_user->id,
|
||||
'Comment' => '',
|
||||
'freeloaded' => false,
|
||||
'freeload_comment' => ''
|
||||
]);
|
||||
$shiftEntry = new ShiftEntry();
|
||||
$shiftEntry->shift()->associate($shift);
|
||||
$shiftEntry->angelType()->associate($angeltype);
|
||||
$shiftEntry->user()->associate($signup_user);
|
||||
$shiftEntry->save();
|
||||
ShiftEntry_onCreate($shiftEntry);
|
||||
|
||||
success(sprintf(__('%s has been subscribed to the shift.'), User_Nick_render($signup_user)));
|
||||
throw_redirect(shift_link($shift));
|
||||
|
@ -150,14 +149,12 @@ function shift_entry_create_controller_supporter(Shift $shift, AngelType $angelt
|
|||
}
|
||||
|
||||
if ($request->hasPostData('submit')) {
|
||||
ShiftEntry_create([
|
||||
'SID' => $shift->id,
|
||||
'TID' => $angeltype->id,
|
||||
'UID' => $signup_user->id,
|
||||
'Comment' => '',
|
||||
'freeloaded' => false,
|
||||
'freeload_comment' => ''
|
||||
]);
|
||||
$shiftEntry = new ShiftEntry();
|
||||
$shiftEntry->shift()->associate($shift);
|
||||
$shiftEntry->angelType()->associate($angeltype);
|
||||
$shiftEntry->user()->associate($signup_user);
|
||||
$shiftEntry->save();
|
||||
ShiftEntry_onCreate($shiftEntry);
|
||||
|
||||
success(sprintf(__('%s has been subscribed to the shift.'), User_Nick_render($signup_user)));
|
||||
throw_redirect(shift_link($shift));
|
||||
|
@ -214,7 +211,9 @@ function shift_entry_create_controller_user(Shift $shift, AngelType $angeltype):
|
|||
|
||||
$signup_user = auth()->user();
|
||||
$needed_angeltype = (new AngelType())->forceFill(NeededAngeltype_by_Shift_and_Angeltype($shift, $angeltype));
|
||||
$shift_entries = ShiftEntries_by_shift_and_angeltype($shift->id, $angeltype->id);
|
||||
$shift_entries = $shift->shiftEntries()
|
||||
->where('angel_type_id', $angeltype->id)
|
||||
->get();
|
||||
$shift_signup_state = Shift_signup_allowed(
|
||||
$signup_user,
|
||||
$shift,
|
||||
|
@ -232,14 +231,14 @@ function shift_entry_create_controller_user(Shift $shift, AngelType $angeltype):
|
|||
$comment = '';
|
||||
if ($request->hasPostData('submit')) {
|
||||
$comment = strip_request_item_nl('comment');
|
||||
ShiftEntry_create([
|
||||
'SID' => $shift->id,
|
||||
'TID' => $angeltype->id,
|
||||
'UID' => $signup_user->id,
|
||||
'Comment' => $comment,
|
||||
'freeloaded' => false,
|
||||
'freeload_comment' => ''
|
||||
]);
|
||||
|
||||
$shiftEntry = new ShiftEntry();
|
||||
$shiftEntry->shift()->associate($shift);
|
||||
$shiftEntry->angelType()->associate($angeltype);
|
||||
$shiftEntry->user()->associate($signup_user);
|
||||
$shiftEntry->user_comment = $comment;
|
||||
$shiftEntry->save();
|
||||
ShiftEntry_onCreate($shiftEntry);
|
||||
|
||||
if (
|
||||
!$angeltype->restricted
|
||||
|
@ -299,7 +298,7 @@ function shift_entry_create_link_admin(Shift $shift, $params = [])
|
|||
/**
|
||||
* Load a shift entry from get parameter shift_entry_id.
|
||||
*
|
||||
* @return array
|
||||
* @return ShiftEntry
|
||||
*/
|
||||
function shift_entry_load()
|
||||
{
|
||||
|
@ -308,11 +307,7 @@ function shift_entry_load()
|
|||
if (!$request->has('shift_entry_id') || !test_request_int('shift_entry_id')) {
|
||||
throw_redirect(page_link_to('user_shifts'));
|
||||
}
|
||||
$shiftEntry = ShiftEntry($request->input('shift_entry_id'));
|
||||
if (empty($shiftEntry)) {
|
||||
error(__('Shift entry not found.'));
|
||||
throw_redirect(page_link_to('user_shifts'));
|
||||
}
|
||||
$shiftEntry = ShiftEntry::findOrFail($request->input('shift_entry_id'));
|
||||
|
||||
return $shiftEntry;
|
||||
}
|
||||
|
@ -328,9 +323,9 @@ function shift_entry_delete_controller()
|
|||
$request = request();
|
||||
$shiftEntry = shift_entry_load();
|
||||
|
||||
$shift = Shift($shiftEntry['SID']);
|
||||
$angeltype = AngelType::find($shiftEntry['TID']);
|
||||
$signout_user = User::find($shiftEntry['UID']);
|
||||
$shift = Shift($shiftEntry->shift);
|
||||
$angeltype = $shiftEntry->angelType;
|
||||
$signout_user = $shiftEntry->user;
|
||||
if (!Shift_signout_allowed($shift, $angeltype, $signout_user->id)) {
|
||||
error(__(
|
||||
'You are not allowed to remove this shift entry. If necessary, ask your supporter or heaven to do so.'
|
||||
|
@ -339,7 +334,8 @@ function shift_entry_delete_controller()
|
|||
}
|
||||
|
||||
if ($request->hasPostData('delete')) {
|
||||
ShiftEntry_delete($shiftEntry);
|
||||
$shiftEntry->delete();
|
||||
ShiftEntry_onDelete($shiftEntry);
|
||||
success(__('Shift entry removed.'));
|
||||
throw_redirect(shift_link($shift));
|
||||
}
|
||||
|
@ -347,7 +343,7 @@ function shift_entry_delete_controller()
|
|||
if ($user->id == $signout_user->id) {
|
||||
return [
|
||||
ShiftEntry_delete_title(),
|
||||
ShiftEntry_delete_view($shift, $angeltype, $signout_user->id)
|
||||
ShiftEntry_delete_view($shift, $angeltype, $signout_user)
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -360,7 +356,7 @@ function shift_entry_delete_controller()
|
|||
/**
|
||||
* Link to delete a shift entry.
|
||||
*
|
||||
* @param array|Shift $shiftEntry
|
||||
* @param Shift|ShiftEntry $shiftEntry
|
||||
* @param array $params
|
||||
* @return string URL
|
||||
*/
|
||||
|
|
|
@ -6,7 +6,6 @@ use Engelsystem\Models\AngelType;
|
|||
use Engelsystem\Models\Shifts\ScheduleShift;
|
||||
use Engelsystem\Models\Shifts\Shift;
|
||||
use Engelsystem\Models\Shifts\ShiftType;
|
||||
use Engelsystem\Models\User\User;
|
||||
use Engelsystem\ShiftSignupState;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
|
@ -159,7 +158,6 @@ function shift_edit_controller()
|
|||
$shift->updatedBy()->associate(auth()->user());
|
||||
|
||||
// Remove merged data as it is not really part of the model and thus can't be saved
|
||||
unset($shift->shiftEntry);
|
||||
unset($shift->neededAngels);
|
||||
|
||||
$shift->save();
|
||||
|
@ -244,17 +242,16 @@ function shift_delete_controller()
|
|||
|
||||
// Schicht löschen bestätigt
|
||||
if ($request->hasPostData('delete')) {
|
||||
foreach ($shift->shiftEntry as $entry) {
|
||||
$type = AngelType::find($entry['TID']);
|
||||
foreach ($shift->shiftEntries as $entry) {
|
||||
event('shift.entry.deleting', [
|
||||
'user' => User::find($entry['user_id']),
|
||||
'user' => $entry->user,
|
||||
'start' => $shift->start,
|
||||
'end' => $shift->end,
|
||||
'name' => $shift->shiftType->name,
|
||||
'title' => $shift->title,
|
||||
'type' => $type->name,
|
||||
'type' => $entry->angelType->name,
|
||||
'room' => $shift->room,
|
||||
'freeloaded' => (bool) $entry['freeloaded'],
|
||||
'freeloaded' => $entry->freeloaded,
|
||||
]);
|
||||
}
|
||||
|
||||
|
@ -318,7 +315,9 @@ function shift_controller()
|
|||
continue;
|
||||
}
|
||||
|
||||
$shift_entries = ShiftEntries_by_shift_and_angeltype($shift->id, $angeltype->id);
|
||||
$shift_entries = $shift->shiftEntries()
|
||||
->where('angel_type_id', $angeltype->id)
|
||||
->get();
|
||||
$needed_angeltype = (new AngelType())->forceFill($needed_angeltype);
|
||||
|
||||
$angeltype_signup_state = Shift_signup_allowed(
|
||||
|
@ -368,8 +367,8 @@ function shift_next_controller()
|
|||
|
||||
$upcoming_shifts = ShiftEntries_upcoming_for_user(auth()->user());
|
||||
|
||||
if (!empty($upcoming_shifts)) {
|
||||
throw_redirect(shift_link($upcoming_shifts[0]));
|
||||
if (!$upcoming_shifts->isEmpty()) {
|
||||
throw_redirect(shift_link($upcoming_shifts[0]->shift));
|
||||
}
|
||||
|
||||
throw_redirect(page_link_to('user_shifts'));
|
||||
|
@ -413,7 +412,7 @@ function shifts_json_export_controller()
|
|||
'description' => $shift->description,
|
||||
|
||||
// Users comment
|
||||
'Comment' => $shift->Comment,
|
||||
'Comment' => $shift->user_comment,
|
||||
|
||||
// Shift id
|
||||
'SID' => $shift->id,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
<?php
|
||||
|
||||
use Engelsystem\Database\Db;
|
||||
use Engelsystem\Models\Shifts\ShiftEntry;
|
||||
use Engelsystem\Models\User\State;
|
||||
use Engelsystem\Models\User\User;
|
||||
use Engelsystem\ShiftCalendarRenderer;
|
||||
|
@ -209,9 +210,9 @@ function user_controller()
|
|||
$shift->needed_angeltypes = Db::select(
|
||||
'
|
||||
SELECT DISTINCT `angel_types`.*
|
||||
FROM `ShiftEntry`
|
||||
JOIN `angel_types` ON `ShiftEntry`.`TID`=`angel_types`.`id`
|
||||
WHERE `ShiftEntry`.`SID` = ?
|
||||
FROM `shift_entries`
|
||||
JOIN `angel_types` ON `shift_entries`.`angel_type_id`=`angel_types`.`id`
|
||||
WHERE `shift_entries`.`shift_id` = ?
|
||||
ORDER BY `angel_types`.`name`
|
||||
',
|
||||
[$shift->id]
|
||||
|
@ -220,11 +221,11 @@ function user_controller()
|
|||
foreach ($neededAngeltypes as &$needed_angeltype) {
|
||||
$needed_angeltype['users'] = Db::select(
|
||||
'
|
||||
SELECT `ShiftEntry`.`freeloaded`, `users`.*
|
||||
FROM `ShiftEntry`
|
||||
JOIN `users` ON `ShiftEntry`.`UID`=`users`.`id`
|
||||
WHERE `ShiftEntry`.`SID` = ?
|
||||
AND `ShiftEntry`.`TID` = ?
|
||||
SELECT `shift_entries`.`freeloaded`, `users`.*
|
||||
FROM `shift_entries`
|
||||
JOIN `users` ON `shift_entries`.`user_id`=`users`.`id`
|
||||
WHERE `shift_entries`.`shift_id` = ?
|
||||
AND `shift_entries`.`angel_type_id` = ?
|
||||
',
|
||||
[$shift->id, $needed_angeltype['id']]
|
||||
);
|
||||
|
@ -247,7 +248,7 @@ function user_controller()
|
|||
User_view(
|
||||
$user_source,
|
||||
auth()->can('admin_user'),
|
||||
User_is_freeloader($user_source),
|
||||
$user_source->isFreeloader(),
|
||||
$user_source->userAngelTypes,
|
||||
$user_source->groups,
|
||||
$shifts,
|
||||
|
@ -300,7 +301,12 @@ function users_list_controller()
|
|||
->orderBy('name')
|
||||
->get();
|
||||
foreach ($users as $user) {
|
||||
$user->setAttribute('freeloads', count(ShiftEntries_freeloaded_by_user($user->id)));
|
||||
$user->setAttribute(
|
||||
'freeloads',
|
||||
$user->shiftEntries()
|
||||
->where('freeloaded', true)
|
||||
->count()
|
||||
);
|
||||
}
|
||||
|
||||
$users = $users->sortBy(function (User $user) use ($order_by) {
|
||||
|
@ -321,7 +327,7 @@ function users_list_controller()
|
|||
State::whereArrived(true)->count(),
|
||||
State::whereActive(true)->count(),
|
||||
State::whereForceActive(true)->count(),
|
||||
ShiftEntries_freeloaded_count(),
|
||||
ShiftEntry::whereFreeloaded(true)->count(),
|
||||
State::whereGotShirt(true)->count(),
|
||||
State::query()->sum('got_voucher')
|
||||
)
|
||||
|
@ -360,6 +366,7 @@ function shiftCalendarRendererByShiftFilter(ShiftsFilter $shiftsFilter)
|
|||
$shift_entries_source = ShiftEntries_by_ShiftsFilter($shiftsFilter);
|
||||
|
||||
$needed_angeltypes = [];
|
||||
/** @var ShiftEntry[][] $shift_entries */
|
||||
$shift_entries = [];
|
||||
foreach ($shifts as $shift) {
|
||||
$needed_angeltypes[$shift->id] = [];
|
||||
|
@ -367,8 +374,8 @@ function shiftCalendarRendererByShiftFilter(ShiftsFilter $shiftsFilter)
|
|||
}
|
||||
|
||||
foreach ($shift_entries_source as $shift_entry) {
|
||||
if (isset($shift_entries[$shift_entry['SID']])) {
|
||||
$shift_entries[$shift_entry['SID']][] = $shift_entry;
|
||||
if (isset($shift_entries[$shift_entry->shift_id])) {
|
||||
$shift_entries[$shift_entry->shift_id][] = $shift_entry;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -403,8 +410,8 @@ function shiftCalendarRendererByShiftFilter(ShiftsFilter $shiftsFilter)
|
|||
|
||||
foreach ($shift_entries[$shift->id] as $shift_entry) {
|
||||
if (
|
||||
$needed_angeltype['angel_type_id'] == $shift_entry['TID']
|
||||
&& $shift_entry['freeloaded'] == 0
|
||||
$needed_angeltype['angel_type_id'] == $shift_entry->angel_type_id
|
||||
&& !$shift_entry->freeloaded
|
||||
) {
|
||||
$taken++;
|
||||
}
|
||||
|
|
|
@ -1,11 +1,16 @@
|
|||
<?php
|
||||
|
||||
use Engelsystem\Models\Shifts\Shift;
|
||||
use Engelsystem\Models\Shifts\ShiftEntry;
|
||||
use Engelsystem\Models\User\User;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
|
||||
function mail_shift_change(Shift $old_shift, Shift $new_shift)
|
||||
{
|
||||
$users = ShiftEntries_by_shift($old_shift->id);
|
||||
/** @var ShiftEntry[]|Collection $shiftEntries */
|
||||
$shiftEntries = $old_shift->shiftEntries()
|
||||
->with(['user', 'user.settings'])
|
||||
->get();
|
||||
$old_room = $old_shift->room;
|
||||
$new_room = $new_shift->room;
|
||||
|
||||
|
@ -65,8 +70,8 @@ function mail_shift_change(Shift $old_shift, Shift $new_shift)
|
|||
$message .= $new_room->name . "\n\n";
|
||||
$message .= url('/shifts', ['action' => 'view', 'shift_id' => $new_shift->id]) . "\n";
|
||||
|
||||
foreach ($users as $user) {
|
||||
$user = (new User())->forceFill($user);
|
||||
foreach ($shiftEntries as $shiftEntry) {
|
||||
$user = $shiftEntry->user;
|
||||
if ($user->settings->email_shiftinfo) {
|
||||
engelsystem_email_to_user(
|
||||
$user,
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
<?php
|
||||
|
||||
use Engelsystem\Database\Db;
|
||||
use Engelsystem\Models\Shifts\ShiftEntry;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
|
||||
/**
|
||||
* Entity needed angeltypes describes how many angels of given type are needed for a shift or in a room.
|
||||
|
@ -108,13 +110,16 @@ function NeededAngelTypes_by_shift($shiftId)
|
|||
', [$shiftId]);
|
||||
}
|
||||
|
||||
$shift_entries = ShiftEntries_by_shift($shiftId);
|
||||
/** @var ShiftEntry[]|Collection $shift_entries */
|
||||
$shift_entries = ShiftEntry::with('user', 'angelType')
|
||||
->where('shift_id', $shiftId)
|
||||
->get();
|
||||
$needed_angeltypes = [];
|
||||
foreach ($needed_angeltypes_source as $angeltype) {
|
||||
$angeltype['shift_entries'] = [];
|
||||
$angeltype['taken'] = 0;
|
||||
foreach ($shift_entries as $shift_entry) {
|
||||
if ($shift_entry['TID'] == $angeltype['angel_type_id'] && $shift_entry['freeloaded'] == 0) {
|
||||
if ($shift_entry->angel_type_id == $angeltype['angel_type_id'] && !$shift_entry->freeloaded) {
|
||||
$angeltype['taken']++;
|
||||
$angeltype['shift_entries'][] = $shift_entry;
|
||||
}
|
||||
|
|
|
@ -1,153 +1,40 @@
|
|||
<?php
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Engelsystem\Database\Db;
|
||||
use Engelsystem\Models\AngelType;
|
||||
use Engelsystem\Models\Shifts\ShiftEntry;
|
||||
use Engelsystem\Models\User\User;
|
||||
|
||||
/**
|
||||
* Counts all freeloaded shifts.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
function ShiftEntries_freeloaded_count()
|
||||
{
|
||||
$result = Db::selectOne('SELECT COUNT(*) FROM `ShiftEntry` WHERE `freeloaded` = 1');
|
||||
|
||||
if (empty($result)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (int) array_shift($result);
|
||||
}
|
||||
|
||||
/**
|
||||
* List users subscribed to a given shift.
|
||||
*
|
||||
* @param int $shift_id
|
||||
* @return array
|
||||
*/
|
||||
function ShiftEntries_by_shift($shift_id)
|
||||
{
|
||||
return Db::select(
|
||||
'
|
||||
SELECT
|
||||
`users`.*,
|
||||
`ShiftEntry`.`UID`,
|
||||
`ShiftEntry`.`TID`,
|
||||
`ShiftEntry`.`SID`,
|
||||
`angel_types`.`name` AS `angel_type_name`,
|
||||
`ShiftEntry`.`Comment`,
|
||||
`ShiftEntry`.`freeloaded`
|
||||
FROM `ShiftEntry`
|
||||
JOIN `users` ON `ShiftEntry`.`UID`=`users`.`id`
|
||||
JOIN `angel_types` ON `ShiftEntry`.`TID`=`angel_types`.`id`
|
||||
WHERE `ShiftEntry`.`SID` = ?
|
||||
',
|
||||
[$shift_id]
|
||||
);
|
||||
}
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
|
||||
/**
|
||||
* Create a new shift entry.
|
||||
*
|
||||
* @param array $shift_entry
|
||||
* @return bool
|
||||
*/
|
||||
function ShiftEntry_create($shift_entry)
|
||||
function ShiftEntry_onCreate(ShiftEntry $shiftEntry): void
|
||||
{
|
||||
$user = User::find($shift_entry['UID']);
|
||||
$shift = Shift($shift_entry['SID']);
|
||||
$shifttype = $shift->shiftType;
|
||||
$room = $shift->room;
|
||||
$angeltype = AngelType::find($shift_entry['TID']);
|
||||
$result = Db::insert(
|
||||
'
|
||||
INSERT INTO `ShiftEntry` (
|
||||
`SID`,
|
||||
`TID`,
|
||||
`UID`,
|
||||
`Comment`,
|
||||
`freeload_comment`,
|
||||
`freeloaded`
|
||||
)
|
||||
VALUES(?, ?, ?, ?, ?, ?)
|
||||
',
|
||||
[
|
||||
$shift_entry['SID'],
|
||||
$shift_entry['TID'],
|
||||
$shift_entry['UID'],
|
||||
$shift_entry['Comment'],
|
||||
$shift_entry['freeload_comment'],
|
||||
(int) $shift_entry['freeloaded'],
|
||||
]
|
||||
);
|
||||
$shift = $shiftEntry->shift;
|
||||
engelsystem_log(
|
||||
'User ' . User_Nick_render($user, true)
|
||||
. ' signed up for shift ' . $shift->title
|
||||
. ' (' . $shifttype->name . ')'
|
||||
. ' at ' . $room->name
|
||||
'User ' . User_Nick_render($shiftEntry->user, true)
|
||||
. ' signed up for shift ' . $shiftEntry->shift->title
|
||||
. ' (' . $shift->shiftType->name . ')'
|
||||
. ' at ' . $shift->room->name
|
||||
. ' from ' . $shift->start->format('Y-m-d H:i')
|
||||
. ' to ' . $shift->end->format('Y-m-d H:i')
|
||||
. ' as ' . $angeltype->name
|
||||
. ' as ' . $shiftEntry->angelType->name
|
||||
);
|
||||
mail_shift_assign($user, $shift);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a shift entry.
|
||||
*
|
||||
* @param array $shift_entry
|
||||
*/
|
||||
function ShiftEntry_update($shift_entry)
|
||||
{
|
||||
Db::update(
|
||||
'
|
||||
UPDATE `ShiftEntry`
|
||||
SET
|
||||
`Comment` = ?,
|
||||
`freeload_comment` = ?,
|
||||
`freeloaded` = ?
|
||||
WHERE `id` = ?
|
||||
',
|
||||
[
|
||||
$shift_entry['Comment'],
|
||||
$shift_entry['freeload_comment'],
|
||||
(int) $shift_entry['freeloaded'],
|
||||
$shift_entry['id']
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a shift entry.
|
||||
*
|
||||
* @param int $shift_entry_id
|
||||
* @return array|null
|
||||
*/
|
||||
function ShiftEntry($shift_entry_id)
|
||||
{
|
||||
$shiftEntry = Db::selectOne('SELECT * FROM `ShiftEntry` WHERE `id` = ?', [$shift_entry_id]);
|
||||
|
||||
return empty($shiftEntry) ? null : $shiftEntry;
|
||||
mail_shift_assign($shiftEntry->user, $shift);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a shift entry.
|
||||
*
|
||||
* @param array $shiftEntry
|
||||
* @param ShiftEntry $shiftEntry
|
||||
*/
|
||||
function ShiftEntry_delete($shiftEntry)
|
||||
function ShiftEntry_onDelete(ShiftEntry $shiftEntry)
|
||||
{
|
||||
Db::delete('DELETE FROM `ShiftEntry` WHERE `id` = ?', [$shiftEntry['id']]);
|
||||
|
||||
$signout_user = User::find($shiftEntry['UID']);
|
||||
$shift = Shift($shiftEntry['SID']);
|
||||
$signout_user = $shiftEntry->user;
|
||||
$shift = Shift($shiftEntry->shift);
|
||||
$shifttype = $shift->shiftType;
|
||||
$room = $shift->room;
|
||||
$angeltype = AngelType::find($shiftEntry['TID']);
|
||||
$angeltype = $shiftEntry->angelType;
|
||||
|
||||
engelsystem_log(
|
||||
'Shift signout: ' . User_Nick_render($signout_user, true)
|
||||
|
@ -159,31 +46,23 @@ function ShiftEntry_delete($shiftEntry)
|
|||
. ' as ' . $angeltype->name
|
||||
);
|
||||
|
||||
mail_shift_removed(User::find($shiftEntry['UID']), $shift);
|
||||
mail_shift_removed($signout_user, $shift);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns next (or current) shifts of given user.
|
||||
*
|
||||
* @param User $user
|
||||
* @return array
|
||||
* @return ShiftEntry[]|Collection
|
||||
*/
|
||||
function ShiftEntries_upcoming_for_user(User $user)
|
||||
{
|
||||
return Db::select(
|
||||
'
|
||||
SELECT *, shifts.id as shift_id
|
||||
FROM `ShiftEntry`
|
||||
JOIN `shifts` ON (`shifts`.`id` = `ShiftEntry`.`SID`)
|
||||
JOIN `shift_types` ON `shift_types`.`id` = `shifts`.`shift_type_id`
|
||||
WHERE `ShiftEntry`.`UID` = ?
|
||||
AND `shifts`.`end` > NOW()
|
||||
ORDER BY `shifts`.`end`
|
||||
',
|
||||
[
|
||||
$user->id
|
||||
]
|
||||
);
|
||||
return $user->shiftEntries()
|
||||
->with(['shift', 'shift.shiftType'])
|
||||
->join('shifts', 'shift_entries.shift_id', 'shifts.id')
|
||||
->where('shifts.end', '>', Carbon::now())
|
||||
->orderBy('shifts.end')
|
||||
->get();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -191,68 +70,20 @@ function ShiftEntries_upcoming_for_user(User $user)
|
|||
*
|
||||
* @param User $user
|
||||
* @param Carbon|null $sinceTime
|
||||
* @return array
|
||||
* @return ShiftEntry[]|Collection
|
||||
*/
|
||||
function ShiftEntries_finished_by_user(User $user, Carbon $sinceTime = null)
|
||||
{
|
||||
return Db::select(
|
||||
'
|
||||
SELECT *
|
||||
FROM `ShiftEntry`
|
||||
JOIN `shifts` ON (`shifts`.`id` = `ShiftEntry`.`SID`)
|
||||
JOIN `shift_types` ON `shift_types`.`id` = `shifts`.`shift_type_id`
|
||||
WHERE `ShiftEntry`.`UID` = ?
|
||||
AND `shifts`.`end` < NOW()
|
||||
AND `ShiftEntry`.`freeloaded` = 0
|
||||
' . ($sinceTime ? 'AND shifts.start >= "' . $sinceTime->toString() . '"' : '') . '
|
||||
ORDER BY `shifts`.`end` desc
|
||||
',
|
||||
[
|
||||
$user->id,
|
||||
]
|
||||
);
|
||||
}
|
||||
$query = $user->shiftEntries()
|
||||
->with(['shift', 'shift.shiftType'])
|
||||
->join('shifts', 'shift_entries.shift_id', 'shifts.id')
|
||||
->where('shifts.end', '<', Carbon::now())
|
||||
->where('freeloaded', false)
|
||||
->orderByDesc('shifts.end');
|
||||
|
||||
/**
|
||||
* Returns all shift entries in given shift for given angeltype.
|
||||
*
|
||||
* @param int $shift_id
|
||||
* @param int $angeltype_id
|
||||
* @return array
|
||||
*/
|
||||
function ShiftEntries_by_shift_and_angeltype($shift_id, $angeltype_id)
|
||||
{
|
||||
return Db::select(
|
||||
'
|
||||
SELECT *
|
||||
FROM `ShiftEntry`
|
||||
WHERE `SID` = ?
|
||||
AND `TID` = ?
|
||||
',
|
||||
[
|
||||
$shift_id,
|
||||
$angeltype_id,
|
||||
]
|
||||
);
|
||||
}
|
||||
if ($sinceTime) {
|
||||
$query = $query->where('shifts.start', '>=', $sinceTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all freeloaded shifts for given user.
|
||||
*
|
||||
* @param int $userId
|
||||
* @return array
|
||||
*/
|
||||
function ShiftEntries_freeloaded_by_user($userId)
|
||||
{
|
||||
return Db::select(
|
||||
'
|
||||
SELECT *
|
||||
FROM `ShiftEntry`
|
||||
WHERE `freeloaded` = 1
|
||||
AND `UID` = ?
|
||||
',
|
||||
[
|
||||
$userId
|
||||
]
|
||||
);
|
||||
return $query->get();
|
||||
}
|
||||
|
|
|
@ -4,11 +4,13 @@ use Engelsystem\Database\Db;
|
|||
use Engelsystem\Helpers\Carbon;
|
||||
use Engelsystem\Models\AngelType;
|
||||
use Engelsystem\Models\Shifts\Shift;
|
||||
use Engelsystem\Models\Shifts\ShiftEntry;
|
||||
use Engelsystem\Models\User\User;
|
||||
use Engelsystem\Models\UserAngelType;
|
||||
use Engelsystem\ShiftsFilter;
|
||||
use Engelsystem\ShiftSignupState;
|
||||
use Illuminate\Support\Collection;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Illuminate\Support\Collection as SupportCollection;
|
||||
|
||||
/**
|
||||
* @param AngelType $angeltype
|
||||
|
@ -57,7 +59,7 @@ function Shifts_free($start, $end, ShiftsFilter $filter = null)
|
|||
LEFT JOIN schedule_shift AS s on shifts.id = s.shift_id
|
||||
WHERE (`end` > ? AND `start` < ?)
|
||||
AND (SELECT SUM(`count`) FROM `NeededAngelTypes` WHERE `NeededAngelTypes`.`shift_id`=`shifts`.`id`' . ($filter ? ' AND NeededAngelTypes.angel_type_id IN (' . implode(',', $filter->getTypes()) . ')' : '') . ')
|
||||
> (SELECT COUNT(*) FROM `ShiftEntry` WHERE `ShiftEntry`.`SID`=`shifts`.`id` AND `freeloaded`=0' . ($filter ? ' AND ShiftEntry.TID IN (' . implode(',', $filter->getTypes()) . ')' : '') . ')
|
||||
> (SELECT COUNT(*) FROM `shift_entries` WHERE `shift_entries`.`shift_id`=`shifts`.`id` AND shift_entries.`freeloaded`=0' . ($filter ? ' AND shift_entries.angel_type_id IN (' . implode(',', $filter->getTypes()) . ')' : '') . ')
|
||||
AND s.shift_id IS NULL
|
||||
' . ($filter ? 'AND shifts.room_id IN (' . implode(',', $filter->getRooms()) . ')' : '') . '
|
||||
|
||||
|
@ -68,7 +70,7 @@ function Shifts_free($start, $end, ShiftsFilter $filter = null)
|
|||
LEFT JOIN schedule_shift AS s on shifts.id = s.shift_id
|
||||
WHERE (`end` > ? AND `start` < ?)
|
||||
AND (SELECT SUM(`count`) FROM `NeededAngelTypes` WHERE `NeededAngelTypes`.`room_id`=`shifts`.`room_id`' . ($filter ? ' AND NeededAngelTypes.angel_type_id IN (' . implode(',', $filter->getTypes()) . ')' : '') . ')
|
||||
> (SELECT COUNT(*) FROM `ShiftEntry` WHERE `ShiftEntry`.`SID`=`shifts`.`id` AND `freeloaded`=0' . ($filter ? ' AND ShiftEntry.TID IN (' . implode(',', $filter->getTypes()) . ')' : '') . ')
|
||||
> (SELECT COUNT(*) FROM `shift_entries` WHERE `shift_entries`.`shift_id`=`shifts`.`id` AND `freeloaded`=0' . ($filter ? ' AND shift_entries.angel_type_id IN (' . implode(',', $filter->getTypes()) . ')' : '') . ')
|
||||
AND NOT s.shift_id IS NULL
|
||||
' . ($filter ? 'AND shifts.room_id IN (' . implode(',', $filter->getRooms()) . ')' : '') . '
|
||||
) AS `tmp`
|
||||
|
@ -246,35 +248,15 @@ function NeededAngeltype_by_Shift_and_Angeltype(Shift $shift, AngelType $angelty
|
|||
|
||||
/**
|
||||
* @param ShiftsFilter $shiftsFilter
|
||||
* @return array[]
|
||||
* @return ShiftEntry[]|Collection
|
||||
*/
|
||||
function ShiftEntries_by_ShiftsFilter(ShiftsFilter $shiftsFilter)
|
||||
{
|
||||
$sql = sprintf(
|
||||
'
|
||||
SELECT
|
||||
users.*,
|
||||
`ShiftEntry`.`UID`,
|
||||
`ShiftEntry`.`TID`,
|
||||
`ShiftEntry`.`SID`,
|
||||
`ShiftEntry`.`Comment`,
|
||||
`ShiftEntry`.`freeloaded`
|
||||
FROM `shifts`
|
||||
JOIN `ShiftEntry` ON `ShiftEntry`.`SID`=`shifts`.`id`
|
||||
JOIN `users` ON `ShiftEntry`.`UID`=`users`.`id`
|
||||
WHERE `shifts`.`room_id` IN (%s)
|
||||
AND `start` BETWEEN ? AND ?
|
||||
ORDER BY `shifts`.`start`
|
||||
',
|
||||
implode(',', $shiftsFilter->getRooms())
|
||||
);
|
||||
return Db::select(
|
||||
$sql,
|
||||
[
|
||||
$shiftsFilter->getStart(),
|
||||
$shiftsFilter->getEnd(),
|
||||
]
|
||||
);
|
||||
return ShiftEntry::with('user')
|
||||
->join('shifts', 'shifts.id', 'shift_entries.shift_id')
|
||||
->whereIn('shifts.room_id', $shiftsFilter->getRooms())
|
||||
->whereBetween('start', [$shiftsFilter->getStart(), $shiftsFilter->getEnd()])
|
||||
->get();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -305,14 +287,14 @@ function Shift_collides(Shift $shift, $shifts)
|
|||
* Returns the number of needed angels/free shift entries for an angeltype.
|
||||
*
|
||||
* @param AngelType $needed_angeltype
|
||||
* @param array[] $shift_entries
|
||||
* @param ShiftEntry[]|Collection $shift_entries
|
||||
* @return int
|
||||
*/
|
||||
function Shift_free_entries(AngelType $needed_angeltype, $shift_entries)
|
||||
{
|
||||
$taken = 0;
|
||||
foreach ($shift_entries as $shift_entry) {
|
||||
if ($shift_entry['freeloaded'] == 0) {
|
||||
if (!$shift_entry->freeloaded) {
|
||||
$taken++;
|
||||
}
|
||||
}
|
||||
|
@ -330,7 +312,7 @@ function Shift_free_entries(AngelType $needed_angeltype, $shift_entries)
|
|||
* @param array|null $user_angeltype
|
||||
* @param SHift[]|Collection|null $user_shifts List of the users shifts
|
||||
* @param AngelType $needed_angeltype
|
||||
* @param array[] $shift_entries
|
||||
* @param ShiftEntry[]|Collection $shift_entries
|
||||
* @return ShiftSignupState
|
||||
*/
|
||||
function Shift_signup_allowed_angel(
|
||||
|
@ -411,7 +393,7 @@ function Shift_signup_allowed_angel(
|
|||
* Check if an angeltype supporter can sign up a user to a shift.
|
||||
*
|
||||
* @param AngelType $needed_angeltype
|
||||
* @param array[] $shift_entries
|
||||
* @param ShiftEntry[]|Collection $shift_entries
|
||||
* @return ShiftSignupState
|
||||
*/
|
||||
function Shift_signup_allowed_angeltype_supporter(AngelType $needed_angeltype, $shift_entries)
|
||||
|
@ -428,7 +410,7 @@ function Shift_signup_allowed_angeltype_supporter(AngelType $needed_angeltype, $
|
|||
* Check if an admin can sign up a user to a shift.
|
||||
*
|
||||
* @param AngelType $needed_angeltype
|
||||
* @param array[] $shift_entries
|
||||
* @param ShiftEntry[]|Collection $shift_entries
|
||||
* @return ShiftSignupState
|
||||
*/
|
||||
function Shift_signup_allowed_admin(AngelType $needed_angeltype, $shift_entries)
|
||||
|
@ -484,7 +466,7 @@ function Shift_signout_allowed(Shift $shift, AngelType $angeltype, $signout_user
|
|||
* @param array|null $user_angeltype
|
||||
* @param Shift[]|Collection|null $user_shifts List of the users shifts
|
||||
* @param AngelType $needed_angeltype
|
||||
* @param array[] $shift_entries
|
||||
* @param ShiftEntry[]|Collection $shift_entries
|
||||
* @return ShiftSignupState
|
||||
*/
|
||||
function Shift_signup_allowed(
|
||||
|
@ -522,10 +504,10 @@ function Shift_signup_allowed(
|
|||
* Return users shifts.
|
||||
*
|
||||
* @param int $userId
|
||||
* @param bool $include_freeload_comments
|
||||
* @return Collection|Shift[]
|
||||
* @param bool $include_freeloaded_comments
|
||||
* @return SupportCollection|Shift[]
|
||||
*/
|
||||
function Shifts_by_user($userId, $include_freeload_comments = false)
|
||||
function Shifts_by_user($userId, $include_freeloaded_comments = false)
|
||||
{
|
||||
$shiftsData = Db::select(
|
||||
'
|
||||
|
@ -534,19 +516,19 @@ function Shifts_by_user($userId, $include_freeload_comments = false)
|
|||
`rooms`.name AS Name,
|
||||
`shift_types`.`id` AS `shifttype_id`,
|
||||
`shift_types`.`name`,
|
||||
`ShiftEntry`.`id` as shift_entry_id,
|
||||
`ShiftEntry`.`SID`,
|
||||
`ShiftEntry`.`TID`,
|
||||
`ShiftEntry`.`UID`,
|
||||
`ShiftEntry`.`freeloaded`,
|
||||
`ShiftEntry`.`Comment`,
|
||||
' . ($include_freeload_comments ? '`ShiftEntry`.`freeload_comment`, ' : '') . '
|
||||
`shift_entries`.`id` as shift_entry_id,
|
||||
`shift_entries`.`shift_id`,
|
||||
`shift_entries`.`angel_type_id`,
|
||||
`shift_entries`.`user_id`,
|
||||
`shift_entries`.`freeloaded`,
|
||||
`shift_entries`.`user_comment`,
|
||||
' . ($include_freeloaded_comments ? '`shift_entries`.`freeloaded_comment`, ' : '') . '
|
||||
`shifts`.*
|
||||
FROM `ShiftEntry`
|
||||
JOIN `shifts` ON (`ShiftEntry`.`SID` = `shifts`.`id`)
|
||||
FROM `shift_entries`
|
||||
JOIN `shifts` ON (`shift_entries`.`shift_id` = `shifts`.`id`)
|
||||
JOIN `shift_types` ON (`shift_types`.`id` = `shifts`.`shift_type_id`)
|
||||
JOIN `rooms` ON (`shifts`.`room_id` = `rooms`.`id`)
|
||||
WHERE ShiftEntry.`UID` = ?
|
||||
WHERE shift_entries.`user_id` = ?
|
||||
ORDER BY `start`
|
||||
',
|
||||
[
|
||||
|
@ -578,19 +560,11 @@ function Shift($shift)
|
|||
return null;
|
||||
}
|
||||
|
||||
$shift->shiftEntry = Db::select('
|
||||
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]);
|
||||
|
||||
$neededAngels = [];
|
||||
$angelTypes = NeededAngelTypes_by_shift($shift->id);
|
||||
foreach ($angelTypes as $type) {
|
||||
$neededAngels[] = [
|
||||
'TID' => $type['angel_type_id'],
|
||||
'angel_type_id' => $type['angel_type_id'],
|
||||
'count' => $type['count'],
|
||||
'restricted' => $type['restricted'],
|
||||
'taken' => $type['taken']
|
||||
|
|
|
@ -16,10 +16,10 @@ function stats_currently_working(ShiftsFilter $filter = null)
|
|||
'
|
||||
SELECT SUM((
|
||||
SELECT COUNT(*)
|
||||
FROM `ShiftEntry`
|
||||
WHERE `ShiftEntry`.`SID`=`shifts`.`id`
|
||||
FROM `shift_entries`
|
||||
WHERE `shift_entries`.`shift_id`=`shifts`.`id`
|
||||
AND `freeloaded`=0
|
||||
' . ($filter ? 'AND ShiftEntry.TID IN (' . implode(',', $filter->getTypes()) . ')' : '') . '
|
||||
' . ($filter ? 'AND shift_entries.angel_type_id IN (' . implode(',', $filter->getTypes()) . ')' : '') . '
|
||||
)) AS `count`
|
||||
FROM `shifts`
|
||||
WHERE (`end` >= NOW() AND `start` <= NOW())
|
||||
|
@ -89,12 +89,12 @@ function stats_angels_needed_three_hours(ShiftsFilter $filter = null)
|
|||
AND `NeededAngelTypes`.`shift_id`=`shifts`.`id`
|
||||
' . ($filter ? 'AND NeededAngelTypes.angel_type_id IN (' . implode(',', $filter->getTypes()) . ')' : '') . '
|
||||
) - (
|
||||
SELECT COUNT(*) FROM `ShiftEntry`
|
||||
JOIN `angel_types` ON `angel_types`.`id`=`ShiftEntry`.`TID`
|
||||
SELECT COUNT(*) FROM `shift_entries`
|
||||
JOIN `angel_types` ON `angel_types`.`id`=`shift_entries`.`angel_type_id`
|
||||
WHERE `angel_types`.`show_on_dashboard`=TRUE
|
||||
AND `ShiftEntry`.`SID`=`shifts`.`id`
|
||||
AND `shift_entries`.`shift_id`=`shifts`.`id`
|
||||
AND `freeloaded`=0
|
||||
' . ($filter ? 'AND ShiftEntry.TID IN (' . implode(',', $filter->getTypes()) . ')' : '') . '
|
||||
' . ($filter ? 'AND shift_entries.angel_type_id IN (' . implode(',', $filter->getTypes()) . ')' : '') . '
|
||||
)
|
||||
)
|
||||
AS `count`
|
||||
|
@ -116,12 +116,13 @@ function stats_angels_needed_three_hours(ShiftsFilter $filter = null)
|
|||
AND `NeededAngelTypes`.`room_id`=`shifts`.`room_id`
|
||||
' . ($filter ? 'AND NeededAngelTypes.angel_type_id IN (' . implode(',', $filter->getTypes()) . ')' : '') . '
|
||||
) - (
|
||||
SELECT COUNT(*) FROM `ShiftEntry`
|
||||
JOIN `angel_types` ON `angel_types`.`id`=`ShiftEntry`.`TID`
|
||||
SELECT COUNT(*)
|
||||
FROM `shift_entries`
|
||||
JOIN `angel_types` ON `angel_types`.`id`=`shift_entries`.`angel_type_id`
|
||||
WHERE `angel_types`.`show_on_dashboard`=TRUE
|
||||
AND `ShiftEntry`.`SID`=`shifts`.`id`
|
||||
AND `shift_entries`.`shift_id`=`shifts`.`id`
|
||||
AND `freeloaded`=0
|
||||
' . ($filter ? 'AND ShiftEntry.TID IN (' . implode(',', $filter->getTypes()) . ')' : '') . '
|
||||
' . ($filter ? 'AND shift_entries.angel_type_id IN (' . implode(',', $filter->getTypes()) . ')' : '') . '
|
||||
)
|
||||
)
|
||||
AS `count`
|
||||
|
@ -168,12 +169,12 @@ function stats_angels_needed_for_nightshifts(ShiftsFilter $filter = null)
|
|||
AND `NeededAngelTypes`.`shift_id`=`shifts`.`id`
|
||||
' . ($filter ? 'AND NeededAngelTypes.angel_type_id IN (' . implode(',', $filter->getTypes()) . ')' : '') . '
|
||||
) - (
|
||||
SELECT COUNT(*) FROM `ShiftEntry`
|
||||
JOIN `angel_types` ON `angel_types`.`id`=`ShiftEntry`.`TID`
|
||||
SELECT COUNT(*) FROM `shift_entries`
|
||||
JOIN `angel_types` ON `angel_types`.`id`=`shift_entries`.`angel_type_id`
|
||||
WHERE `angel_types`.`show_on_dashboard`=TRUE
|
||||
AND `ShiftEntry`.`SID`=`shifts`.`id`
|
||||
AND `freeloaded`=0
|
||||
' . ($filter ? 'AND ShiftEntry.TID IN (' . implode(',', $filter->getTypes()) . ')' : '') . '
|
||||
AND `shift_entries`.`shift_id`=`shifts`.`id`
|
||||
AND shift_entries.`freeloaded`=0
|
||||
' . ($filter ? 'AND shift_entries.angel_type_id IN (' . implode(',', $filter->getTypes()) . ')' : '') . '
|
||||
)
|
||||
)
|
||||
AS `count`
|
||||
|
@ -195,12 +196,12 @@ function stats_angels_needed_for_nightshifts(ShiftsFilter $filter = null)
|
|||
AND `NeededAngelTypes`.`room_id`=`shifts`.`room_id`
|
||||
' . ($filter ? 'AND angel_types.id IN (' . implode(',', $filter->getTypes()) . ')' : '') . '
|
||||
) - (
|
||||
SELECT COUNT(*) FROM `ShiftEntry`
|
||||
JOIN `angel_types` ON `angel_types`.`id`=`ShiftEntry`.`TID`
|
||||
SELECT COUNT(*) FROM `shift_entries`
|
||||
JOIN `angel_types` ON `angel_types`.`id`=`shift_entries`.`angel_type_id`
|
||||
WHERE `angel_types`.`show_on_dashboard`=TRUE
|
||||
AND `ShiftEntry`.`SID`=`shifts`.`id`
|
||||
AND `shift_entries`.`shift_id`=`shifts`.`id`
|
||||
AND `freeloaded`=0
|
||||
' . ($filter ? 'AND ShiftEntry.TID IN (' . implode(',', $filter->getTypes()) . ')' : '') . '
|
||||
' . ($filter ? 'AND shift_entries.angel_type_id IN (' . implode(',', $filter->getTypes()) . ')' : '') . '
|
||||
)
|
||||
)
|
||||
AS `count`
|
||||
|
|
|
@ -25,8 +25,8 @@ function User_tshirt_score($userId)
|
|||
$shift_sum_formula = User_get_shifts_sum_query();
|
||||
$result_shifts = Db::selectOne(sprintf('
|
||||
SELECT ROUND((%s) / 3600, 2) AS `tshirt_score`
|
||||
FROM `users` LEFT JOIN `ShiftEntry` ON `users`.`id` = `ShiftEntry`.`UID`
|
||||
LEFT JOIN `shifts` ON `ShiftEntry`.`SID` = `shifts`.`id`
|
||||
FROM `users` LEFT JOIN `shift_entries` ON `users`.`id` = `shift_entries`.`user_id`
|
||||
LEFT JOIN `shifts` ON `shift_entries`.`shift_id` = `shifts`.`id`
|
||||
WHERE `users`.`id` = ?
|
||||
AND `shifts`.`end` < NOW()
|
||||
GROUP BY `users`.`id`
|
||||
|
@ -45,17 +45,6 @@ function User_tshirt_score($userId)
|
|||
return $result_shifts['tshirt_score'] + $worklogHours;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if user is freeloader
|
||||
*
|
||||
* @param User $user
|
||||
* @return bool
|
||||
*/
|
||||
function User_is_freeloader($user)
|
||||
{
|
||||
return count(ShiftEntries_freeloaded_by_user($user->id)) >= config('max_freeloadable_shifts');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns all users that are not member of given angeltype.
|
||||
*
|
||||
|
@ -196,15 +185,15 @@ function User_get_eligable_voucher_count($user)
|
|||
? Carbon::createFromFormat('Y-m-d', $voucher_settings['voucher_start'])->setTime(0, 0)
|
||||
: null;
|
||||
|
||||
$shifts = ShiftEntries_finished_by_user($user, $start);
|
||||
$shiftEntries = ShiftEntries_finished_by_user($user, $start);
|
||||
$worklog = UserWorkLogsForUser($user->id, $start);
|
||||
$shifts_done =
|
||||
count($shifts)
|
||||
count($shiftEntries)
|
||||
+ $worklog->count();
|
||||
|
||||
$shiftsTime = 0;
|
||||
foreach ($shifts as $shift) {
|
||||
$shiftsTime += (Carbon::make($shift['end'])->timestamp - Carbon::make($shift['start'])->timestamp) / 60 / 60;
|
||||
foreach ($shiftEntries as $shiftEntry) {
|
||||
$shiftsTime += ($shiftEntry->shift->end->timestamp - $shiftEntry->shift->start->timestamp) / 60 / 60;
|
||||
}
|
||||
foreach ($worklog as $entry) {
|
||||
$shiftsTime += $entry->hours;
|
||||
|
@ -248,7 +237,7 @@ function User_get_shifts_sum_query()
|
|||
OR (HOUR(shifts.start) <= %1$d AND HOUR(shifts.end) >= %2$d)
|
||||
))
|
||||
* (UNIX_TIMESTAMP(shifts.end) - UNIX_TIMESTAMP(shifts.start))
|
||||
* (1 - (%3$d + 1) * `ShiftEntry`.`freeloaded`)
|
||||
* (1 - (%3$d + 1) * `shift_entries`.`freeloaded`)
|
||||
), 0)
|
||||
',
|
||||
$nightShifts['start'],
|
||||
|
|
|
@ -60,7 +60,7 @@ function admin_active()
|
|||
sprintf(
|
||||
'
|
||||
users.*,
|
||||
COUNT(ShiftEntry.id) AS shift_count,
|
||||
COUNT(shift_entries.id) AS shift_count,
|
||||
(%s + (
|
||||
SELECT COALESCE(SUM(`hours`) * 3600, 0)
|
||||
FROM `worklogs` WHERE `user_id`=`users`.`id`
|
||||
|
@ -70,8 +70,8 @@ function admin_active()
|
|||
$shift_sum_formula
|
||||
)
|
||||
)
|
||||
->leftJoin('ShiftEntry', 'users.id', '=', 'ShiftEntry.UID')
|
||||
->leftJoin('shifts', 'ShiftEntry.SID', '=', 'shifts.id')
|
||||
->leftJoin('shift_entries', 'users.id', '=', 'shift_entries.user_id')
|
||||
->leftJoin('shifts', 'shift_entries.shift_id', '=', 'shifts.id')
|
||||
->leftJoin('users_state', 'users.id', '=', 'users_state.user_id')
|
||||
->where('users_state.arrived', '=', true)
|
||||
->groupBy('users.id')
|
||||
|
@ -152,7 +152,7 @@ function admin_active()
|
|||
sprintf(
|
||||
'
|
||||
users.*,
|
||||
COUNT(ShiftEntry.id) AS shift_count,
|
||||
COUNT(shift_entries.id) AS shift_count,
|
||||
(%s + (
|
||||
SELECT COALESCE(SUM(`hours`) * 3600, 0)
|
||||
FROM `worklogs` WHERE `user_id`=`users`.`id`
|
||||
|
@ -162,10 +162,10 @@ function admin_active()
|
|||
$shift_sum_formula
|
||||
)
|
||||
)
|
||||
->leftJoin('ShiftEntry', 'users.id', '=', 'ShiftEntry.UID')
|
||||
->leftJoin('shift_entries', 'users.id', '=', 'shift_entries.user_id')
|
||||
->leftJoin('shifts', function ($join) use ($show_all_shifts) {
|
||||
/** @var JoinClause $join */
|
||||
$join->on('ShiftEntry.SID', '=', 'shifts.id');
|
||||
$join->on('shift_entries.shift_id', '=', 'shifts.id');
|
||||
if (!$show_all_shifts) {
|
||||
$join->where(function ($query) {
|
||||
/** @var Builder $query */
|
||||
|
|
|
@ -40,11 +40,11 @@ function admin_free()
|
|||
if ($request->has('submit')) {
|
||||
$query = User::with('personalData')
|
||||
->select('users.*')
|
||||
->leftJoin('ShiftEntry', 'users.id', 'ShiftEntry.UID')
|
||||
->leftJoin('shift_entries', 'users.id', 'shift_entries.user_id')
|
||||
->leftJoin('users_state', 'users.id', 'users_state.user_id')
|
||||
->leftJoin('shifts', function ($join) {
|
||||
/** @var JoinClause $join */
|
||||
$join->on('ShiftEntry.SID', '=', 'shifts.id')
|
||||
$join->on('shift_entries.shift_id', '=', 'shifts.id')
|
||||
->where('shifts.start', '<', Carbon::now())
|
||||
->where('shifts.end', '>', Carbon::now());
|
||||
})
|
||||
|
|
|
@ -189,15 +189,14 @@ function admin_rooms()
|
|||
$shifts = $room->shifts;
|
||||
foreach ($shifts as $shift) {
|
||||
$shift = Shift($shift);
|
||||
foreach ($shift->shiftEntry as $entry) {
|
||||
$type = AngelType::find($entry['TID']);
|
||||
foreach ($shift->shiftEntries as $entry) {
|
||||
event('shift.entry.deleting', [
|
||||
'user' => User::find($entry['user_id']),
|
||||
'start' => $shift->start,
|
||||
'end' => $shift->end,
|
||||
'name' => $shift->shiftType->name,
|
||||
'title' => $shift->title,
|
||||
'type' => $type->name,
|
||||
'type' => $entry->angelType->name,
|
||||
'room' => $room,
|
||||
'freeloaded' => (bool) $entry['freeloaded'],
|
||||
]);
|
||||
|
|
|
@ -563,17 +563,16 @@ function admin_shifts_history(): string
|
|||
|
||||
foreach ($shifts as $shift) {
|
||||
$shift = Shift($shift);
|
||||
foreach ($shift->shiftEntry as $entry) {
|
||||
$type = AngelType::find($entry['TID']);
|
||||
foreach ($shift->shiftEntries as $entry) {
|
||||
event('shift.entry.deleting', [
|
||||
'user' => User::find($entry['user_id']),
|
||||
'user' => $entry->user,
|
||||
'start' => $shift->start,
|
||||
'end' => $shift->end,
|
||||
'name' => $shift->shiftType->name,
|
||||
'title' => $shift->title,
|
||||
'type' => $type->name,
|
||||
'type' => $entry->angelType->name,
|
||||
'room' => $shift->room,
|
||||
'freeloaded' => (bool) $entry['freeloaded'],
|
||||
'freeloaded' => $entry->freeloaded,
|
||||
]);
|
||||
}
|
||||
|
||||
|
|
|
@ -266,15 +266,15 @@ class ImportSchedule extends BaseController
|
|||
protected function fireDeleteShiftEntryEvents(Event $event): void
|
||||
{
|
||||
$shiftEntries = $this->db
|
||||
->table('ShiftEntry')
|
||||
->table('shift_entries')
|
||||
->select([
|
||||
'shift_types.name', 'shifts.title', 'angel_types.name AS type', 'rooms.id AS room_id',
|
||||
'shifts.start', 'shifts.end', 'ShiftEntry.UID as user_id', 'ShiftEntry.freeloaded'
|
||||
'shifts.start', 'shifts.end', 'shift_entries.user_id', 'shift_entries.freeloaded'
|
||||
])
|
||||
->join('shifts', 'shifts.id', 'ShiftEntry.SID')
|
||||
->join('shifts', 'shifts.id', 'shift_entries.shift_id')
|
||||
->join('schedule_shift', 'shifts.id', 'schedule_shift.shift_id')
|
||||
->join('rooms', 'rooms.id', 'shifts.room_id')
|
||||
->join('angel_types', 'angel_types.id', 'ShiftEntry.TID')
|
||||
->join('angel_types', 'angel_types.id', 'shift_entries.angel_type_id')
|
||||
->join('shift_types', 'shift_types.id', 'shifts.shift_type_id')
|
||||
->where('schedule_shift.guid', $event->getGuid())
|
||||
->get();
|
||||
|
|
|
@ -60,8 +60,8 @@ function make_ical_entry_from_shift(Shift $shift)
|
|||
$output .= 'UID:' . md5($shift->start->timestamp . $shift->end->timestamp . $shift->shiftType->name) . "\r\n";
|
||||
$output .= 'SUMMARY:' . str_replace("\n", "\\n", $shift->shiftType->name)
|
||||
. ' (' . str_replace("\n", "\\n", $shift->title) . ")\r\n";
|
||||
if (isset($shift->Comment)) {
|
||||
$output .= 'DESCRIPTION:' . str_replace("\n", "\\n", $shift->Comment) . "\r\n";
|
||||
if (isset($shift->user_comment)) {
|
||||
$output .= 'DESCRIPTION:' . str_replace("\n", "\\n", $shift->user_comment) . "\r\n";
|
||||
}
|
||||
$output .= 'DTSTAMP:' . $shift->start->utc()->format('Ymd\THis\Z') . "\r\n";
|
||||
$output .= 'DTSTART:' . $shift->start->utc()->format('Ymd\THis\Z') . "\r\n";
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
<?php
|
||||
|
||||
use Engelsystem\Database\Db;
|
||||
use Engelsystem\Models\Shifts\Shift;
|
||||
use Engelsystem\Models\Shifts\ShiftEntry;
|
||||
use Engelsystem\Models\User\User;
|
||||
|
||||
/**
|
||||
|
@ -49,60 +48,38 @@ function user_myshifts()
|
|||
]);
|
||||
} elseif ($request->has('edit') && preg_match('/^\d+$/', $request->input('edit'))) {
|
||||
$shift_entry_id = $request->input('edit');
|
||||
$shift = Db::selectOne(
|
||||
'
|
||||
SELECT
|
||||
`ShiftEntry`.`freeloaded`,
|
||||
`ShiftEntry`.`freeload_comment`,
|
||||
`ShiftEntry`.`Comment`,
|
||||
`ShiftEntry`.`UID`,
|
||||
`shift_types`.`name`,
|
||||
`shifts`.*,
|
||||
`angel_types`.`name` AS `angel_type`
|
||||
FROM `ShiftEntry`
|
||||
JOIN `angel_types` ON (`ShiftEntry`.`TID` = `angel_types`.`id`)
|
||||
JOIN `shifts` ON (`ShiftEntry`.`SID` = `shifts`.`id`)
|
||||
JOIN `shift_types` ON (`shift_types`.`id` = `shifts`.`shift_type_id`)
|
||||
WHERE `ShiftEntry`.`id`=?
|
||||
AND `UID`=?
|
||||
LIMIT 1
|
||||
',
|
||||
[
|
||||
$shift_entry_id,
|
||||
$shifts_user->id,
|
||||
]
|
||||
);
|
||||
if (!empty($shift)) {
|
||||
/** @var Shift $shift */
|
||||
$shift = (new Shift())->forceFill($shift);
|
||||
|
||||
$freeloaded = $shift->freeloaded;
|
||||
$freeload_comment = $shift->freeloaded_comment;
|
||||
/** @var ShiftEntry $shiftEntry */
|
||||
$shiftEntry = ShiftEntry::where('id', $shift_entry_id)
|
||||
->where('user_id', $shifts_user->id)
|
||||
->with(['shift', 'shift.shiftType', 'shift.room', 'user'])
|
||||
->first();
|
||||
if (!empty($shiftEntry)) {
|
||||
$shift = $shiftEntry->shift;
|
||||
$freeloaded = $shiftEntry->freeloaded;
|
||||
$freeloaded_comment = $shiftEntry->freeloaded_comment;
|
||||
|
||||
if ($request->hasPostData('submit')) {
|
||||
$valid = true;
|
||||
if (auth()->can('user_shifts_admin')) {
|
||||
$freeloaded = $request->has('freeloaded');
|
||||
$freeload_comment = strip_request_item_nl('freeload_comment');
|
||||
if ($freeloaded && $freeload_comment == '') {
|
||||
$freeloaded_comment = strip_request_item_nl('freeloaded_comment');
|
||||
if ($freeloaded && $freeloaded_comment == '') {
|
||||
$valid = false;
|
||||
error(__('Please enter a freeload comment!'));
|
||||
}
|
||||
}
|
||||
|
||||
$comment = $shift->Comment;
|
||||
$user_source = User::find($shift->UID);
|
||||
$comment = $shiftEntry->user_comment;
|
||||
$user_source = $shiftEntry->user;
|
||||
if (auth()->user()->id == $user_source->id) {
|
||||
$comment = strip_request_item_nl('comment');
|
||||
}
|
||||
|
||||
if ($valid) {
|
||||
ShiftEntry_update([
|
||||
'id' => $shift_entry_id,
|
||||
'Comment' => $comment,
|
||||
'freeloaded' => $freeloaded,
|
||||
'freeload_comment' => $freeload_comment
|
||||
]);
|
||||
$shiftEntry->user_comment = $comment;
|
||||
$shiftEntry->freeloaded = $freeloaded;
|
||||
$shiftEntry->freeloaded_comment = $freeloaded_comment;
|
||||
$shiftEntry->save();
|
||||
|
||||
engelsystem_log(
|
||||
'Updated ' . User_Nick_render($user_source, true) . '\'s shift '
|
||||
|
@ -110,7 +87,7 @@ function user_myshifts()
|
|||
. ' from ' . $shift->start->format('Y-m-d H:i')
|
||||
. ' to ' . $shift->end->format('Y-m-d H:i')
|
||||
. ' with comment ' . $comment
|
||||
. '. Freeloaded: ' . ($freeloaded ? 'YES Comment: ' . $freeload_comment : 'NO')
|
||||
. '. Freeloaded: ' . ($freeloaded ? 'YES Comment: ' . $freeloaded_comment : 'NO')
|
||||
);
|
||||
success(__('Shift saved.'));
|
||||
throw_redirect(page_link_to('users', ['action' => 'view', 'user_id' => $shifts_user->id]));
|
||||
|
@ -122,10 +99,10 @@ function user_myshifts()
|
|||
$shift->start->format('Y-m-d H:i') . ', ' . shift_length($shift),
|
||||
$shift->room->name,
|
||||
$shift->shiftType->name,
|
||||
$shift->angel_type,
|
||||
$shift->Comment,
|
||||
$shift->freeloaded,
|
||||
$shift->freeload_comment,
|
||||
$shiftEntry->angelType->name,
|
||||
$shiftEntry->user_comment,
|
||||
$shiftEntry->freeloaded,
|
||||
$shiftEntry->freeloaded_comment,
|
||||
auth()->can('user_shifts_admin')
|
||||
);
|
||||
} else {
|
||||
|
|
|
@ -31,7 +31,7 @@ function user_shifts()
|
|||
{
|
||||
$request = request();
|
||||
|
||||
if (User_is_freeloader(auth()->user())) {
|
||||
if (auth()->user()->isFreeloader()) {
|
||||
throw_redirect(page_link_to('user_myshifts'));
|
||||
}
|
||||
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
namespace Engelsystem;
|
||||
|
||||
use Engelsystem\Models\Shifts\Shift;
|
||||
use Engelsystem\Models\Shifts\ShiftEntry;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
class ShiftCalendarRenderer
|
||||
{
|
||||
|
@ -47,7 +49,7 @@ class ShiftCalendarRenderer
|
|||
*
|
||||
* @param Shift[] $shifts
|
||||
* @param array[] $needed_angeltypes
|
||||
* @param array[] $shift_entries
|
||||
* @param ShiftEntry[][]|Collection $shift_entries
|
||||
* @param ShiftsFilter $shiftsFilter
|
||||
*/
|
||||
public function __construct($shifts, private $needed_angeltypes, private $shift_entries, ShiftsFilter $shiftsFilter)
|
||||
|
|
|
@ -4,7 +4,9 @@ namespace Engelsystem;
|
|||
|
||||
use Engelsystem\Models\AngelType;
|
||||
use Engelsystem\Models\Shifts\Shift;
|
||||
use Engelsystem\Models\Shifts\ShiftEntry;
|
||||
use Engelsystem\Models\User\User;
|
||||
use Illuminate\Support\Collection;
|
||||
|
||||
use function theme_type;
|
||||
|
||||
|
@ -18,7 +20,7 @@ class ShiftCalendarShiftRenderer
|
|||
*
|
||||
* @param Shift $shift The shift to render
|
||||
* @param array[] $needed_angeltypes
|
||||
* @param array $shift_entries
|
||||
* @param ShiftEntry[]|Collection $shift_entries
|
||||
* @param User $user The user who is viewing the shift calendar
|
||||
* @return array
|
||||
*/
|
||||
|
@ -82,7 +84,7 @@ class ShiftCalendarShiftRenderer
|
|||
/**
|
||||
* @param Shift $shift
|
||||
* @param array[] $needed_angeltypes
|
||||
* @param array[] $shift_entries
|
||||
* @param ShiftEntry[]|Collection $shift_entries
|
||||
* @param User $user
|
||||
* @return array
|
||||
*/
|
||||
|
@ -93,7 +95,7 @@ class ShiftCalendarShiftRenderer
|
|||
$shift_entries_filtered[$needed_angeltype['id']] = [];
|
||||
}
|
||||
foreach ($shift_entries as $shift_entry) {
|
||||
$shift_entries_filtered[$shift_entry['TID']][] = $shift_entry;
|
||||
$shift_entries_filtered[$shift_entry->angel_type_id][] = $shift_entry;
|
||||
}
|
||||
|
||||
$html = '';
|
||||
|
@ -145,7 +147,7 @@ class ShiftCalendarShiftRenderer
|
|||
* Renders a list entry containing the needed angels for an angeltype
|
||||
*
|
||||
* @param Shift $shift The shift which is rendered
|
||||
* @param array[] $shift_entries
|
||||
* @param ShiftEntry[]|Collection $shift_entries
|
||||
* @param array $angeltype The angeltype, containing information about needed angeltypes
|
||||
* and already signed up angels
|
||||
* @param User $user The user who is viewing the shift calendar
|
||||
|
@ -156,8 +158,8 @@ class ShiftCalendarShiftRenderer
|
|||
$angeltype = (new AngelType())->forceFill($angeltype);
|
||||
$entry_list = [];
|
||||
foreach ($shift_entries as $entry) {
|
||||
$class = $entry['freeloaded'] ? 'text-decoration-line-through' : '';
|
||||
$entry_list[] = '<span class="text-nowrap ' . $class . '">' . User_Nick_render($entry) . '</span>';
|
||||
$class = $entry->freeloaded ? 'text-decoration-line-through' : '';
|
||||
$entry_list[] = '<span class="text-nowrap ' . $class . '">' . User_Nick_render($entry->user) . '</span>';
|
||||
}
|
||||
$shift_signup_state = Shift_signup_allowed(
|
||||
$user,
|
||||
|
|
|
@ -39,11 +39,11 @@ function ShiftEntry_delete_view_admin(Shift $shift, AngelType $angeltype, User $
|
|||
*
|
||||
* @param Shift $shift
|
||||
* @param AngelType $angeltype
|
||||
* @param int $signoff_user_id
|
||||
* @param User $signoff_user
|
||||
*
|
||||
* @return string HTML
|
||||
*/
|
||||
function ShiftEntry_delete_view(Shift $shift, AngelType $angeltype, $signoff_user_id)
|
||||
function ShiftEntry_delete_view(Shift $shift, AngelType $angeltype, User $signoff_user)
|
||||
{
|
||||
return page_with_title(ShiftEntry_delete_title(), [
|
||||
info(sprintf(
|
||||
|
@ -56,7 +56,7 @@ function ShiftEntry_delete_view(Shift $shift, AngelType $angeltype, $signoff_use
|
|||
|
||||
form([
|
||||
buttons([
|
||||
button(user_link($signoff_user_id), icon('x-lg') . __('cancel')),
|
||||
button(user_link($signoff_user->id), icon('x-lg') . __('cancel')),
|
||||
form_submit('delete', icon('trash') . __('delete'), 'btn-danger', false),
|
||||
]),
|
||||
]),
|
||||
|
@ -180,7 +180,7 @@ function ShiftEntry_create_title()
|
|||
* @param string $type
|
||||
* @param string $comment
|
||||
* @param bool $freeloaded
|
||||
* @param string $freeload_comment
|
||||
* @param string $freeloaded_comment
|
||||
* @param bool $user_admin_shifts
|
||||
* @return string
|
||||
*/
|
||||
|
@ -192,7 +192,7 @@ function ShiftEntry_edit_view(
|
|||
$type,
|
||||
$comment,
|
||||
$freeloaded,
|
||||
$freeload_comment,
|
||||
$freeloaded_comment,
|
||||
$user_admin_shifts = false
|
||||
) {
|
||||
$freeload_form = [];
|
||||
|
@ -200,9 +200,9 @@ function ShiftEntry_edit_view(
|
|||
$freeload_form = [
|
||||
form_checkbox('freeloaded', __('Freeloaded'), $freeloaded),
|
||||
form_textarea(
|
||||
'freeload_comment',
|
||||
'freeloaded_comment',
|
||||
__('Freeload comment (Only for shift coordination):'),
|
||||
$freeload_comment
|
||||
$freeloaded_comment
|
||||
)
|
||||
];
|
||||
}
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
use Engelsystem\Models\AngelType;
|
||||
use Engelsystem\Models\Room;
|
||||
use Engelsystem\Models\Shifts\Shift;
|
||||
use Engelsystem\Models\Shifts\ShiftEntry;
|
||||
use Engelsystem\Models\Shifts\ShiftType;
|
||||
use Engelsystem\Models\User\User;
|
||||
use Engelsystem\Models\UserAngelType;
|
||||
use Engelsystem\ShiftSignupState;
|
||||
use Illuminate\Support\Collection;
|
||||
|
@ -136,13 +136,13 @@ function Shift_view(Shift $shift, ShiftType $shifttype, Room $room, $angeltypes_
|
|||
$needed_angels .= Shift_view_render_needed_angeltype($needed_angeltype, $angeltypes, $shift, $user_shift_admin);
|
||||
}
|
||||
|
||||
$shiftEntry = new Collection($shift->shiftEntry);
|
||||
foreach ($shiftEntry->groupBy('TID') as $angelTypes) {
|
||||
$shiftEntry = $shift->shiftEntries;
|
||||
foreach ($shiftEntry->groupBy('angel_type_id') as $angelTypes) {
|
||||
/** @var Collection $angelTypes */
|
||||
$type = $angelTypes->first()['TID'];
|
||||
if (!$neededAngels->where('TID', $type)->first()) {
|
||||
$type = $angelTypes->first()['angel_type_id'];
|
||||
if (!$neededAngels->where('angel_type_id', $type)->first()) {
|
||||
$needed_angels .= Shift_view_render_needed_angeltype([
|
||||
'TID' => $type,
|
||||
'angel_type_id' => $type,
|
||||
'count' => 0,
|
||||
'restricted' => true,
|
||||
'taken' => $angelTypes->count(),
|
||||
|
@ -213,7 +213,7 @@ function Shift_view(Shift $shift, ShiftType $shifttype, Room $room, $angeltypes_
|
|||
*/
|
||||
function Shift_view_render_needed_angeltype($needed_angeltype, $angeltypes, Shift $shift, $user_shift_admin)
|
||||
{
|
||||
$angeltype = $angeltypes[$needed_angeltype['TID']];
|
||||
$angeltype = $angeltypes[$needed_angeltype['angel_type_id']];
|
||||
$angeltype_supporter = auth()->user()->isAngelTypeSupporter($angeltype)
|
||||
|| auth()->can('admin_user_angeltypes');
|
||||
|
||||
|
@ -242,8 +242,8 @@ function Shift_view_render_needed_angeltype($needed_angeltype, $angeltypes, Shif
|
|||
);
|
||||
|
||||
$angels = [];
|
||||
foreach ($shift->shiftEntry as $shift_entry) {
|
||||
if ($shift_entry['TID'] == $needed_angeltype['TID']) {
|
||||
foreach ($shift->shiftEntries as $shift_entry) {
|
||||
if ($shift_entry->angel_type_id == $needed_angeltype['angel_type_id']) {
|
||||
$angels[] = Shift_view_render_shift_entry($shift_entry, $user_shift_admin, $angeltype_supporter, $shift);
|
||||
}
|
||||
}
|
||||
|
@ -255,30 +255,30 @@ function Shift_view_render_needed_angeltype($needed_angeltype, $angeltypes, Shif
|
|||
}
|
||||
|
||||
/**
|
||||
* @param array $shift_entry
|
||||
* @param ShiftEntry $shift_entry
|
||||
* @param bool $user_shift_admin
|
||||
* @param bool $angeltype_supporter
|
||||
* @param Shift $shift
|
||||
* @return string
|
||||
*/
|
||||
function Shift_view_render_shift_entry($shift_entry, $user_shift_admin, $angeltype_supporter, Shift $shift)
|
||||
function Shift_view_render_shift_entry(ShiftEntry $shift_entry, $user_shift_admin, $angeltype_supporter, Shift $shift)
|
||||
{
|
||||
$entry = User_Nick_render(User::find($shift_entry['UID']));
|
||||
if ($shift_entry['freeloaded']) {
|
||||
$entry = User_Nick_render($shift_entry->user);
|
||||
if ($shift_entry->freeloaded) {
|
||||
$entry = '<del>' . $entry . '</del>';
|
||||
}
|
||||
$isUser = $shift_entry['UID'] == auth()->user()->id;
|
||||
$isUser = $shift_entry->user_id == auth()->user()->id;
|
||||
if ($user_shift_admin || $angeltype_supporter || $isUser) {
|
||||
$entry .= ' <div class="btn-group m-1">';
|
||||
if ($user_shift_admin || $isUser) {
|
||||
$entry .= button_icon(
|
||||
page_link_to('user_myshifts', ['edit' => $shift_entry['id'], 'id' => $shift_entry['UID']]),
|
||||
page_link_to('user_myshifts', ['edit' => $shift_entry->id, 'id' => $shift_entry->user_id]),
|
||||
'pencil',
|
||||
'btn-sm'
|
||||
);
|
||||
}
|
||||
$angeltype = AngelType::find($shift_entry['TID']);
|
||||
$disabled = Shift_signout_allowed($shift, $angeltype, $shift_entry['UID']) ? '' : ' btn-disabled';
|
||||
$angeltype = $shift_entry->angelType;
|
||||
$disabled = Shift_signout_allowed($shift, $angeltype, $shift_entry->user_id) ? '' : ' btn-disabled';
|
||||
$entry .= button_icon(shift_entry_delete_link($shift_entry), 'trash', 'btn-sm' . $disabled);
|
||||
$entry .= '</div>';
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ use Carbon\Carbon;
|
|||
use Engelsystem\Models\AngelType;
|
||||
use Engelsystem\Models\Group;
|
||||
use Engelsystem\Models\Shifts\Shift;
|
||||
use Engelsystem\Models\Shifts\ShiftEntry;
|
||||
use Engelsystem\Models\User\User;
|
||||
use Engelsystem\Models\Worklog;
|
||||
use Illuminate\Support\Collection;
|
||||
|
@ -197,14 +198,15 @@ function User_shift_state_render($user)
|
|||
}
|
||||
|
||||
$upcoming_shifts = ShiftEntries_upcoming_for_user($user);
|
||||
if (empty($upcoming_shifts)) {
|
||||
if ($upcoming_shifts->isEmpty()) {
|
||||
return '<span class="text-success">' . __('Free') . '</span>';
|
||||
}
|
||||
|
||||
$nextShift = array_shift($upcoming_shifts);
|
||||
/** @var ShiftEntry $nextShiftEntry */
|
||||
$nextShiftEntry = $upcoming_shifts->first();
|
||||
|
||||
$start = Carbon::make($nextShift['start']);
|
||||
$end = Carbon::make($nextShift['end']);
|
||||
$start = $nextShiftEntry->shift->start;
|
||||
$end = $nextShiftEntry->shift->end;
|
||||
$startFormat = $start->format(__('Y-m-d H:i'));
|
||||
$endFormat = $end->format(__('Y-m-d H:i'));
|
||||
$startTimestamp = $start->timestamp;
|
||||
|
@ -244,8 +246,9 @@ function User_last_shift_render($user)
|
|||
return '';
|
||||
}
|
||||
|
||||
$lastShift = array_shift($last_shifts);
|
||||
$end = Carbon::make($lastShift['end']);
|
||||
/** @var ShiftEntry $lastShiftEntry */
|
||||
$lastShiftEntry = $last_shifts->first();
|
||||
$end = $lastShiftEntry->shift->end;
|
||||
|
||||
return '<span title="' . $end->format(__('Y-m-d H:i')) . '" data-countdown-ts="' . $end->timestamp . '">'
|
||||
. __('Shift ended %c')
|
||||
|
@ -307,7 +310,7 @@ function User_view_myshift(Shift $shift, $user_source, $its_me)
|
|||
];
|
||||
|
||||
if ($its_me) {
|
||||
$myshift['comment'] = $shift->Comment;
|
||||
$myshift['comment'] = $shift->user_comment;
|
||||
}
|
||||
|
||||
if ($shift->freeloaded) {
|
||||
|
@ -316,7 +319,7 @@ function User_view_myshift(Shift $shift, $user_source, $its_me)
|
|||
. '</p>';
|
||||
if (auth()->can('user_shifts_admin')) {
|
||||
$myshift['comment'] .= '<br />'
|
||||
. '<p class="text-danger">' . __('Freeloaded') . ': ' . $shift->freeload_comment . '</p>';
|
||||
. '<p class="text-danger">' . __('Freeloaded') . ': ' . $shift->freeloaded_comment . '</p>';
|
||||
} else {
|
||||
$myshift['comment'] .= '<br /><p class="text-danger">' . __('Freeloaded') . '</p>';
|
||||
}
|
||||
|
@ -332,7 +335,8 @@ function User_view_myshift(Shift $shift, $user_source, $its_me)
|
|||
'btn-sm'
|
||||
);
|
||||
}
|
||||
if (Shift_signout_allowed($shift, (new AngelType())->forceFill(['id' => $shift->TID]), $user_source->id)) {
|
||||
|
||||
if (Shift_signout_allowed($shift, (new AngelType())->forceFill(['id' => $shift->angel_type_id]), $user_source->id)) {
|
||||
$myshift['actions'][] = button(
|
||||
shift_entry_delete_link($shift),
|
||||
icon('trash') . __('sign off'),
|
||||
|
@ -591,7 +595,7 @@ function User_view(
|
|||
. $user_source->contact->dect
|
||||
. '</a>'
|
||||
)
|
||||
: '' ,
|
||||
: '',
|
||||
config('enable_mobile_show') && $user_source->contact->mobile ?
|
||||
$user_source->settings->mobile_show ?
|
||||
heading(
|
||||
|
@ -601,14 +605,14 @@ function User_view(
|
|||
. '</a>'
|
||||
)
|
||||
: ''
|
||||
: '' ,
|
||||
: '',
|
||||
$auth->can('user_messages') ?
|
||||
heading(
|
||||
'<a href="' . page_link_to('/messages/' . $user_source->id) . '">'
|
||||
. icon('envelope')
|
||||
. '</a>'
|
||||
)
|
||||
: '' ,
|
||||
: '',
|
||||
]),
|
||||
User_view_state($admin_user_privilege, $freeloader, $user_source),
|
||||
User_angeltypes_render($user_angeltypes),
|
||||
|
@ -887,7 +891,7 @@ function render_user_departure_date_hint()
|
|||
*/
|
||||
function render_user_freeloader_hint()
|
||||
{
|
||||
if (User_is_freeloader(auth()->user())) {
|
||||
if (auth()->user()->isFreeloader()) {
|
||||
return sprintf(
|
||||
__('You freeloaded at least %s shifts. Shift signup is locked. Please go to heavens desk to be unlocked again.'),
|
||||
config('max_freeloadable_shifts')
|
||||
|
|
|
@ -45,27 +45,25 @@ class Stats
|
|||
$query = State::whereArrived(true);
|
||||
|
||||
if (!is_null($working)) {
|
||||
// @codeCoverageIgnoreStart
|
||||
$query
|
||||
->leftJoin('worklogs', 'worklogs.user_id', '=', 'users_state.user_id')
|
||||
->leftJoin('ShiftEntry', 'ShiftEntry.UID', '=', 'users_state.user_id')
|
||||
->leftJoin('shift_entries', 'shift_entries.user_id', '=', 'users_state.user_id')
|
||||
->distinct();
|
||||
|
||||
$query->where(function ($query) use ($working): void {
|
||||
/** @var QueryBuilder $query */
|
||||
if ($working) {
|
||||
$query
|
||||
->whereNotNull('ShiftEntry.SID')
|
||||
->whereNotNull('shift_entries.shift_id')
|
||||
->orWhereNotNull('worklogs.hours');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$query
|
||||
->whereNull('ShiftEntry.SID')
|
||||
->whereNull('shift_entries.shift_id')
|
||||
->whereNull('worklogs.hours');
|
||||
});
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
return $query->count('users_state.user_id');
|
||||
|
@ -104,18 +102,17 @@ class Stats
|
|||
* The number of currently working users
|
||||
*
|
||||
* @param bool|null $freeloaded
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function currentlyWorkingUsers(bool $freeloaded = null): int
|
||||
{
|
||||
$query = User::query()
|
||||
->join('ShiftEntry', 'ShiftEntry.UID', '=', 'users.id')
|
||||
->join('shifts', 'shifts.id', '=', 'ShiftEntry.SID')
|
||||
->join('shift_entries', 'shift_entries.user_id', '=', 'users.id')
|
||||
->join('shifts', 'shifts.id', '=', 'shift_entries.shift_id')
|
||||
->where('shifts.start', '<=', Carbon::now())
|
||||
->where('shifts.end', '>', Carbon::now());
|
||||
|
||||
if (!is_null($freeloaded)) {
|
||||
$query->where('ShiftEntry.freeloaded', '=', $freeloaded);
|
||||
$query->where('shift_entries.freeloaded', '=', $freeloaded);
|
||||
}
|
||||
|
||||
return $query->count();
|
||||
|
@ -202,13 +199,13 @@ class Stats
|
|||
* @param bool|null $done
|
||||
* @param bool|null $freeloaded
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @codeCoverageIgnore because it is only used in functions that use TIMESTAMPDIFF
|
||||
*/
|
||||
protected function workSecondsQuery(bool $done = null, bool $freeloaded = null): QueryBuilder
|
||||
{
|
||||
$query = $this
|
||||
->getQuery('ShiftEntry')
|
||||
->join('shifts', 'shifts.id', '=', 'ShiftEntry.SID');
|
||||
->getQuery('shift_entries')
|
||||
->join('shifts', 'shifts.id', '=', 'shift_entries.shift_id');
|
||||
|
||||
if (!is_null($freeloaded)) {
|
||||
$query->where('freeloaded', '=', $freeloaded);
|
||||
|
@ -227,13 +224,13 @@ class Stats
|
|||
* @param bool|null $done
|
||||
* @param bool|null $freeloaded
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @codeCoverageIgnore as TIMESTAMPDIFF is not implemented in SQLite
|
||||
*/
|
||||
public function workSeconds(bool $done = null, bool $freeloaded = null): int
|
||||
{
|
||||
$query = $this->workSecondsQuery($done, $freeloaded);
|
||||
|
||||
return (int) $query->sum($this->raw('end - start'));
|
||||
return (int) $query->sum($this->raw('TIMESTAMPDIFF(MINUTE, start, end) * 60'));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -242,22 +239,19 @@ class Stats
|
|||
* @param bool|null $done
|
||||
* @param bool|null $freeloaded
|
||||
*
|
||||
* @codeCoverageIgnore
|
||||
* @codeCoverageIgnore as TIMESTAMPDIFF is not implemented in SQLite
|
||||
*/
|
||||
public function workBuckets(array $buckets, bool $done = null, bool $freeloaded = null): array
|
||||
{
|
||||
return $this->getBuckets(
|
||||
$buckets,
|
||||
$this->workSecondsQuery($done, $freeloaded),
|
||||
'UID',
|
||||
'SUM(end - start)',
|
||||
'SUM(end - start)'
|
||||
'user_id',
|
||||
'SUM(TIMESTAMPDIFF(MINUTE, start, end) * 60)',
|
||||
'SUM(TIMESTAMPDIFF(MINUTE, start, end) * 60)'
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore As long as its only used for old tables
|
||||
*/
|
||||
protected function getBuckets(
|
||||
array $buckets,
|
||||
BuilderContract $basicQuery,
|
||||
|
@ -281,18 +275,12 @@ class Stats
|
|||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function worklogSeconds(): int
|
||||
{
|
||||
return (int) Worklog::query()
|
||||
->sum($this->raw('hours * 60 * 60'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @codeCoverageIgnore
|
||||
*/
|
||||
public function worklogBuckets(array $buckets): array
|
||||
{
|
||||
return $this->getBuckets(
|
||||
|
|
|
@ -4,11 +4,13 @@ declare(strict_types=1);
|
|||
|
||||
namespace Engelsystem\Models;
|
||||
|
||||
use Engelsystem\Models\Shifts\ShiftEntry;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Engelsystem\Models\User\User;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Query\Builder as QueryBuilder;
|
||||
|
||||
/**
|
||||
|
@ -24,8 +26,9 @@ use Illuminate\Database\Query\Builder as QueryBuilder;
|
|||
* @property boolean $show_on_dashboard # Show on public dashboard
|
||||
* @property boolean $hide_register # Hide from registration page
|
||||
*
|
||||
* @property-read Collection|User[] $userAngelTypes
|
||||
* @property-read UserAngelType $pivot
|
||||
* @property-read Collection|ShiftEntry[] $shiftEntries
|
||||
* @property-read Collection|User[] $userAngelTypes
|
||||
*
|
||||
* @method static QueryBuilder|AngelType[] whereId($value)
|
||||
* @method static QueryBuilder|AngelType[] whereName($value)
|
||||
|
@ -68,6 +71,11 @@ class AngelType extends BaseModel
|
|||
'hide_register' => 'boolean',
|
||||
];
|
||||
|
||||
public function shiftEntries(): HasMany
|
||||
{
|
||||
return $this->hasMany(ShiftEntry::class);
|
||||
}
|
||||
|
||||
public function userAngelTypes(): BelongsToMany
|
||||
{
|
||||
return $this
|
||||
|
|
|
@ -8,8 +8,10 @@ use Carbon\Carbon;
|
|||
use Engelsystem\Models\BaseModel;
|
||||
use Engelsystem\Models\Room;
|
||||
use Engelsystem\Models\User\User;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\HasMany;
|
||||
use Illuminate\Database\Eloquent\Relations\HasOneThrough;
|
||||
use Illuminate\Database\Query\Builder as QueryBuilder;
|
||||
|
||||
|
@ -29,6 +31,7 @@ use Illuminate\Database\Query\Builder as QueryBuilder;
|
|||
* @property Carbon|null $updated_at
|
||||
*
|
||||
* @property-read QueryBuilder|Schedule $schedule
|
||||
* @property-read QueryBuilder|Collection|ShiftEntry[] $shiftEntries
|
||||
* @property-read QueryBuilder|ShiftType $shiftType
|
||||
* @property-read QueryBuilder|Room $room
|
||||
* @property-read QueryBuilder|User $createdBy
|
||||
|
@ -88,6 +91,11 @@ class Shift extends BaseModel
|
|||
return $this->hasOneThrough(Schedule::class, ScheduleShift::class, null, 'id', null, 'schedule_id');
|
||||
}
|
||||
|
||||
public function shiftEntries(): HasMany
|
||||
{
|
||||
return $this->hasMany(ShiftEntry::class);
|
||||
}
|
||||
|
||||
public function shiftType(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(ShiftType::class);
|
||||
|
|
|
@ -0,0 +1,63 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Engelsystem\Models\Shifts;
|
||||
|
||||
use Engelsystem\Models\AngelType;
|
||||
use Engelsystem\Models\BaseModel;
|
||||
use Engelsystem\Models\User\UsesUserModel;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Query\Builder as QueryBuilder;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property int $shift_id
|
||||
* @property int $angel_type_id
|
||||
* @property string $user_comment
|
||||
* @property bool $freeloaded
|
||||
* @property string $freeloaded_comment
|
||||
*
|
||||
* @property-read Shift $shift
|
||||
* @property-read AngelType $angelType
|
||||
*
|
||||
* @method static QueryBuilder|ShiftEntry[] whereId($value)
|
||||
* @method static QueryBuilder|ShiftEntry[] whereShiftId($value)
|
||||
* @method static QueryBuilder|ShiftEntry[] whereAngelTypeId($value)
|
||||
* @method static QueryBuilder|ShiftEntry[] whereUserComment($value)
|
||||
* @method static QueryBuilder|ShiftEntry[] whereFreeloaded($value)
|
||||
* @method static QueryBuilder|ShiftEntry[] whereFreeloadedComment($value)
|
||||
*/
|
||||
class ShiftEntry extends BaseModel
|
||||
{
|
||||
use HasFactory;
|
||||
use UsesUserModel;
|
||||
|
||||
/** @var array<string> */
|
||||
protected $fillable = [ // phpcs:ignore
|
||||
'shift_id',
|
||||
'angel_type_id',
|
||||
'user_id',
|
||||
'user_comment',
|
||||
'freeloaded',
|
||||
'freeloaded_comment',
|
||||
];
|
||||
|
||||
/** @var array<string, string|bool> default attributes */
|
||||
protected $attributes = [ // phpcs:ignore
|
||||
'user_comment' => '',
|
||||
'freeloaded' => false,
|
||||
'freeloaded_comment' => '',
|
||||
];
|
||||
|
||||
public function shift(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Shift::class);
|
||||
}
|
||||
|
||||
public function angelType(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(AngelType::class);
|
||||
}
|
||||
}
|
|
@ -13,6 +13,7 @@ use Engelsystem\Models\OAuth;
|
|||
use Engelsystem\Models\Privilege;
|
||||
use Engelsystem\Models\Question;
|
||||
use Engelsystem\Models\Shifts\Shift;
|
||||
use Engelsystem\Models\Shifts\ShiftEntry;
|
||||
use Engelsystem\Models\UserAngelType;
|
||||
use Engelsystem\Models\Worklog;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
@ -47,6 +48,7 @@ use Illuminate\Support\Collection as SupportCollection;
|
|||
* @property-read SupportCollection|Privilege[] $privileges
|
||||
* @property-read Collection|AngelType[] $userAngelTypes
|
||||
* @property-read UserAngelType $pivot
|
||||
* @property-read Collection|ShiftEntry[] $shiftEntries
|
||||
* @property-read Collection|Worklog[] $worklogs
|
||||
* @property-read Collection|Worklog[] $worklogsCreated
|
||||
* @property-read Collection|Question[] $questionsAsked
|
||||
|
@ -109,6 +111,14 @@ class User extends BaseModel
|
|||
return $this->belongsToMany(Group::class, 'users_groups');
|
||||
}
|
||||
|
||||
public function isFreeloader(): bool
|
||||
{
|
||||
return $this->shiftEntries()
|
||||
->where('freeloaded', true)
|
||||
->count()
|
||||
>= config('max_freeloadable_shifts');
|
||||
}
|
||||
|
||||
public function license(): HasOne
|
||||
{
|
||||
return $this
|
||||
|
@ -189,6 +199,11 @@ class User extends BaseModel
|
|||
return $this->hasMany(OAuth::class);
|
||||
}
|
||||
|
||||
public function shiftEntries(): HasMany
|
||||
{
|
||||
return $this->hasMany(ShiftEntry::class);
|
||||
}
|
||||
|
||||
public function worklogs(): HasMany
|
||||
{
|
||||
return $this->hasMany(Worklog::class);
|
||||
|
|
|
@ -76,8 +76,10 @@ class TwigServiceProvider extends ServiceProvider
|
|||
$this->app->instance('twig.loader', $twigLoader);
|
||||
|
||||
$cache = $this->app->get('path.cache.views');
|
||||
$twigDebug = false;
|
||||
if ($config->get('environment') == 'development') {
|
||||
$cache = false;
|
||||
$twigDebug = true;
|
||||
}
|
||||
|
||||
$twig = $this->app->make(
|
||||
|
@ -86,7 +88,8 @@ class TwigServiceProvider extends ServiceProvider
|
|||
'options' => [
|
||||
'cache' => $cache,
|
||||
'auto_reload' => true,
|
||||
'strict_variables' => ($config->get('environment') == 'development'),
|
||||
'debug' => $twigDebug,
|
||||
'strict_variables' => $twigDebug,
|
||||
],
|
||||
]
|
||||
);
|
||||
|
|
|
@ -13,6 +13,7 @@ use Engelsystem\Models\OAuth;
|
|||
use Engelsystem\Models\Question;
|
||||
use Engelsystem\Models\Room;
|
||||
use Engelsystem\Models\Shifts\Shift;
|
||||
use Engelsystem\Models\Shifts\ShiftEntry;
|
||||
use Engelsystem\Models\User\License;
|
||||
use Engelsystem\Models\User\PasswordReset;
|
||||
use Engelsystem\Models\User\PersonalData;
|
||||
|
@ -163,6 +164,35 @@ class StatsTest extends TestCase
|
|||
$this->assertEquals(2.4 * 60 * 60 + 1.2 * 60 * 60, $seconds);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Engelsystem\Controllers\Metrics\Stats::worklogBuckets
|
||||
* @covers \Engelsystem\Controllers\Metrics\Stats::getBuckets
|
||||
*/
|
||||
public function testWorklogBuckets(): void
|
||||
{
|
||||
Worklog::factory()->create(['hours' => 1.2, 'worked_at' => Carbon::now()->subDay()]);
|
||||
Worklog::factory()->create(['hours' => 1.9, 'worked_at' => Carbon::now()->subDay()]);
|
||||
Worklog::factory()->create(['hours' => 3, 'worked_at' => Carbon::now()->subDay()]);
|
||||
Worklog::factory()->create(['hours' => 10, 'worked_at' => Carbon::now()->subDay()]);
|
||||
|
||||
$stats = new Stats($this->database);
|
||||
$buckets = $stats->worklogBuckets([
|
||||
1 * 60 * 60,
|
||||
2 * 60 * 60,
|
||||
3 * 60 * 60,
|
||||
4 * 60 * 60,
|
||||
'+Inf'
|
||||
]);
|
||||
|
||||
$this->assertEquals([
|
||||
3600 => 0,
|
||||
7200 => 2,
|
||||
10800 => 3,
|
||||
14400 => 3,
|
||||
'+Inf' => 4,
|
||||
], $buckets);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Engelsystem\Controllers\Metrics\Stats::rooms
|
||||
*/
|
||||
|
@ -251,9 +281,13 @@ class StatsTest extends TestCase
|
|||
public function testArrivedUsers(): void
|
||||
{
|
||||
$this->addUsers();
|
||||
ShiftEntry::factory()->create(['user_id' => 3]);
|
||||
ShiftEntry::factory()->create(['user_id' => 4]);
|
||||
|
||||
$stats = new Stats($this->database);
|
||||
$this->assertEquals(7, $stats->arrivedUsers());
|
||||
$this->assertEquals(5, $stats->arrivedUsers(false));
|
||||
$this->assertEquals(2, $stats->arrivedUsers(true));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -293,6 +327,25 @@ class StatsTest extends TestCase
|
|||
$this->assertEquals(1, $stats->email('news'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Engelsystem\Controllers\Metrics\Stats::currentlyWorkingUsers
|
||||
*/
|
||||
public function testCurrentlyWorkingUsers(): void
|
||||
{
|
||||
$this->addUsers();
|
||||
/** @var Shift $shift */
|
||||
$shift = Shift::factory()->create(['start' => Carbon::now()->subHour(), 'end' => Carbon::now()->addHour()]);
|
||||
|
||||
ShiftEntry::factory()->create(['shift_id' => $shift->id]);
|
||||
ShiftEntry::factory()->create(['shift_id' => $shift->id]);
|
||||
ShiftEntry::factory()->create(['shift_id' => $shift->id, 'freeloaded' => true]);
|
||||
|
||||
$stats = new Stats($this->database);
|
||||
$this->assertEquals(3, $stats->currentlyWorkingUsers());
|
||||
$this->assertEquals(2, $stats->currentlyWorkingUsers(false));
|
||||
$this->assertEquals(1, $stats->currentlyWorkingUsers(true));
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Engelsystem\Controllers\Metrics\Stats::faq
|
||||
*/
|
||||
|
|
|
@ -10,6 +10,7 @@ use Engelsystem\Models\Question;
|
|||
use Engelsystem\Models\Room;
|
||||
use Engelsystem\Models\Shifts\Schedule;
|
||||
use Engelsystem\Models\Shifts\Shift;
|
||||
use Engelsystem\Models\Shifts\ShiftEntry;
|
||||
use Engelsystem\Models\User\Contact;
|
||||
use Engelsystem\Models\User\License;
|
||||
use Engelsystem\Models\User\PasswordReset;
|
||||
|
@ -41,6 +42,7 @@ class FactoriesTest extends TestCase
|
|||
[Question::class],
|
||||
[Room::class],
|
||||
[Schedule::class],
|
||||
[ShiftEntry::class],
|
||||
[Settings::class],
|
||||
[Shift::class],
|
||||
[State::class],
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
namespace Engelsystem\Test\Unit\Models;
|
||||
|
||||
use Engelsystem\Models\AngelType;
|
||||
use Engelsystem\Models\Shifts\ShiftEntry;
|
||||
use Engelsystem\Models\User\User;
|
||||
use Engelsystem\Models\UserAngelType;
|
||||
|
||||
|
@ -47,8 +48,7 @@ class AngelTypeTest extends ModelTest
|
|||
User::factory(1)->create();
|
||||
$user2 = User::factory()->create();
|
||||
|
||||
$angelType = new AngelType(['name' => 'Test']);
|
||||
$angelType->save();
|
||||
$angelType = AngelType::create(['name' => 'Test']);
|
||||
|
||||
$angelType->userAngelTypes()->attach($user1);
|
||||
$angelType->userAngelTypes()->attach($user2);
|
||||
|
@ -61,6 +61,18 @@ class AngelTypeTest extends ModelTest
|
|||
$this->assertCount(2, $angeltypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Engelsystem\Models\AngelType::shiftEntries
|
||||
*/
|
||||
public function testShiftEntries(): void
|
||||
{
|
||||
$angelType = AngelType::create(['name' => 'test type']);
|
||||
|
||||
ShiftEntry::factory(3)->create(['angel_type_id' => $angelType->id]);
|
||||
|
||||
$this->assertCount(3, $angelType->shiftEntries);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Engelsystem\Models\AngelType::boot
|
||||
*/
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
|
||||
namespace Engelsystem\Test\Unit\Models\Shifts;
|
||||
|
||||
use Engelsystem\Models\AngelType;
|
||||
use Engelsystem\Models\Shifts\Shift;
|
||||
use Engelsystem\Models\Shifts\ShiftEntry;
|
||||
use Engelsystem\Models\User\User;
|
||||
use Engelsystem\Test\Unit\Models\ModelTest;
|
||||
|
||||
class ShiftEntryTest extends ModelTest
|
||||
{
|
||||
/**
|
||||
* @covers \Engelsystem\Models\Shifts\ShiftEntry::shift
|
||||
* @covers \Engelsystem\Models\Shifts\ShiftEntry::angelType
|
||||
*/
|
||||
public function testShift(): void
|
||||
{
|
||||
/** @var Shift $shift */
|
||||
$shift = Shift::factory()->create();
|
||||
/** @var AngelType $angelType */
|
||||
$angelType = AngelType::factory()->create();
|
||||
/** @var User $user */
|
||||
$user = User::factory()->create();
|
||||
|
||||
$model = new ShiftEntry();
|
||||
$model->shift()->associate($shift);
|
||||
$model->angelType()->associate($angelType);
|
||||
$model->user()->associate($user);
|
||||
$model->save();
|
||||
|
||||
$model = ShiftEntry::find(1);
|
||||
$this->assertEquals($shift->id, $model->shift->id);
|
||||
$this->assertEquals($angelType->id, $model->angelType->id);
|
||||
$this->assertEquals($user->id, $model->user->id);
|
||||
}
|
||||
}
|
|
@ -9,6 +9,7 @@ use Engelsystem\Models\Room;
|
|||
use Engelsystem\Models\Shifts\Schedule;
|
||||
use Engelsystem\Models\Shifts\ScheduleShift;
|
||||
use Engelsystem\Models\Shifts\Shift;
|
||||
use Engelsystem\Models\Shifts\ShiftEntry;
|
||||
use Engelsystem\Models\Shifts\ShiftType;
|
||||
use Engelsystem\Models\User\User;
|
||||
use Engelsystem\Test\Unit\Models\ModelTest;
|
||||
|
@ -73,4 +74,18 @@ class ShiftTest extends ModelTest
|
|||
$this->assertEquals(1, Shift::find(2)->schedule->id);
|
||||
$this->assertEquals(1, Shift::find(3)->schedule->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Engelsystem\Models\Shifts\Shift::shiftEntries
|
||||
*/
|
||||
public function testShiftEntries(): void
|
||||
{
|
||||
/** @var Shift $shift */
|
||||
$shift = Shift::factory()->make();
|
||||
$shift->save();
|
||||
|
||||
ShiftEntry::factory(5)->create(['shift_id' => $shift->id]);
|
||||
|
||||
$this->assertCount(5, $shift->shiftEntries);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@ namespace Engelsystem\Test\Unit\Models\User;
|
|||
|
||||
use Carbon\Carbon;
|
||||
use DMS\PHPUnitExtensions\ArraySubset\ArraySubsetAsserts;
|
||||
use Engelsystem\Config\Config;
|
||||
use Engelsystem\Models\AngelType;
|
||||
use Engelsystem\Models\BaseModel;
|
||||
use Engelsystem\Models\Group;
|
||||
|
@ -13,6 +14,7 @@ use Engelsystem\Models\OAuth;
|
|||
use Engelsystem\Models\Privilege;
|
||||
use Engelsystem\Models\Question;
|
||||
use Engelsystem\Models\Shifts\Shift;
|
||||
use Engelsystem\Models\Shifts\ShiftEntry;
|
||||
use Engelsystem\Models\User\Contact;
|
||||
use Engelsystem\Models\User\HasUserModel;
|
||||
use Engelsystem\Models\User\License;
|
||||
|
@ -209,6 +211,30 @@ class UserTest extends ModelTest
|
|||
$this->assertEquals($relatedModelIds, $user->{$name}->modelKeys());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Engelsystem\Models\User\User::isFreeloader
|
||||
*/
|
||||
public function testIsFreeloader(): void
|
||||
{
|
||||
$this->app->instance('config', new Config([
|
||||
'max_freeloadable_shifts' => 2,
|
||||
]));
|
||||
|
||||
$user = new User($this->data);
|
||||
$user->save();
|
||||
$this->assertFalse($user->isFreeloader());
|
||||
|
||||
ShiftEntry::factory()->create(['user_id' => $user->id]);
|
||||
ShiftEntry::factory()->create(['user_id' => $user->id, 'freeloaded' => true]);
|
||||
$this->assertFalse($user->isFreeloader());
|
||||
|
||||
ShiftEntry::factory()->create(['user_id' => $user->id, 'freeloaded' => true]);
|
||||
$this->assertTrue($user->isFreeloader());
|
||||
|
||||
ShiftEntry::factory()->create(['user_id' => $user->id, 'freeloaded' => true]);
|
||||
$this->assertTrue($user->isFreeloader());
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Engelsystem\Models\User\User::userAngelTypes
|
||||
*/
|
||||
|
@ -334,6 +360,19 @@ class UserTest extends ModelTest
|
|||
$this->assertCount(1, $oauth);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Engelsystem\Models\User\User::shiftEntries
|
||||
*/
|
||||
public function testShiftEntries(): void
|
||||
{
|
||||
$user = new User($this->data);
|
||||
$user->save();
|
||||
|
||||
ShiftEntry::factory(2)->create(['user_id' => $user->id]);
|
||||
|
||||
$this->assertCount(2, $user->shiftEntries);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Engelsystem\Models\User\User::worklogs
|
||||
*/
|
||||
|
|
|
@ -40,7 +40,7 @@ abstract class ExtensionTest extends TestCase
|
|||
*/
|
||||
protected function assertExtensionExists(
|
||||
string $name,
|
||||
callable $callback,
|
||||
mixed $callback,
|
||||
array $functions,
|
||||
array $options = []
|
||||
): void {
|
||||
|
|
|
@ -136,7 +136,12 @@ class TwigServiceProviderTest extends ServiceProviderTest
|
|||
->method('make')
|
||||
->withConsecutive(
|
||||
[TwigLoader::class, ['paths' => $viewsPath]],
|
||||
[Twig::class, ['options' => ['cache' => false, 'auto_reload' => true, 'strict_variables' => true]]],
|
||||
[Twig::class, ['options' => [
|
||||
'cache' => false,
|
||||
'auto_reload' => true,
|
||||
'strict_variables' => true,
|
||||
'debug' => true,
|
||||
]]],
|
||||
[TwigEngine::class]
|
||||
)->willReturnOnConsecutiveCalls(
|
||||
$twigLoader,
|
||||
|
@ -162,10 +167,10 @@ class TwigServiceProviderTest extends ServiceProviderTest
|
|||
|
||||
$this->setExpects($app, 'tag', ['renderer.twigEngine', ['renderer.engine']]);
|
||||
|
||||
$config->expects($this->exactly(3))
|
||||
$config->expects($this->exactly(2))
|
||||
->method('get')
|
||||
->withConsecutive(['environment'], ['environment'], ['timezone'])
|
||||
->willReturnOnConsecutiveCalls('development', 'development', 'The/World');
|
||||
->withConsecutive(['environment'], ['timezone'])
|
||||
->willReturnOnConsecutiveCalls('development', 'The/World');
|
||||
|
||||
$twig->expects($this->once())
|
||||
->method('getExtension')
|
||||
|
|
Loading…
Reference in New Issue