Added room selection for schedules

This commit is contained in:
Igor Scheller 2023-12-27 03:18:05 +01:00 committed by msquare
parent 197d0d724a
commit caa699ff05
9 changed files with 185 additions and 41 deletions

View File

@ -0,0 +1,52 @@
<?php
declare(strict_types=1);
namespace Engelsystem\Migrations;
use Engelsystem\Database\Migration\Migration;
use Illuminate\Database\Schema\Blueprint;
class CreateScheduleLocationsTable extends Migration
{
use ChangesReferences;
use Reference;
/**
* Creates the new table
*/
public function up(): void
{
$connection = $this->schema->getConnection();
$this->schema->create('schedule_locations', function (Blueprint $table): void {
$table->increments('id');
$this->references($table, 'schedules');
$this->references($table, 'locations');
$table->index(['schedule_id', 'location_id']);
});
$scheduleLocations = $connection
->table('schedule_shift')
->select(['schedules.id AS schedule_id', 'locations.id AS location_id'])
->leftJoin('schedules', 'schedules.id', 'schedule_shift.schedule_id')
->leftJoin('shifts', 'shifts.id', 'schedule_shift.shift_id')
->leftJoin('locations', 'locations.id', 'shifts.location_id')
->groupBy(['schedules.id', 'locations.id'])
->get();
foreach ($scheduleLocations as $scheduleLocation) {
$connection->table('schedule_locations')
->insert((array)$scheduleLocation);
}
}
/**
* Drops the table
*/
public function down(): void
{
$this->schema->drop('schedule_locations');
}
}

View File

@ -92,13 +92,14 @@ class ImportSchedule extends BaseController
{ {
$scheduleId = $request->getAttribute('schedule_id'); // optional $scheduleId = $request->getAttribute('schedule_id'); // optional
$schedule = ScheduleUrl::find($scheduleId); $schedule = ScheduleUrl::findOrFail($scheduleId);
return $this->response->withView( return $this->response->withView(
'admin/schedule/edit.twig', 'admin/schedule/edit.twig',
[ [
'schedule' => $schedule, 'schedule' => $schedule,
'shift_types' => ShiftType::all()->pluck('name', 'id'), 'shift_types' => ShiftType::all()->sortBy('name')->pluck('name', 'id'),
'locations' => Location::all()->sortBy('name')->pluck('name', 'id'),
] ]
); );
} }
@ -114,6 +115,12 @@ class ImportSchedule extends BaseController
return $this->delete($schedule); return $this->delete($schedule);
} }
$locationsList = Location::all()->pluck('id');
$locationsValidation = [];
foreach ($locationsList as $id) {
$locationsValidation['location_' . $id] = 'optional|checked';
}
$data = $this->validate($request, [ $data = $this->validate($request, [
'name' => 'required', 'name' => 'required',
'url' => 'required', 'url' => 'required',
@ -121,7 +128,7 @@ class ImportSchedule extends BaseController
'needed_from_shift_type' => 'optional|checked', 'needed_from_shift_type' => 'optional|checked',
'minutes_before' => 'int', 'minutes_before' => 'int',
'minutes_after' => 'int', 'minutes_after' => 'int',
]); ] + $locationsValidation);
if (!ShiftType::find($data['shift_type'])) { if (!ShiftType::find($data['shift_type'])) {
throw new ErrorException('schedule.import.invalid-shift-type'); throw new ErrorException('schedule.import.invalid-shift-type');
@ -135,9 +142,22 @@ class ImportSchedule extends BaseController
$schedule->minutes_after = $data['minutes_after']; $schedule->minutes_after = $data['minutes_after'];
$schedule->save(); $schedule->save();
$schedule->activeLocations()->detach();
$for = new Collection();
foreach ($locationsList as $id) {
if (!$data['location_' . $id]) {
continue;
}
$location = Location::find($id);
$schedule->activeLocations()->attach($location);
$for[] = $location->name;
}
$this->log->info( $this->log->info(
'Schedule {name}: Url {url}, Shift Type {shift_type}, ({need}), minutes before/after {before}/{after}', 'Schedule {name}: Url {url}, Shift Type {shift_type}, ({need}), '
. 'minutes before/after {before}/{after}, for: {locations}',
[ [
'name' => $schedule->name, 'name' => $schedule->name,
'url' => $schedule->name, 'url' => $schedule->name,
@ -145,6 +165,7 @@ class ImportSchedule extends BaseController
'need' => $schedule->needed_from_shift_type ? 'from shift type' : 'from room', 'need' => $schedule->needed_from_shift_type ? 'from shift type' : 'from room',
'before' => $schedule->minutes_before, 'before' => $schedule->minutes_before,
'after' => $schedule->minutes_after, 'after' => $schedule->minutes_after,
'locations' => $for->implode(', '),
] ]
); );
@ -509,6 +530,10 @@ class ImportSchedule extends BaseController
foreach ($schedule->getDay() as $day) { foreach ($schedule->getDay() as $day) {
foreach ($day->getRoom() as $room) { foreach ($day->getRoom() as $room) {
if (!$scheduleUrl->activeLocations->where('name', $room->getName())->count()) {
continue;
}
foreach ($room->getEvent() as $event) { foreach ($room->getEvent() as $event) {
$scheduleEvents[$event->getGuid()] = $event; $scheduleEvents[$event->getGuid()] = $event;

View File

@ -1441,6 +1441,9 @@ msgstr "Minuten vor Talk beginn hinzufügen"
msgid "schedule.minutes-after" msgid "schedule.minutes-after"
msgstr "Minuten nach Talk ende hinzufügen" msgstr "Minuten nach Talk ende hinzufügen"
msgid "schedule.for_locations"
msgstr "Für Orte"
msgid "schedule.import.locations.add" msgid "schedule.import.locations.add"
msgstr "Neue Orte" msgstr "Neue Orte"

View File

@ -163,6 +163,9 @@ msgstr "Add minutes before talk begins"
msgid "schedule.minutes-after" msgid "schedule.minutes-after"
msgstr "Add minutes after talk ends" msgstr "Add minutes after talk ends"
msgid "schedule.for_locations"
msgstr "For locations"
msgid "schedule.import.request_error" msgid "schedule.import.request_error"
msgstr "Unable to load schedule." msgstr "Unable to load schedule."

View File

@ -12,50 +12,63 @@
{% block row_content %} {% block row_content %}
{% if schedule and schedule.updated_at %} {% if schedule and schedule.updated_at %}
<div class="col-md-12"> <div class="col-md-12">
<p>{{ __('schedule.last_update', [schedule.updated_at.format(__('general.datetime'))]) }}</p> <p>{{ __('schedule.last_update', [schedule.updated_at.format(__('general.datetime'))]) }}</p>
</div> </div>
{% endif %} {% endif %}
<form method="post"> <form method="post">
{{ csrf() }} {{ csrf() }}
<div class="col-lg-12"> <div class="row">
{{ f.input('name', __('schedule.name'), { <div class="col-md-6">
'required': true, {{ f.input('name', __('schedule.name'), {
'value': schedule ? schedule.name : '', 'required': true,
}) }} 'value': schedule ? schedule.name : '',
{{ f.input('url', __('schedule.url'), {
'type': 'url',
'required': true,
'value': schedule ? schedule.url : ''
}) }}
{{ f.select('shift_type', __('schedule.shift-type'), shift_types|default([]), {
'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,
'value': schedule ? schedule.minutes_before : 15
}) }}
{{ f.input('minutes_after', __('schedule.minutes-after'), {
'type': 'number',
'required': true,
'value': schedule ? schedule.minutes_after : 15
}) }}
{{ f.save(__('form.save')) }}
{% if schedule %}
{{ f.delete(__('form.delete'), {
'confirm_title': __('schedule.delete.title', [schedule.shifts|length])
}) }} }) }}
{% endif %} {{ f.input('url', __('schedule.url'), {
'type': 'url',
'required': true,
'value': schedule ? schedule.url : ''
}) }}
{{ f.select('shift_type', __('schedule.shift-type'), shift_types|default([]), {
'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,
'value': schedule ? schedule.minutes_before : 15
}) }}
{{ f.input('minutes_after', __('schedule.minutes-after'), {
'type': 'number',
'required': true,
'value': schedule ? schedule.minutes_after : 15
}) }}
{{ f.save(__('form.save')) }}
{% if schedule %}
{{ f.delete(__('form.delete'), {
'confirm_title': __('schedule.delete.title', [schedule.shifts|length])
}) }}
{% endif %}
</div>
<div class="col-md-6">
<h3>{{ __('schedule.for_locations') }}</h3>
<div class="row">
{% for id,name in locations %}
<div class="col-md-3">
{{ f.checkbox('location_' ~ id, name, {'checked': id in schedule.activeLocations.pluck('id')}) }}
</div>
{% endfor %}
</div>
</div>
</div> </div>
</form> </form>
{% endblock %} {% endblock %}

View File

@ -6,9 +6,11 @@ namespace Engelsystem\Models;
use Carbon\Carbon; use Carbon\Carbon;
use Engelsystem\Models\Shifts\NeededAngelType; use Engelsystem\Models\Shifts\NeededAngelType;
use Engelsystem\Models\Shifts\Schedule;
use Engelsystem\Models\Shifts\Shift; use Engelsystem\Models\Shifts\Shift;
use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Query\Builder as QueryBuilder; use Illuminate\Database\Query\Builder as QueryBuilder;
@ -21,6 +23,7 @@ use Illuminate\Database\Query\Builder as QueryBuilder;
* @property Carbon|null $created_at * @property Carbon|null $created_at
* @property Carbon|null $updated_at * @property Carbon|null $updated_at
* *
* @property-read Collection|Schedule[] $activeForSchedules
* @property-read Collection|NeededAngelType[] $neededAngelTypes * @property-read Collection|NeededAngelType[] $neededAngelTypes
* @property-read Collection|Shift[] $shifts * @property-read Collection|Shift[] $shifts
* *
@ -54,6 +57,11 @@ class Location extends BaseModel
'description', 'description',
]; ];
public function activeForSchedules(): BelongsToMany
{
return $this->belongsToMany(Schedule::class, 'schedule_locations');
}
public function neededAngelTypes(): HasMany public function neededAngelTypes(): HasMany
{ {
return $this->hasMany(NeededAngelType::class); return $this->hasMany(NeededAngelType::class);

View File

@ -6,9 +6,11 @@ namespace Engelsystem\Models\Shifts;
use Carbon\Carbon; use Carbon\Carbon;
use Engelsystem\Models\BaseModel; use Engelsystem\Models\BaseModel;
use Engelsystem\Models\Location;
use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo; use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany; use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasManyThrough; use Illuminate\Database\Eloquent\Relations\HasManyThrough;
use Illuminate\Database\Query\Builder as QueryBuilder; use Illuminate\Database\Query\Builder as QueryBuilder;
@ -24,6 +26,7 @@ use Illuminate\Database\Query\Builder as QueryBuilder;
* @property Carbon $created_at * @property Carbon $created_at
* @property Carbon $updated_at * @property Carbon $updated_at
* *
* @property-read QueryBuilder|Location[] $activeLocations
* @property-read QueryBuilder|Collection|Shift[] $shifts * @property-read QueryBuilder|Collection|Shift[] $shifts
* @property-read QueryBuilder|Collection|ScheduleShift[] $scheduleShifts * @property-read QueryBuilder|Collection|ScheduleShift[] $scheduleShifts
* @property-read QueryBuilder|ShiftType $shiftType * @property-read QueryBuilder|ShiftType $shiftType
@ -63,6 +66,11 @@ class Schedule extends BaseModel
'minutes_after', 'minutes_after',
]; ];
public function activeLocations(): BelongsToMany
{
return $this->belongsToMany(Location::class, 'schedule_locations');
}
public function scheduleShifts(): HasMany public function scheduleShifts(): HasMany
{ {
return $this->hasMany(ScheduleShift::class); return $this->hasMany(ScheduleShift::class);

View File

@ -6,11 +6,27 @@ namespace Engelsystem\Test\Unit\Models;
use Engelsystem\Models\Location; use Engelsystem\Models\Location;
use Engelsystem\Models\Shifts\NeededAngelType; use Engelsystem\Models\Shifts\NeededAngelType;
use Engelsystem\Models\Shifts\Schedule;
use Engelsystem\Models\Shifts\Shift; use Engelsystem\Models\Shifts\Shift;
use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Collection;
class LocationTest extends ModelTest class LocationTest extends ModelTest
{ {
/**
* @covers \Engelsystem\Models\Location::activeForSchedules
*/
public function testActiveForSchedules(): void
{
$location = new Location(['name' => 'Test location']);
$location->save();
$schedule = Schedule::factory()->create();
$location->activeForSchedules()->attach($schedule);
$location = Location::find($location->id);
$this->assertCount(1, $location->activeForSchedules);
}
/** /**
* @covers \Engelsystem\Models\Location::shifts * @covers \Engelsystem\Models\Location::shifts
*/ */

View File

@ -4,6 +4,7 @@ declare(strict_types=1);
namespace Engelsystem\Test\Unit\Models\Shifts; namespace Engelsystem\Test\Unit\Models\Shifts;
use Engelsystem\Models\Location;
use Engelsystem\Models\Shifts\Schedule; use Engelsystem\Models\Shifts\Schedule;
use Engelsystem\Models\Shifts\ScheduleShift; use Engelsystem\Models\Shifts\ScheduleShift;
use Engelsystem\Models\Shifts\Shift; use Engelsystem\Models\Shifts\Shift;
@ -22,6 +23,21 @@ class ScheduleTest extends ModelTest
'minutes_after' => 10, 'minutes_after' => 10,
]; ];
/**
* @covers \Engelsystem\Models\Shifts\Schedule::activeLocations
*/
public function testActiveLocations(): void
{
$schedule = new Schedule($this->data);
$schedule->save();
$location = Location::factory()->create();
$schedule->activeLocations()->attach($location);
$schedule = Schedule::find($schedule->id);
$this->assertCount(1, $schedule->activeLocations);
}
/** /**
* @covers \Engelsystem\Models\Shifts\Schedule::scheduleShifts * @covers \Engelsystem\Models\Shifts\Schedule::scheduleShifts
*/ */