Implemented loading angels by shift type on schedule import
This commit is contained in:
parent
909f7bba5a
commit
4bbeb93d64
|
@ -17,11 +17,12 @@ class NeededAngelTypeFactory extends Factory
|
|||
|
||||
public function definition(): array
|
||||
{
|
||||
$forLocation = $this->faker->boolean();
|
||||
$type = $this->faker->numberBetween(0, 2);
|
||||
|
||||
return [
|
||||
'location_id' => $forLocation ? Location::factory() : null,
|
||||
'shift_id' => $forLocation ? null : Shift::factory(),
|
||||
'location_id' => $type == 0 ? Location::factory() : null,
|
||||
'shift_id' => $type == 1 ? null : Shift::factory(),
|
||||
'shift_type_id' => $type == 2 ? null : Shift::factory(),
|
||||
'angel_type_id' => AngelType::factory(),
|
||||
'count' => $this->faker->numberBetween(1, 5),
|
||||
];
|
||||
|
|
|
@ -18,6 +18,7 @@ class ScheduleFactory extends Factory
|
|||
'name' => $this->faker->unique()->words(4, true),
|
||||
'url' => $this->faker->parse('https://{{safeEmailDomain}}/{{slug}}.xml'),
|
||||
'shift_type' => $this->faker->numberBetween(1, 5),
|
||||
'needed_from_shift_type' => $this->faker->boolean(.2),
|
||||
'minutes_before' => 15,
|
||||
'minutes_after' => 15,
|
||||
];
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Engelsystem\Migrations;
|
||||
|
||||
use Engelsystem\Database\Migration\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
|
||||
class ScheduleShiftTypeNeededAngelTypes extends Migration
|
||||
{
|
||||
use Reference;
|
||||
|
||||
/**
|
||||
* Run the migration
|
||||
*/
|
||||
public function up(): void
|
||||
{
|
||||
$this->schema->table('schedules', function (Blueprint $table): void {
|
||||
$table->boolean('needed_from_shift_type')->after('shift_type')->default(false);
|
||||
});
|
||||
$this->schema->table('needed_angel_types', function (Blueprint $table): void {
|
||||
$this->references($table, 'shift_types')->after('shift_id')->nullable();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migration
|
||||
*/
|
||||
public function down(): void
|
||||
{
|
||||
$this->schema->table('schedules', function (Blueprint $table): void {
|
||||
$table->dropColumn('needed_from_shift_type');
|
||||
});
|
||||
$this->schema->table('needed_angel_types', function (Blueprint $table): void {
|
||||
$table->dropForeign('needed_angel_types_shift_type_id_foreign');
|
||||
$table->dropColumn('shift_type_id');
|
||||
});
|
||||
}
|
||||
}
|
|
@ -74,7 +74,7 @@ function shift_edit_controller()
|
|||
$angeltypes = AngelType::all()->pluck('name', 'id')->toArray();
|
||||
$shifttypes = ShiftType::all()->pluck('name', 'id')->toArray();
|
||||
|
||||
$needed_angel_types = collect(NeededAngelTypes_by_shift($shift_id))->pluck('count', 'angel_type_id')->toArray();
|
||||
$needed_angel_types = collect(NeededAngelTypes_by_shift($shift))->pluck('count', 'angel_type_id')->toArray();
|
||||
foreach (array_keys($angeltypes) as $angeltype_id) {
|
||||
if (!isset($needed_angel_types[$angeltype_id])) {
|
||||
$needed_angel_types[$angeltype_id] = 0;
|
||||
|
|
|
@ -1,47 +1,70 @@
|
|||
<?php
|
||||
|
||||
use Engelsystem\Database\Db;
|
||||
use Engelsystem\Models\Shifts\Shift;
|
||||
use Engelsystem\Models\Shifts\ShiftEntry;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
|
||||
/**
|
||||
* Returns all needed angeltypes and already taken needs.
|
||||
*
|
||||
* @param int $shiftId id of shift
|
||||
* @param Shift $shift
|
||||
* @return array
|
||||
*/
|
||||
function NeededAngelTypes_by_shift($shiftId)
|
||||
function NeededAngelTypes_by_shift($shift)
|
||||
{
|
||||
$needed_angeltypes_source = Db::select(
|
||||
'
|
||||
$needed_angeltypes_source = [];
|
||||
// Select from shift
|
||||
if (!$shift->schedule) {
|
||||
$needed_angeltypes_source = Db::select(
|
||||
'
|
||||
SELECT
|
||||
`needed_angel_types`.*,
|
||||
`angel_types`.`id`,
|
||||
`angel_types`.`name`,
|
||||
`angel_types`.`restricted`,
|
||||
`angel_types`.`shift_self_signup`
|
||||
FROM `needed_angel_types`
|
||||
JOIN `angel_types` ON `angel_types`.`id` = `needed_angel_types`.`angel_type_id`
|
||||
WHERE `shift_id` = ?
|
||||
ORDER BY `location_id` DESC',
|
||||
[$shiftId]
|
||||
);
|
||||
WHERE `needed_angel_types`.`shift_id` = ?
|
||||
ORDER BY `location_id` DESC
|
||||
',
|
||||
[$shift->id]
|
||||
);
|
||||
}
|
||||
|
||||
// Use settings from location
|
||||
if (count($needed_angeltypes_source) == 0) {
|
||||
// Get needed by shift type
|
||||
if ($shift->schedule && $shift->schedule->needed_from_shift_type) {
|
||||
$needed_angeltypes_source = Db::select('
|
||||
SELECT `needed_angel_types`.*, `angel_types`.`name`, `angel_types`.`restricted`
|
||||
SELECT
|
||||
`needed_angel_types`.*,
|
||||
`angel_types`.`name`,
|
||||
`angel_types`.`restricted`,
|
||||
`angel_types`.`shift_self_signup`
|
||||
FROM `needed_angel_types`
|
||||
JOIN `angel_types` ON `angel_types`.`id` = `needed_angel_types`.`angel_type_id`
|
||||
JOIN `shifts` ON `shifts`.`location_id` = `needed_angel_types`.`location_id`
|
||||
WHERE `shifts`.`id` = ?
|
||||
WHERE `needed_angel_types`.`shift_type_id` = ?
|
||||
ORDER BY `location_id` DESC
|
||||
', [$shiftId]);
|
||||
', [$shift->shift_type_id]);
|
||||
}
|
||||
|
||||
// Load from room
|
||||
if ($shift->schedule && !$shift->schedule->needed_from_shift_type) {
|
||||
$needed_angeltypes_source = Db::select('
|
||||
SELECT
|
||||
`needed_angel_types`.*,
|
||||
`angel_types`.`name`,
|
||||
`angel_types`.`restricted`,
|
||||
`angel_types`.`shift_self_signup`
|
||||
FROM `needed_angel_types`
|
||||
JOIN `angel_types` ON `angel_types`.`id` = `needed_angel_types`.`angel_type_id`
|
||||
WHERE `needed_angel_types`.`location_id` = ?
|
||||
ORDER BY `location_id` DESC
|
||||
', [$shift->location_id]);
|
||||
}
|
||||
|
||||
/** @var ShiftEntry[]|Collection $shift_entries */
|
||||
$shift_entries = ShiftEntry::with('user', 'angelType')
|
||||
->where('shift_id', $shiftId)
|
||||
->where('shift_id', $shift->id)
|
||||
->get();
|
||||
$needed_angeltypes = [];
|
||||
foreach ($needed_angeltypes_source as $angeltype) {
|
||||
|
|
|
@ -28,12 +28,26 @@ function Shifts_by_angeltype(AngelType $angeltype)
|
|||
|
||||
UNION
|
||||
|
||||
/* By shift type */
|
||||
SELECT DISTINCT `shifts`.* FROM `shifts`
|
||||
JOIN `needed_angel_types` ON `needed_angel_types`.`shift_type_id` = `shifts`.`shift_type_id`
|
||||
LEFT JOIN schedule_shift AS s on shifts.id = s.shift_id
|
||||
LEFT JOIN schedules AS se on s.schedule_id = se.id
|
||||
WHERE `needed_angel_types`.`angel_type_id` = ?
|
||||
AND NOT s.shift_id IS NULL
|
||||
AND se.needed_from_shift_type = TRUE
|
||||
|
||||
UNION
|
||||
|
||||
/* By location */
|
||||
SELECT DISTINCT `shifts`.* FROM `shifts`
|
||||
JOIN `needed_angel_types` ON `needed_angel_types`.`location_id` = `shifts`.`location_id`
|
||||
LEFT JOIN schedule_shift AS s on shifts.id = s.shift_id
|
||||
LEFT JOIN schedules AS se on s.schedule_id = se.id
|
||||
WHERE `needed_angel_types`.`angel_type_id` = ?
|
||||
AND NOT s.shift_id IS NULL
|
||||
', [$angeltype->id, $angeltype->id]);
|
||||
AND se.needed_from_shift_type = FALSE
|
||||
', [$angeltype->id, $angeltype->id, $angeltype->id]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -53,7 +67,7 @@ function Shifts_free($start, $end, ShiftsFilter $filter = null)
|
|||
$shifts = Db::select('
|
||||
SELECT *
|
||||
FROM (
|
||||
SELECT id, start
|
||||
SELECT shifts.id, start
|
||||
FROM `shifts`
|
||||
LEFT JOIN schedule_shift AS s on shifts.id = s.shift_id
|
||||
WHERE (`end` > ? AND `start` < ?)
|
||||
|
@ -64,13 +78,30 @@ function Shifts_free($start, $end, ShiftsFilter $filter = null)
|
|||
|
||||
UNION
|
||||
|
||||
SELECT id, start
|
||||
/* By shift type */
|
||||
SELECT shifts.id, start
|
||||
FROM `shifts`
|
||||
LEFT JOIN schedule_shift AS s on shifts.id = s.shift_id
|
||||
LEFT JOIN schedules AS se on s.schedule_id = se.id
|
||||
WHERE (`end` > ? AND `start` < ?)
|
||||
AND (SELECT SUM(`count`) FROM `needed_angel_types` WHERE `needed_angel_types`.`shift_type_id`=`shifts`.`shift_type_id`' . ($filter ? ' AND needed_angel_types.angel_type_id 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 NOT s.shift_id IS NULL
|
||||
AND se.needed_from_shift_type = TRUE
|
||||
' . ($filter ? 'AND shifts.location_id IN (' . implode(',', $filter->getLocations()) . ')' : '') . '
|
||||
|
||||
UNION
|
||||
|
||||
/* By location */
|
||||
SELECT shifts.id, start
|
||||
FROM `shifts`
|
||||
LEFT JOIN schedule_shift AS s on shifts.id = s.shift_id
|
||||
LEFT JOIN schedules AS se on s.schedule_id = se.id
|
||||
WHERE (`end` > ? AND `start` < ?)
|
||||
AND (SELECT SUM(`count`) FROM `needed_angel_types` WHERE `needed_angel_types`.`location_id`=`shifts`.`location_id`' . ($filter ? ' AND needed_angel_types.angel_type_id 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()) . ')' : '') . ')
|
||||
> (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 NOT s.shift_id IS NULL
|
||||
AND se.needed_from_shift_type = FALSE
|
||||
' . ($filter ? 'AND shifts.location_id IN (' . implode(',', $filter->getLocations()) . ')' : '') . '
|
||||
) AS `tmp`
|
||||
ORDER BY `tmp`.`start`
|
||||
|
@ -79,6 +110,8 @@ function Shifts_free($start, $end, ShiftsFilter $filter = null)
|
|||
$end,
|
||||
$start,
|
||||
$end,
|
||||
$start,
|
||||
$end,
|
||||
]);
|
||||
|
||||
$shifts = collect($shifts);
|
||||
|
@ -110,16 +143,35 @@ function Shifts_by_ShiftsFilter(ShiftsFilter $shiftsFilter)
|
|||
|
||||
UNION
|
||||
|
||||
/* By shift type */
|
||||
SELECT DISTINCT `shifts`.*, `shift_types`.`name`, `locations`.`name` AS `location_name`
|
||||
FROM `shifts`
|
||||
JOIN `locations` ON `shifts`.`location_id` = `locations`.`id`
|
||||
JOIN `shift_types` ON `shift_types`.`id` = `shifts`.`shift_type_id`
|
||||
JOIN `needed_angel_types` ON `needed_angel_types`.`shift_type_id`=`shifts`.`shift_type_id`
|
||||
LEFT JOIN schedule_shift AS s on shifts.id = s.shift_id
|
||||
LEFT JOIN schedules AS se on s.schedule_id = se.id
|
||||
WHERE `shifts`.`location_id` IN (' . implode(',', $shiftsFilter->getLocations()) . ')
|
||||
AND `start` BETWEEN ? AND ?
|
||||
AND `needed_angel_types`.`angel_type_id` IN (' . implode(',', $shiftsFilter->getTypes()) . ')
|
||||
AND NOT s.shift_id IS NULL
|
||||
AND se.needed_from_shift_type = TRUE
|
||||
|
||||
UNION
|
||||
|
||||
/* By location */
|
||||
SELECT DISTINCT `shifts`.*, `shift_types`.`name`, `locations`.`name` AS `location_name`
|
||||
FROM `shifts`
|
||||
JOIN `locations` ON `shifts`.`location_id` = `locations`.`id`
|
||||
JOIN `shift_types` ON `shift_types`.`id` = `shifts`.`shift_type_id`
|
||||
JOIN `needed_angel_types` ON `needed_angel_types`.`location_id`=`shifts`.`location_id`
|
||||
LEFT JOIN schedule_shift AS s on shifts.id = s.shift_id
|
||||
LEFT JOIN schedules AS se on s.schedule_id = se.id
|
||||
WHERE `shifts`.`location_id` IN (' . implode(',', $shiftsFilter->getLocations()) . ')
|
||||
AND `start` BETWEEN ? AND ?
|
||||
AND `needed_angel_types`.`angel_type_id` IN (' . implode(',', $shiftsFilter->getTypes()) . ')
|
||||
AND NOT s.shift_id IS NULL
|
||||
AND se.needed_from_shift_type = FALSE
|
||||
) AS tmp_shifts
|
||||
|
||||
ORDER BY `location_name`, `start`
|
||||
|
@ -132,6 +184,8 @@ function Shifts_by_ShiftsFilter(ShiftsFilter $shiftsFilter)
|
|||
$shiftsFilter->getEnd(),
|
||||
$shiftsFilter->getStart(),
|
||||
$shiftsFilter->getEnd(),
|
||||
$shiftsFilter->getStart(),
|
||||
$shiftsFilter->getEnd(),
|
||||
]
|
||||
);
|
||||
|
||||
|
@ -167,6 +221,27 @@ function NeededAngeltypes_by_ShiftsFilter(ShiftsFilter $shiftsFilter)
|
|||
|
||||
UNION
|
||||
|
||||
/* By shift type */
|
||||
SELECT
|
||||
`needed_angel_types`.*,
|
||||
`shifts`.`id` AS shift_id,
|
||||
`angel_types`.`id`,
|
||||
`angel_types`.`name`,
|
||||
`angel_types`.`restricted`,
|
||||
`angel_types`.`shift_self_signup`
|
||||
FROM `shifts`
|
||||
JOIN `needed_angel_types` ON `needed_angel_types`.`shift_type_id`=`shifts`.`shift_type_id`
|
||||
JOIN `angel_types` ON `angel_types`.`id`= `needed_angel_types`.`angel_type_id`
|
||||
LEFT JOIN schedule_shift AS s on shifts.id = s.shift_id
|
||||
LEFT JOIN schedules AS se on s.schedule_id = se.id
|
||||
WHERE `shifts`.`location_id` IN (' . implode(',', $shiftsFilter->getLocations()) . ')
|
||||
AND shifts.`start` BETWEEN ? AND ?
|
||||
AND NOT s.shift_id IS NULL
|
||||
AND se.needed_from_shift_type = TRUE
|
||||
|
||||
UNION
|
||||
|
||||
/* By location */
|
||||
SELECT
|
||||
`needed_angel_types`.*,
|
||||
`shifts`.`id` AS shift_id,
|
||||
|
@ -178,9 +253,11 @@ function NeededAngeltypes_by_ShiftsFilter(ShiftsFilter $shiftsFilter)
|
|||
JOIN `needed_angel_types` ON `needed_angel_types`.`location_id`=`shifts`.`location_id`
|
||||
JOIN `angel_types` ON `angel_types`.`id`= `needed_angel_types`.`angel_type_id`
|
||||
LEFT JOIN schedule_shift AS s on shifts.id = s.shift_id
|
||||
LEFT JOIN schedules AS se on s.schedule_id = se.id
|
||||
WHERE `shifts`.`location_id` IN (' . implode(',', $shiftsFilter->getLocations()) . ')
|
||||
AND shifts.`start` BETWEEN ? AND ?
|
||||
AND NOT s.shift_id IS NULL
|
||||
AND se.needed_from_shift_type = FALSE
|
||||
';
|
||||
|
||||
return Db::select(
|
||||
|
@ -190,6 +267,8 @@ function NeededAngeltypes_by_ShiftsFilter(ShiftsFilter $shiftsFilter)
|
|||
$shiftsFilter->getEnd(),
|
||||
$shiftsFilter->getStart(),
|
||||
$shiftsFilter->getEnd(),
|
||||
$shiftsFilter->getStart(),
|
||||
$shiftsFilter->getEnd(),
|
||||
]
|
||||
);
|
||||
}
|
||||
|
@ -220,6 +299,27 @@ function NeededAngeltype_by_Shift_and_Angeltype(Shift $shift, AngelType $angelty
|
|||
|
||||
UNION
|
||||
|
||||
/* By shift type */
|
||||
SELECT
|
||||
`needed_angel_types`.*,
|
||||
`shifts`.`id` AS shift_id,
|
||||
`angel_types`.`id`,
|
||||
`angel_types`.`name`,
|
||||
`angel_types`.`restricted`,
|
||||
`angel_types`.`shift_self_signup`
|
||||
FROM `shifts`
|
||||
JOIN `needed_angel_types` ON `needed_angel_types`.`shift_type_id`=`shifts`.`shift_type_id`
|
||||
JOIN `angel_types` ON `angel_types`.`id`= `needed_angel_types`.`angel_type_id`
|
||||
LEFT JOIN schedule_shift AS s on shifts.id = s.shift_id
|
||||
LEFT JOIN schedules AS se on s.schedule_id = se.id
|
||||
WHERE `shifts`.`id`=?
|
||||
AND `angel_types`.`id`=?
|
||||
AND NOT s.shift_id IS NULL
|
||||
AND se.needed_from_shift_type = TRUE
|
||||
|
||||
UNION
|
||||
|
||||
/* By location */
|
||||
SELECT
|
||||
`needed_angel_types`.*,
|
||||
`shifts`.`id` AS shift_id,
|
||||
|
@ -231,15 +331,19 @@ function NeededAngeltype_by_Shift_and_Angeltype(Shift $shift, AngelType $angelty
|
|||
JOIN `needed_angel_types` ON `needed_angel_types`.`location_id`=`shifts`.`location_id`
|
||||
JOIN `angel_types` ON `angel_types`.`id`= `needed_angel_types`.`angel_type_id`
|
||||
LEFT JOIN schedule_shift AS s on shifts.id = s.shift_id
|
||||
LEFT JOIN schedules AS se on s.schedule_id = se.id
|
||||
WHERE `shifts`.`id`=?
|
||||
AND `angel_types`.`id`=?
|
||||
AND NOT s.shift_id IS NULL
|
||||
AND se.needed_from_shift_type = FALSE
|
||||
',
|
||||
[
|
||||
$shift->id,
|
||||
$angeltype->id,
|
||||
$shift->id,
|
||||
$angeltype->id,
|
||||
$shift->id,
|
||||
$angeltype->id,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
@ -559,7 +663,7 @@ function Shift($shift)
|
|||
}
|
||||
|
||||
$neededAngels = [];
|
||||
$angelTypes = NeededAngelTypes_by_shift($shift->id);
|
||||
$angelTypes = NeededAngelTypes_by_shift($shift);
|
||||
foreach ($angelTypes as $type) {
|
||||
$neededAngels[] = [
|
||||
'angel_type_id' => $type['angel_type_id'],
|
||||
|
|
|
@ -47,19 +47,36 @@ function stats_hours_to_work(ShiftsFilter $filter = null)
|
|||
* TIMESTAMPDIFF(MINUTE, `shifts`.`start`, `shifts`.`end`) / 60 AS `count`
|
||||
FROM `shifts`
|
||||
LEFT JOIN schedule_shift AS s on shifts.id = s.shift_id
|
||||
WHERE `shifts`.`end` >= NOW()
|
||||
WHERE shifts.`end` >= NOW()
|
||||
AND s.shift_id IS NULL
|
||||
' . ($filter ? 'AND shifts.location_id IN (' . implode(',', $filter->getLocations()) . ')' : '') . '
|
||||
|
||||
UNION ALL
|
||||
|
||||
/* By shift type */
|
||||
SELECT
|
||||
(SELECT SUM(`count`) FROM `needed_angel_types` WHERE `needed_angel_types`.`shift_type_id`=`shifts`.`shift_type_id`' . ($filter ? ' AND needed_angel_types.angel_type_id IN (' . implode(',', $filter->getTypes()) . ')' : '') . ')
|
||||
* TIMESTAMPDIFF(MINUTE, `shifts`.`start`, `shifts`.`end`) / 60 AS `count`
|
||||
FROM `shifts`
|
||||
LEFT JOIN schedule_shift AS s on shifts.id = s.shift_id
|
||||
LEFT JOIN schedules AS se on s.schedule_id = se.id
|
||||
WHERE shifts.`end` >= NOW()
|
||||
AND NOT s.shift_id IS NULL
|
||||
AND se.needed_from_shift_type = TRUE
|
||||
' . ($filter ? 'AND shifts.location_id IN (' . implode(',', $filter->getLocations()) . ')' : '') . '
|
||||
|
||||
UNION ALL
|
||||
|
||||
/* By location */
|
||||
SELECT
|
||||
(SELECT SUM(`count`) FROM `needed_angel_types` WHERE `needed_angel_types`.`location_id`=`shifts`.`location_id`' . ($filter ? ' AND needed_angel_types.angel_type_id IN (' . implode(',', $filter->getTypes()) . ')' : '') . ')
|
||||
* TIMESTAMPDIFF(MINUTE, `shifts`.`start`, `shifts`.`end`) / 60 AS `count`
|
||||
FROM `shifts`
|
||||
LEFT JOIN schedule_shift AS s on shifts.id = s.shift_id
|
||||
WHERE shifts.`end` >= NOW()
|
||||
LEFT JOIN schedules AS se on s.schedule_id = se.id
|
||||
WHERE shifts.`end` >= NOW()
|
||||
AND NOT s.shift_id IS NULL
|
||||
AND se.needed_from_shift_type = FALSE
|
||||
' . ($filter ? 'AND shifts.location_id IN (' . implode(',', $filter->getLocations()) . ')' : '') . '
|
||||
) AS `tmp`
|
||||
'
|
||||
|
@ -90,7 +107,8 @@ function stats_angels_needed_three_hours(ShiftsFilter $filter = null)
|
|||
AND `needed_angel_types`.`shift_id`=`shifts`.`id`
|
||||
' . ($filter ? 'AND needed_angel_types.angel_type_id IN (' . implode(',', $filter->getTypes()) . ')' : '') . '
|
||||
) - (
|
||||
SELECT COUNT(*) FROM `shift_entries`
|
||||
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 `shift_entries`.`shift_id`=`shifts`.`id`
|
||||
|
@ -107,6 +125,38 @@ function stats_angels_needed_three_hours(ShiftsFilter $filter = null)
|
|||
|
||||
UNION ALL
|
||||
|
||||
/* By shift type */
|
||||
SELECT
|
||||
GREATEST(0,
|
||||
(
|
||||
SELECT SUM(needed_angel_types.`count`)
|
||||
FROM `needed_angel_types`
|
||||
JOIN `angel_types` ON `angel_types`.`id`=`needed_angel_types`.`angel_type_id`
|
||||
WHERE `angel_types`.`show_on_dashboard`=TRUE
|
||||
AND `needed_angel_types`.`shift_type_id`=`shifts`.`shift_type_id`
|
||||
' . ($filter ? 'AND needed_angel_types.angel_type_id IN (' . implode(',', $filter->getTypes()) . ')' : '') . '
|
||||
) - (
|
||||
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 `shift_entries`.`shift_id`=`shifts`.`id`
|
||||
AND `freeloaded`=0
|
||||
' . ($filter ? 'AND shift_entries.angel_type_id IN (' . implode(',', $filter->getTypes()) . ')' : '') . '
|
||||
)
|
||||
)
|
||||
AS `count`
|
||||
FROM `shifts`
|
||||
LEFT JOIN schedule_shift AS s on shifts.id = s.shift_id
|
||||
LEFT JOIN schedules AS se on s.schedule_id = se.id
|
||||
WHERE shifts.`end` > NOW() AND shifts.`start` < ?
|
||||
AND NOT s.shift_id IS NULL
|
||||
AND se.needed_from_shift_type = TRUE
|
||||
' . ($filter ? 'AND shifts.location_id IN (' . implode(',', $filter->getLocations()) . ')' : '') . '
|
||||
|
||||
UNION ALL
|
||||
|
||||
/* By location */
|
||||
SELECT
|
||||
GREATEST(0,
|
||||
(
|
||||
|
@ -129,12 +179,15 @@ function stats_angels_needed_three_hours(ShiftsFilter $filter = null)
|
|||
AS `count`
|
||||
FROM `shifts`
|
||||
LEFT JOIN schedule_shift AS s on shifts.id = s.shift_id
|
||||
WHERE `end` > NOW() AND `start` < ?
|
||||
LEFT JOIN schedules AS se on s.schedule_id = se.id
|
||||
WHERE shifts.`end` > NOW() AND shifts.`start` < ?
|
||||
AND NOT s.shift_id IS NULL
|
||||
AND se.needed_from_shift_type = FALSE
|
||||
' . ($filter ? 'AND shifts.location_id IN (' . implode(',', $filter->getLocations()) . ')' : '') . '
|
||||
) AS `tmp`', [
|
||||
$in3hours,
|
||||
$in3hours,
|
||||
$in3hours,
|
||||
]);
|
||||
|
||||
return $result['count'] ?: '-';
|
||||
|
@ -189,6 +242,37 @@ function stats_angels_needed_for_nightshifts(ShiftsFilter $filter = null)
|
|||
|
||||
UNION ALL
|
||||
|
||||
/* By shift type */
|
||||
SELECT
|
||||
GREATEST(0,
|
||||
(
|
||||
SELECT SUM(needed_angel_types.`count`)
|
||||
FROM `needed_angel_types`
|
||||
JOIN `angel_types` ON `angel_types`.`id`=`needed_angel_types`.`angel_type_id`
|
||||
WHERE `angel_types`.`show_on_dashboard`=TRUE
|
||||
AND `needed_angel_types`.`shift_type_id`=`shifts`.`shift_type_id`
|
||||
' . ($filter ? 'AND angel_types.id IN (' . implode(',', $filter->getTypes()) . ')' : '') . '
|
||||
) - (
|
||||
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 `shift_entries`.`shift_id`=`shifts`.`id`
|
||||
AND shift_entries.`freeloaded`=0
|
||||
' . ($filter ? 'AND shift_entries.angel_type_id IN (' . implode(',', $filter->getTypes()) . ')' : '') . '
|
||||
)
|
||||
)
|
||||
AS `count`
|
||||
FROM `shifts`
|
||||
LEFT JOIN schedule_shift AS s on shifts.id = s.shift_id
|
||||
LEFT JOIN schedules AS se on s.schedule_id = se.id
|
||||
WHERE shifts.`end` > ? AND shifts.`start` < ?
|
||||
AND NOT s.shift_id IS NULL
|
||||
AND se.needed_from_shift_type = TRUE
|
||||
' . ($filter ? 'AND shifts.location_id IN (' . implode(',', $filter->getLocations()) . ')' : '') . '
|
||||
|
||||
UNION ALL
|
||||
|
||||
/* By location */
|
||||
SELECT
|
||||
GREATEST(0,
|
||||
(
|
||||
|
@ -203,21 +287,25 @@ function stats_angels_needed_for_nightshifts(ShiftsFilter $filter = null)
|
|||
JOIN `angel_types` ON `angel_types`.`id`=`shift_entries`.`angel_type_id`
|
||||
WHERE `angel_types`.`show_on_dashboard`=TRUE
|
||||
AND `shift_entries`.`shift_id`=`shifts`.`id`
|
||||
AND `freeloaded`=0
|
||||
AND shift_entries.`freeloaded`=0
|
||||
' . ($filter ? 'AND shift_entries.angel_type_id IN (' . implode(',', $filter->getTypes()) . ')' : '') . '
|
||||
)
|
||||
)
|
||||
AS `count`
|
||||
FROM `shifts`
|
||||
LEFT JOIN schedule_shift AS s on shifts.id = s.shift_id
|
||||
WHERE `end` > ? AND `start` < ?
|
||||
LEFT JOIN schedules AS se on s.schedule_id = se.id
|
||||
WHERE shifts.`end` > ? AND shifts.`start` < ?
|
||||
AND NOT s.shift_id IS NULL
|
||||
AND se.needed_from_shift_type = FALSE
|
||||
' . ($filter ? 'AND shifts.location_id IN (' . implode(',', $filter->getLocations()) . ')' : '') . '
|
||||
) AS `tmp`', [
|
||||
$night_start,
|
||||
$night_end,
|
||||
$night_start,
|
||||
$night_end,
|
||||
$night_start,
|
||||
$night_end,
|
||||
]);
|
||||
|
||||
return $result['count'] ?: '-';
|
||||
|
|
|
@ -171,7 +171,9 @@ function admin_shifts()
|
|||
}
|
||||
|
||||
if ($request->has('angelmode')) {
|
||||
if ($request->input('angelmode') == 'location') {
|
||||
if ($request->input('angelmode') == 'shift_type') {
|
||||
$angelmode = 'shift_type';
|
||||
} elseif ($request->input('angelmode') == 'location') {
|
||||
$angelmode = 'location';
|
||||
} elseif ($request->input('angelmode') == 'manually') {
|
||||
foreach ($types as $type) {
|
||||
|
@ -203,7 +205,11 @@ function admin_shifts()
|
|||
|
||||
// Alle Eingaben in Ordnung
|
||||
if ($valid) {
|
||||
if ($angelmode == 'location') {
|
||||
if ($angelmode == 'shift_type') {
|
||||
$needed_angel_types = NeededAngelType::whereShiftTypeId($shifttype_id)
|
||||
->pluck('count', 'angel_type_id')
|
||||
->toArray() + $needed_angel_types;
|
||||
} elseif ($angelmode == 'location') {
|
||||
$needed_angel_types = NeededAngelType::whereLocationId($lid)
|
||||
->pluck('count', 'angel_type_id')
|
||||
->toArray() + $needed_angel_types;
|
||||
|
@ -541,7 +547,13 @@ function admin_shifts()
|
|||
form_info(__('Needed angels')),
|
||||
form_radio(
|
||||
'angelmode',
|
||||
__('Take needed angels from location settings'),
|
||||
__('Copy needed angels from shift type settings'),
|
||||
$angelmode == 'shift_type',
|
||||
'shift_type'
|
||||
),
|
||||
form_radio(
|
||||
'angelmode',
|
||||
__('Copy needed angels from location settings'),
|
||||
$angelmode == 'location',
|
||||
'location'
|
||||
),
|
||||
|
|
|
@ -118,6 +118,7 @@ class ImportSchedule extends BaseController
|
|||
'name' => 'required',
|
||||
'url' => 'required',
|
||||
'shift_type' => 'required|int',
|
||||
'needed_from_shift_type' => 'optional|checked',
|
||||
'minutes_before' => 'int',
|
||||
'minutes_after' => 'int',
|
||||
]);
|
||||
|
@ -129,17 +130,19 @@ class ImportSchedule extends BaseController
|
|||
$schedule->name = $data['name'];
|
||||
$schedule->url = $data['url'];
|
||||
$schedule->shift_type = $data['shift_type'];
|
||||
$schedule->needed_from_shift_type = (bool) $data['needed_from_shift_type'];
|
||||
$schedule->minutes_before = $data['minutes_before'];
|
||||
$schedule->minutes_after = $data['minutes_after'];
|
||||
|
||||
$schedule->save();
|
||||
|
||||
$this->log->info(
|
||||
'Schedule {name}: Url {url}, Shift Type {shift_type}, minutes before/after {before}/{after}',
|
||||
'Schedule {name}: Url {url}, Shift Type {shift_type}, ({need}), minutes before/after {before}/{after}',
|
||||
[
|
||||
'name' => $schedule->name,
|
||||
'url' => $schedule->name,
|
||||
'shift_type' => $schedule->shift_type,
|
||||
'need' => $schedule->needed_from_shift_type ? 'from shift type' : 'from room',
|
||||
'before' => $schedule->minutes_before,
|
||||
'after' => $schedule->minutes_after,
|
||||
]
|
||||
|
@ -169,8 +172,8 @@ class ImportSchedule extends BaseController
|
|||
''
|
||||
);
|
||||
|
||||
$this->fireDeleteShiftEntryEvents($event);
|
||||
$this->deleteEvent($event);
|
||||
$this->fireDeleteShiftEntryEvents($event, $schedule);
|
||||
$this->deleteEvent($event, $schedule);
|
||||
}
|
||||
$schedule->delete();
|
||||
|
||||
|
@ -271,13 +274,14 @@ class ImportSchedule extends BaseController
|
|||
$shiftType,
|
||||
$locations
|
||||
->where('name', $event->getRoom()->getName())
|
||||
->first()
|
||||
->first(),
|
||||
$scheduleUrl
|
||||
);
|
||||
}
|
||||
|
||||
foreach ($deleteEvents as $event) {
|
||||
$this->fireDeleteShiftEntryEvents($event);
|
||||
$this->deleteEvent($event);
|
||||
$this->fireDeleteShiftEntryEvents($event, $scheduleUrl);
|
||||
$this->deleteEvent($event, $scheduleUrl);
|
||||
}
|
||||
|
||||
$scheduleUrl->touch();
|
||||
|
@ -296,7 +300,7 @@ class ImportSchedule extends BaseController
|
|||
$this->log('Created schedule location "{location}"', ['location' => $room->getName()]);
|
||||
}
|
||||
|
||||
protected function fireDeleteShiftEntryEvents(Event $event): void
|
||||
protected function fireDeleteShiftEntryEvents(Event $event, ScheduleUrl $schedule): void
|
||||
{
|
||||
$shiftEntries = $this->db
|
||||
->table('shift_entries')
|
||||
|
@ -310,6 +314,7 @@ class ImportSchedule extends BaseController
|
|||
->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())
|
||||
->where('schedule_shift.schedule_id', $schedule->id)
|
||||
->get();
|
||||
|
||||
foreach ($shiftEntries as $shiftEntry) {
|
||||
|
@ -359,13 +364,13 @@ class ImportSchedule extends BaseController
|
|||
);
|
||||
}
|
||||
|
||||
protected function updateEvent(Event $event, int $shiftTypeId, Location $location): void
|
||||
protected function updateEvent(Event $event, int $shiftTypeId, Location $location, ScheduleUrl $schedule): void
|
||||
{
|
||||
$user = auth()->user();
|
||||
$eventTimeZone = Carbon::now()->timezone;
|
||||
|
||||
/** @var ScheduleShift $scheduleShift */
|
||||
$scheduleShift = ScheduleShift::whereGuid($event->getGuid())->first();
|
||||
$scheduleShift = ScheduleShift::whereGuid($event->getGuid())->where('schedule_id', $schedule->id)->first();
|
||||
$shift = $scheduleShift->shift;
|
||||
$shift->title = $event->getTitle();
|
||||
$shift->shift_type_id = $shiftTypeId;
|
||||
|
@ -388,10 +393,10 @@ class ImportSchedule extends BaseController
|
|||
);
|
||||
}
|
||||
|
||||
protected function deleteEvent(Event $event): void
|
||||
protected function deleteEvent(Event $event, ScheduleUrl $schedule): void
|
||||
{
|
||||
/** @var ScheduleShift $scheduleShift */
|
||||
$scheduleShift = ScheduleShift::whereGuid($event->getGuid())->first();
|
||||
$scheduleShift = ScheduleShift::whereGuid($event->getGuid())->where('schedule_id', $schedule->id)->first();
|
||||
$shift = $scheduleShift->shift;
|
||||
$shift->delete();
|
||||
|
||||
|
@ -509,10 +514,10 @@ class ImportSchedule extends BaseController
|
|||
|
||||
$scheduleEventsGuidList = array_keys($scheduleEvents);
|
||||
$existingShifts = $this->getScheduleShiftsByGuid($scheduleUrl, $scheduleEventsGuidList);
|
||||
foreach ($existingShifts as $shift) {
|
||||
$guid = $shift->guid;
|
||||
foreach ($existingShifts as $scheduleShift) {
|
||||
$guid = $scheduleShift->guid;
|
||||
/** @var Shift $shift */
|
||||
$shift = Shift::with('location')->find($shift->shift_id);
|
||||
$shift = Shift::with('location')->find($scheduleShift->shift_id);
|
||||
$event = $scheduleEvents[$guid];
|
||||
$location = $locations->where('name', $event->getRoom()->getName())->first();
|
||||
|
||||
|
@ -535,8 +540,8 @@ class ImportSchedule extends BaseController
|
|||
}
|
||||
|
||||
$scheduleShifts = $this->getScheduleShiftsWhereNotGuid($scheduleUrl, $scheduleEventsGuidList);
|
||||
foreach ($scheduleShifts as $shift) {
|
||||
$event = $this->eventFromScheduleShift($shift);
|
||||
foreach ($scheduleShifts as $scheduleShift) {
|
||||
$event = $this->eventFromScheduleShift($scheduleShift);
|
||||
$deleteEvents[$event->getGuid()] = $event;
|
||||
}
|
||||
|
||||
|
@ -545,8 +550,7 @@ class ImportSchedule extends BaseController
|
|||
|
||||
protected function eventFromScheduleShift(ScheduleShift $scheduleShift): Event
|
||||
{
|
||||
/** @var Shift $shift */
|
||||
$shift = Shift::with('location')->find($scheduleShift->shift_id);
|
||||
$shift = $scheduleShift->shift;
|
||||
$duration = $shift->start->diff($shift->end);
|
||||
|
||||
return new Event(
|
||||
|
|
|
@ -126,7 +126,9 @@ function load_locations(bool $onlyWithActiveShifts = false)
|
|||
|
||||
$locationIdsFromShift = Shift::query()
|
||||
->leftJoin('needed_angel_types', 'shifts.id', 'needed_angel_types.shift_id')
|
||||
->whereNotNull('needed_angel_types.shift_id')
|
||||
->leftJoin('needed_angel_types AS nast', 'shifts.shift_type_id', 'nast.shift_type_id')
|
||||
->whereNotNull('needed_angel_types.id')
|
||||
->orWhereNotNull('nast.id')
|
||||
->select('shifts.location_id');
|
||||
|
||||
$locations->whereIn('id', $locationIdsFromAngelType)
|
||||
|
|
|
@ -722,8 +722,11 @@ msgstr "Schichtwechsel-Stunden"
|
|||
msgid "Create a shift over midnight."
|
||||
msgstr "Erstelle Schichten über Mitternacht"
|
||||
|
||||
msgid "Take needed angels from location settings"
|
||||
msgstr "Übernehme benötigte Engel von den Ort-Einstellungen"
|
||||
msgid "Copy needed angels from location settings"
|
||||
msgstr "Kopiere benötigte Engel von den Ort-Einstellungen"
|
||||
|
||||
msgid "Copy needed angels from shift type settings"
|
||||
msgstr "Kopiere benötigte Engel von den Schichttyp-Einstellungen"
|
||||
|
||||
msgid "The following angels are needed"
|
||||
msgstr "Die folgenden Engel werden benötigt"
|
||||
|
@ -1447,6 +1450,9 @@ msgstr "Programm URL (schedule.xml)"
|
|||
msgid "schedule.shift-type"
|
||||
msgstr "Schichttyp"
|
||||
|
||||
msgid "schedule.needed-from-shift-type"
|
||||
msgstr "Engeltypen vom Schichttyp laden (sonst vom Ort)"
|
||||
|
||||
msgid "schedule.minutes-before"
|
||||
msgstr "Minuten vor Talk beginn hinzufügen"
|
||||
|
||||
|
@ -1934,7 +1940,7 @@ msgid "location.map_url"
|
|||
msgstr "Karte"
|
||||
|
||||
msgid "location.required_angels"
|
||||
msgstr "Benötigte Engel"
|
||||
msgstr "Benötigte Engel (bei Fahrplan import)"
|
||||
|
||||
msgid "location.map_url.info"
|
||||
msgstr "Die Karte wird auf der Ort-Seite als iframe eingebettet."
|
||||
|
@ -1960,6 +1966,9 @@ msgstr "Schichttyp erstellen"
|
|||
msgid "shifttype.delete.title"
|
||||
msgstr "Schichttyp \"%s\" löschen"
|
||||
|
||||
msgid "shifttype.required_angels"
|
||||
msgstr "Benötigte Engel (bei Fahrplan import)"
|
||||
|
||||
msgid "event.day"
|
||||
msgstr "Tag %1$d"
|
||||
|
||||
|
|
|
@ -151,6 +151,9 @@ msgstr "Schedule URL (schedule.xml)"
|
|||
msgid "schedule.shift-type"
|
||||
msgstr "Shift type"
|
||||
|
||||
msgid "schedule.needed-from-shift-type"
|
||||
msgstr "Load angel types from shift type (else from location)"
|
||||
|
||||
msgid "schedule.minutes-before"
|
||||
msgstr "Add minutes before talk begins"
|
||||
|
||||
|
@ -664,7 +667,7 @@ msgid "location.map_url"
|
|||
msgstr "Map"
|
||||
|
||||
msgid "location.required_angels"
|
||||
msgstr "Required angels"
|
||||
msgstr "Required angels (on schedule import)"
|
||||
|
||||
msgid "location.map_url.info"
|
||||
msgstr "The map will be embedded on the location page as an iframe."
|
||||
|
@ -690,6 +693,9 @@ msgstr "Create shift type"
|
|||
msgid "shifttype.delete.title"
|
||||
msgstr "Delete shift type \"%s\""
|
||||
|
||||
msgid "shifttype.required_angels"
|
||||
msgstr "Required angels (on schedule import)"
|
||||
|
||||
msgid "event.day"
|
||||
msgstr "Day %1$d"
|
||||
|
||||
|
|
|
@ -34,6 +34,10 @@
|
|||
'selected': schedule ? schedule.shift_type : '',
|
||||
}) }}
|
||||
|
||||
{{ f.checkbox('needed_from_shift_type', __('schedule.needed-from-shift-type'), {
|
||||
'checked': schedule ? schedule.needed_from_shift_type : '',
|
||||
}) }}
|
||||
|
||||
{{ f.input('minutes_before', __('schedule.minutes-before'), {
|
||||
'type': 'number',
|
||||
'required': true,
|
||||
|
|
|
@ -23,6 +23,27 @@
|
|||
'info': __('form.markdown')
|
||||
}) }}
|
||||
</div>
|
||||
|
||||
<div class="col-lg-6">
|
||||
<h4>{{ __('shifttype.required_angels') }}</h4>
|
||||
{% for types in angel_types.chunk(3) %}
|
||||
<div class="row">
|
||||
{% for angel_type in types %}
|
||||
{% set needed = shifttype
|
||||
? shifttype.neededAngelTypes.where('angel_type_id', angel_type.id).first()
|
||||
: null %}
|
||||
{% set name = 'angel_type_' ~ angel_type.id %}
|
||||
<div class="col-md-4">
|
||||
{{ f.number(name, angel_type.name, {
|
||||
'value': f.formData(name, needed ? needed.count : 0),
|
||||
'min': 0,
|
||||
'step': 1,
|
||||
}) }}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-md-12">
|
||||
|
|
|
@ -11,7 +11,10 @@ use Engelsystem\Http\Redirector;
|
|||
use Engelsystem\Http\Request;
|
||||
use Engelsystem\Http\Response;
|
||||
use Engelsystem\Http\Validation\Validator;
|
||||
use Engelsystem\Models\AngelType;
|
||||
use Engelsystem\Models\Shifts\NeededAngelType;
|
||||
use Engelsystem\Models\Shifts\ShiftType;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
class ShiftTypesController extends BaseController
|
||||
|
@ -48,10 +51,15 @@ class ShiftTypesController extends BaseController
|
|||
$shiftTypeId = (int) $request->getAttribute('shift_type_id');
|
||||
|
||||
$shiftType = $this->shiftType->find($shiftTypeId);
|
||||
$angeltypes = AngelType::all()
|
||||
->sortBy('name');
|
||||
|
||||
return $this->response->withView(
|
||||
'admin/shifttypes/edit',
|
||||
['shifttype' => $shiftType]
|
||||
[
|
||||
'shifttype' => $shiftType,
|
||||
'angel_types' => $angeltypes,
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -77,12 +85,19 @@ class ShiftTypesController extends BaseController
|
|||
return $this->delete($request);
|
||||
}
|
||||
|
||||
/** @var Collection|AngelType[] $angelTypes */
|
||||
$angelTypes = AngelType::all();
|
||||
$validation = [];
|
||||
foreach ($angelTypes as $angelType) {
|
||||
$validation['angel_type_' . $angelType->id] = 'optional|int';
|
||||
}
|
||||
|
||||
$data = $this->validate(
|
||||
$request,
|
||||
[
|
||||
'name' => 'required',
|
||||
'description' => 'required|optional',
|
||||
]
|
||||
] + $validation
|
||||
);
|
||||
|
||||
if (ShiftType::whereName($data['name'])->where('id', '!=', $shiftType->id)->exists()) {
|
||||
|
@ -93,12 +108,33 @@ class ShiftTypesController extends BaseController
|
|||
$shiftType->description = $data['description'];
|
||||
|
||||
$shiftType->save();
|
||||
$shiftType->neededAngelTypes()->delete();
|
||||
|
||||
$angelsInfo = '';
|
||||
foreach ($angelTypes as $angelType) {
|
||||
$count = $data['angel_type_' . $angelType->id];
|
||||
if (!$count) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$neededAngelType = new NeededAngelType();
|
||||
|
||||
$neededAngelType->shiftType()->associate($shiftType);
|
||||
$neededAngelType->angelType()->associate($angelType);
|
||||
|
||||
$neededAngelType->count = $data['angel_type_' . $angelType->id];
|
||||
|
||||
$neededAngelType->save();
|
||||
|
||||
$angelsInfo .= sprintf(', %s: %s', $angelType->name, $count);
|
||||
}
|
||||
|
||||
$this->log->info(
|
||||
'Updated shift type "{name}": {description}',
|
||||
'Updated shift type "{name}": {description} {angels}',
|
||||
[
|
||||
'name' => $shiftType->name,
|
||||
'description' => $shiftType->description,
|
||||
'angels' => $angelsInfo,
|
||||
]
|
||||
);
|
||||
|
||||
|
|
|
@ -78,6 +78,10 @@ class ShiftsController extends BaseController
|
|||
$query->on('needed_angel_types.shift_id', '=', 'shifts.id')
|
||||
->whereNull('schedule_shift.shift_id');
|
||||
})
|
||||
->leftJoin('needed_angel_types AS nast', function (JoinClause $query): void {
|
||||
$query->on('nast.shift_type_id', '=', 'shifts.shift_type_id')
|
||||
->whereNotNull('schedule_shift.shift_id');
|
||||
})
|
||||
->leftJoin('needed_angel_types AS nas', function (JoinClause $query): void {
|
||||
$query->on('nas.location_id', '=', 'shifts.location_id')
|
||||
->whereNotNull('schedule_shift.shift_id');
|
||||
|
@ -88,6 +92,7 @@ class ShiftsController extends BaseController
|
|||
->where(function (EloquentBuilder $query) use ($angelTypes): void {
|
||||
$query
|
||||
->whereIn('needed_angel_types.angel_type_id', $angelTypes)
|
||||
->orWhereIn('nast.angel_type_id', $angelTypes)
|
||||
->orWhereIn('nas.angel_type_id', $angelTypes);
|
||||
})
|
||||
// Starts soon
|
||||
|
@ -98,7 +103,7 @@ class ShiftsController extends BaseController
|
|||
->from('shift_entries')
|
||||
->selectRaw('COUNT(*)')
|
||||
->where(fn(Builder $query) => $this->queryShiftEntries($query));
|
||||
}, '<', Shift::query()->raw('COALESCE(needed_angel_types.count, nas.count)'))
|
||||
}, '<', Shift::query()->raw('COALESCE(needed_angel_types.count, nast.count, nas.count)'))
|
||||
->limit(10)
|
||||
->orderBy('start');
|
||||
|
||||
|
|
|
@ -15,16 +15,19 @@ use Illuminate\Database\Query\Builder as QueryBuilder;
|
|||
* @property int $id
|
||||
* @property int|null $location_id
|
||||
* @property int|null $shift_id
|
||||
* @property int|null $shift_type_id
|
||||
* @property int $angel_type_id
|
||||
* @property int $count
|
||||
*
|
||||
* @property-read Location|null $location
|
||||
* @property-read Shift|null $shift
|
||||
* @property-read ShiftType|null $shiftType
|
||||
* @property-read AngelType $angelType
|
||||
*
|
||||
* @method static QueryBuilder|NeededAngelType[] whereId($value)
|
||||
* @method static QueryBuilder|NeededAngelType[] whereLocationId($value)
|
||||
* @method static QueryBuilder|NeededAngelType[] whereShiftId($value)
|
||||
* @method static QueryBuilder|NeededAngelType[] whereShiftTypeId($value)
|
||||
* @method static QueryBuilder|NeededAngelType[] whereAngelTypeId($value)
|
||||
* @method static QueryBuilder|NeededAngelType[] whereCount($value)
|
||||
*/
|
||||
|
@ -36,12 +39,14 @@ class NeededAngelType extends BaseModel
|
|||
protected $attributes = [ // phpcs:ignore
|
||||
'location_id' => null,
|
||||
'shift_id' => null,
|
||||
'shift_type_id' => null,
|
||||
];
|
||||
|
||||
/** @var array<string> */
|
||||
protected $fillable = [ // phpcs:ignore
|
||||
'location_id',
|
||||
'shift_id',
|
||||
'shift_type_id',
|
||||
'angel_type_id',
|
||||
'count',
|
||||
];
|
||||
|
@ -56,6 +61,11 @@ class NeededAngelType extends BaseModel
|
|||
return $this->belongsTo(Shift::class);
|
||||
}
|
||||
|
||||
public function shiftType(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(ShiftType::class);
|
||||
}
|
||||
|
||||
public function angelType(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(AngelType::class);
|
||||
|
|
|
@ -18,6 +18,7 @@ use Illuminate\Database\Query\Builder as QueryBuilder;
|
|||
* @property string $name
|
||||
* @property string $url
|
||||
* @property int $shift_type
|
||||
* @property bool $needed_from_shift_type
|
||||
* @property int $minutes_before
|
||||
* @property int $minutes_after
|
||||
* @property Carbon $created_at
|
||||
|
@ -31,6 +32,7 @@ use Illuminate\Database\Query\Builder as QueryBuilder;
|
|||
* @method static QueryBuilder|Schedule[] whereName($value)
|
||||
* @method static QueryBuilder|Schedule[] whereUrl($value)
|
||||
* @method static QueryBuilder|Schedule[] whereShiftType($value)
|
||||
* @method static QueryBuilder|Schedule[] whereNeededFromShiftType($value)
|
||||
* @method static QueryBuilder|Schedule[] whereMinutesBefore($value)
|
||||
* @method static QueryBuilder|Schedule[] whereMinutesAfter($value)
|
||||
* @method static QueryBuilder|Schedule[] whereCreatedAt($value)
|
||||
|
@ -46,6 +48,7 @@ class Schedule extends BaseModel
|
|||
/** @var array<string> */
|
||||
protected $casts = [ // phpcs:ignore
|
||||
'shift_type' => 'integer',
|
||||
'needed_from_shift_type' => 'boolean',
|
||||
'minutes_before' => 'integer',
|
||||
'minutes_after' => 'integer',
|
||||
];
|
||||
|
@ -55,6 +58,7 @@ class Schedule extends BaseModel
|
|||
'name',
|
||||
'url',
|
||||
'shift_type',
|
||||
'needed_from_shift_type',
|
||||
'minutes_before',
|
||||
'minutes_after',
|
||||
];
|
||||
|
|
|
@ -15,6 +15,7 @@ use Illuminate\Database\Query\Builder as QueryBuilder;
|
|||
* @property string $name
|
||||
* @property string $description
|
||||
*
|
||||
* @property-read Collection|NeededAngelType[] $neededAngelTypes
|
||||
* @property-read Collection|Schedule[] $schedules
|
||||
* @property-read Collection|Shift[] $shifts
|
||||
*
|
||||
|
@ -32,6 +33,11 @@ class ShiftType extends BaseModel
|
|||
'description',
|
||||
];
|
||||
|
||||
public function neededAngelTypes(): HasMany
|
||||
{
|
||||
return $this->hasMany(NeededAngelType::class);
|
||||
}
|
||||
|
||||
public function schedules(): HasMany
|
||||
{
|
||||
return $this->hasMany(Schedule::class, 'shift_type');
|
||||
|
|
|
@ -11,6 +11,7 @@ use Engelsystem\Http\Exceptions\ValidationException;
|
|||
use Engelsystem\Http\Redirector;
|
||||
use Engelsystem\Http\Request;
|
||||
use Engelsystem\Http\Validation\Validator;
|
||||
use Engelsystem\Models\AngelType;
|
||||
use Engelsystem\Models\Shifts\ShiftEntry;
|
||||
use Engelsystem\Models\Shifts\ShiftType;
|
||||
use Engelsystem\Models\Shifts\Shift;
|
||||
|
@ -18,7 +19,7 @@ use Engelsystem\Models\User\User;
|
|||
use Engelsystem\Test\Unit\Controllers\ControllerTest;
|
||||
use PHPUnit\Framework\MockObject\MockObject;
|
||||
|
||||
class ShiftTypeControllerTest extends ControllerTest
|
||||
class ShiftTypesControllerTest extends ControllerTest
|
||||
{
|
||||
protected Redirector|MockObject $redirect;
|
||||
|
||||
|
@ -82,6 +83,7 @@ class ShiftTypeControllerTest extends ControllerTest
|
|||
$this->assertEquals($shifttype->id, $data['shifttype']?->id);
|
||||
$this->assertNotEmpty($data['shifttype']?->name);
|
||||
$this->assertNotEmpty($data['shifttype']?->description);
|
||||
$this->assertNotNull($data['angel_types']);
|
||||
return $this->response;
|
||||
});
|
||||
|
||||
|
@ -104,6 +106,7 @@ class ShiftTypeControllerTest extends ControllerTest
|
|||
$this->assertEquals('admin/shifttypes/edit', $view);
|
||||
$this->assertArrayHasKey('shifttype', $data);
|
||||
$this->assertNull($data['shifttype']);
|
||||
$this->assertNotNull($data['angel_types']);
|
||||
return $this->response;
|
||||
});
|
||||
|
||||
|
@ -115,6 +118,8 @@ class ShiftTypeControllerTest extends ControllerTest
|
|||
*/
|
||||
public function testSave(): void
|
||||
{
|
||||
$angelType = AngelType::factory(2)->create()->first();
|
||||
|
||||
/** @var ShiftTypesController $controller */
|
||||
$controller = $this->app->make(ShiftTypesController::class);
|
||||
$controller->setValidator(new Validator());
|
||||
|
@ -124,6 +129,8 @@ class ShiftTypeControllerTest extends ControllerTest
|
|||
$this->request = $this->request->withParsedBody([
|
||||
'name' => 'Test shift type',
|
||||
'description' => 'Something',
|
||||
'angel_type_' . $angelType->id => 3,
|
||||
'angel_type_' . $angelType->id + 1 => 0,
|
||||
]);
|
||||
|
||||
$controller->save($this->request);
|
||||
|
@ -131,6 +138,7 @@ class ShiftTypeControllerTest extends ControllerTest
|
|||
$this->assertTrue($this->log->hasInfoThatContains('Updated shift type'));
|
||||
$this->assertHasNotification('shifttype.edit.success');
|
||||
$this->assertCount(1, ShiftType::whereName('Test shift type')->get());
|
||||
$this->assertCount(1, ShiftType::first()->neededAngelTypes);
|
||||
}
|
||||
|
||||
/**
|
|
@ -8,6 +8,7 @@ use Engelsystem\Models\AngelType;
|
|||
use Engelsystem\Models\Location;
|
||||
use Engelsystem\Models\Shifts\NeededAngelType;
|
||||
use Engelsystem\Models\Shifts\Shift;
|
||||
use Engelsystem\Models\Shifts\ShiftType;
|
||||
use Engelsystem\Test\Unit\Models\ModelTest;
|
||||
|
||||
class NeededAngelTypeTest extends ModelTest
|
||||
|
@ -15,6 +16,7 @@ class NeededAngelTypeTest extends ModelTest
|
|||
/**
|
||||
* @covers \Engelsystem\Models\Shifts\NeededAngelType::location
|
||||
* @covers \Engelsystem\Models\Shifts\NeededAngelType::shift
|
||||
* @covers \Engelsystem\Models\Shifts\NeededAngelType::shiftType
|
||||
* @covers \Engelsystem\Models\Shifts\NeededAngelType::angelType
|
||||
*/
|
||||
public function testShift(): void
|
||||
|
@ -23,12 +25,15 @@ class NeededAngelTypeTest extends ModelTest
|
|||
$location = Location::factory()->create();
|
||||
/** @var Shift $shift */
|
||||
$shift = Shift::factory()->create();
|
||||
/** @var ShiftType $shiftType */
|
||||
$shiftType = ShiftType::factory()->create();
|
||||
/** @var AngelType $angelType */
|
||||
$angelType = AngelType::factory()->create();
|
||||
|
||||
$model = new NeededAngelType();
|
||||
$model->location()->associate($location);
|
||||
$model->shift()->associate($shift);
|
||||
$model->shiftType()->associate($shiftType);
|
||||
$model->angelType()->associate($angelType);
|
||||
$model->count = 3;
|
||||
$model->save();
|
||||
|
@ -36,6 +41,7 @@ class NeededAngelTypeTest extends ModelTest
|
|||
$model = NeededAngelType::find(1);
|
||||
$this->assertEquals($location->id, $model->location->id);
|
||||
$this->assertEquals($shift->id, $model->shift->id);
|
||||
$this->assertEquals($shiftType->id, $model->shiftType->id);
|
||||
$this->assertEquals($angelType->id, $model->angelType->id);
|
||||
$this->assertEquals(3, $model->count);
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ class ScheduleTest extends ModelTest
|
|||
'url' => 'https://foo.bar/schedule.xml',
|
||||
'name' => 'Testing',
|
||||
'shift_type' => 1,
|
||||
'needed_from_shift_type' => false,
|
||||
'minutes_before' => 10,
|
||||
'minutes_after' => 10,
|
||||
];
|
||||
|
|
|
@ -4,6 +4,7 @@ declare(strict_types=1);
|
|||
|
||||
namespace Engelsystem\Test\Unit\Models\Shifts;
|
||||
|
||||
use Engelsystem\Models\Shifts\NeededAngelType;
|
||||
use Engelsystem\Models\Shifts\Schedule;
|
||||
use Engelsystem\Models\Shifts\Shift;
|
||||
use Engelsystem\Models\Shifts\ShiftType;
|
||||
|
@ -11,6 +12,19 @@ use Engelsystem\Test\Unit\Models\ModelTest;
|
|||
|
||||
class ShiftTypeTest extends ModelTest
|
||||
{
|
||||
/**
|
||||
* @covers \Engelsystem\Models\Shifts\ShiftType::neededAngelTypes
|
||||
*/
|
||||
public function testNeededAngelTypes(): void
|
||||
{
|
||||
$shiftType = new ShiftType(['name' => 'Another type', 'description' => '']);
|
||||
$shiftType->save();
|
||||
|
||||
NeededAngelType::factory()->create(['shift_type_id' => 1]);
|
||||
|
||||
$this->assertCount(1, ShiftType::find(1)->neededAngelTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers \Engelsystem\Models\Shifts\ShiftType::schedules
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue