API: Show needed/added users by angeltype in shifts
This commit is contained in:
parent
ea93e27a9d
commit
ef3bd7c319
|
@ -167,10 +167,6 @@ components:
|
|||
format: date-time
|
||||
description: DateTime in ISO-8601 format
|
||||
example: 2023-05-13T16:00:00.000000Z23
|
||||
entries:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/ShiftEntry'
|
||||
room:
|
||||
$ref: '#/components/schemas/Room'
|
||||
shift_type:
|
||||
|
@ -187,6 +183,11 @@ components:
|
|||
format: date-time
|
||||
description: DateTime in ISO-8601 format
|
||||
example: 2023-05-13T23:00:00.000000Z
|
||||
entries:
|
||||
type: array
|
||||
description: Can be empty (for example on Schedule import of unused room)
|
||||
items:
|
||||
$ref: '#/components/schemas/ShiftEntry'
|
||||
url:
|
||||
type: string
|
||||
example: https://example.com/shifts/42
|
||||
|
@ -196,22 +197,31 @@ components:
|
|||
- description
|
||||
- start
|
||||
- end
|
||||
- entries
|
||||
- room
|
||||
- shift_type
|
||||
- created_at
|
||||
- updated_at
|
||||
- entries
|
||||
- url
|
||||
ShiftEntry:
|
||||
type: object
|
||||
properties:
|
||||
user:
|
||||
$ref: '#/components/schemas/User'
|
||||
users:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/User'
|
||||
type:
|
||||
$ref: '#/components/schemas/AngelType'
|
||||
needs:
|
||||
type: integer
|
||||
description: |
|
||||
Number of users needed for the shift.
|
||||
Can be more than users count when not full, less when overbooked or 0 when additional users have been added.
|
||||
example: 3
|
||||
required:
|
||||
- user
|
||||
- users
|
||||
- type
|
||||
- needs
|
||||
ShiftType:
|
||||
type: object
|
||||
properties:
|
||||
|
|
|
@ -7,6 +7,9 @@ namespace Engelsystem\Controllers\Api;
|
|||
use Engelsystem\Http\Request;
|
||||
use Engelsystem\Http\Response;
|
||||
use Engelsystem\Models\Room;
|
||||
use Engelsystem\Models\Shifts\NeededAngelType;
|
||||
use Engelsystem\Models\Shifts\Shift;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
|
||||
class ShiftsController extends ApiController
|
||||
{
|
||||
|
@ -15,40 +18,55 @@ class ShiftsController extends ApiController
|
|||
$roomId = (int) $request->getAttribute('room_id');
|
||||
/** @var Room $room */
|
||||
$room = Room::findOrFail($roomId);
|
||||
/** @var Shift[]|Collection $shifts */
|
||||
$shifts = $room->shifts()
|
||||
->with([
|
||||
'neededAngelTypes.angelType',
|
||||
'room',
|
||||
'shiftEntries.angelType',
|
||||
'shiftEntries.user.contact',
|
||||
'shiftEntries.user.personalData',
|
||||
'shiftType',
|
||||
])
|
||||
->orderBy('start')
|
||||
->get();
|
||||
$shiftEntries = [];
|
||||
|
||||
$shiftEntries = [];
|
||||
// Blob of not-optimized mediocre pseudo-serialization
|
||||
foreach ($shifts as $shift) {
|
||||
$entries = [];
|
||||
foreach ($shift->shiftEntries as $entry) {
|
||||
$user = $entry->user;
|
||||
$userData = [
|
||||
'id' => $user->id,
|
||||
'name' => $user->name,
|
||||
'first_name' => $user->personalData->first_name,
|
||||
'last_name' => $user->personalData->last_name,
|
||||
'pronoun' => $user->personalData->pronoun,
|
||||
'contact' => $user->contact->only(['dect', 'mobile']),
|
||||
'url' => $this->url->to('/users', ['action' => 'view', 'user_id' => $user->id]),
|
||||
];
|
||||
// Get all needed/used angel types
|
||||
$neededAngelTypes = $this->getNeededAngelTypes($shift);
|
||||
|
||||
$angelTypeData = $entry->angelType->only(['id', 'name']);
|
||||
$entries = new Collection();
|
||||
foreach ($neededAngelTypes as $neededAngelType) {
|
||||
$users = [];
|
||||
foreach ($neededAngelType->users ?? [] as $user) {
|
||||
$users[] = [
|
||||
'id' => $user->id,
|
||||
'name' => $user->name,
|
||||
'first_name' => $user->personalData->first_name,
|
||||
'last_name' => $user->personalData->last_name,
|
||||
'pronoun' => $user->personalData->pronoun,
|
||||
'contact' => $user->contact->only(['dect', 'mobile']),
|
||||
'url' => $this->url->to('/users', ['action' => 'view', 'user_id' => $user->id]),
|
||||
];
|
||||
}
|
||||
|
||||
// Skip empty entries
|
||||
if ($neededAngelType->count <= 0 && empty($users)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$angelTypeData = $neededAngelType->angelType->only(['id', 'name', 'description']);
|
||||
$angelTypeData['url'] = $this->url->to(
|
||||
'/angeltypes',
|
||||
['action' => 'view', 'angeltype_id' => $entry->angelType->id]
|
||||
['action' => 'view', 'angeltype_id' => $neededAngelType->angelType->id]
|
||||
);
|
||||
|
||||
$entries[] = [
|
||||
'user' => $userData,
|
||||
'users' => $users,
|
||||
'type' => $angelTypeData,
|
||||
'needs' => $neededAngelType->count,
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -61,11 +79,11 @@ class ShiftsController extends ApiController
|
|||
'description' => $shift->description,
|
||||
'start' => $shift->start,
|
||||
'end' => $shift->end,
|
||||
'entries' => $entries,
|
||||
'room' => $roomData,
|
||||
'shift_type' => $shift->shiftType->only(['id', 'name', 'description']),
|
||||
'created_at' => $shift->created_at,
|
||||
'updated_at' => $shift->updated_at,
|
||||
'entries' => $entries,
|
||||
'url' => $this->url->to('/shifts', ['action' => 'view', 'shift_id' => $shift->id]),
|
||||
];
|
||||
}
|
||||
|
@ -74,4 +92,49 @@ class ShiftsController extends ApiController
|
|||
return $this->response
|
||||
->withContent(json_encode($data));
|
||||
}
|
||||
|
||||
/**
|
||||
* Collect all needed angeltypes
|
||||
*/
|
||||
protected function getNeededAngelTypes(Shift $shift): Collection
|
||||
{
|
||||
// From shift
|
||||
$neededAngelTypes = $shift->neededAngelTypes;
|
||||
|
||||
// Add from room
|
||||
foreach ($shift->room->neededAngelTypes as $neededAngelType) {
|
||||
/** @var NeededAngelType $existingNeededAngelType */
|
||||
$existingNeededAngelType = $neededAngelTypes
|
||||
->where('angel_type_id', $neededAngelType->angel_type_id)
|
||||
->first();
|
||||
if (!$existingNeededAngelType) {
|
||||
$neededAngelTypes[] = clone $neededAngelType;
|
||||
continue;
|
||||
}
|
||||
|
||||
$existingNeededAngelType->room_id = $shift->room->id;
|
||||
$existingNeededAngelType->count += $neededAngelType->count;
|
||||
}
|
||||
|
||||
// Add needed angeltypes from additionally added users
|
||||
foreach ($shift->shiftEntries as $entry) {
|
||||
$neededAngelType = $neededAngelTypes->where('angel_type_id', $entry->angelType->id)->first();
|
||||
if (!$neededAngelType) {
|
||||
$neededAngelType = new NeededAngelType([
|
||||
'shift_id' => $shift->id,
|
||||
'angel_type_id' => $entry->angelType->id,
|
||||
'count' => 0,
|
||||
]);
|
||||
$neededAngelTypes[] = $neededAngelType;
|
||||
}
|
||||
|
||||
// Add users to entries
|
||||
$neededAngelType->users = isset($neededAngelType->users)
|
||||
? $neededAngelType->users
|
||||
: new Collection();
|
||||
$neededAngelType->users[] = $entry->user;
|
||||
}
|
||||
|
||||
return $neededAngelTypes;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,16 +8,19 @@ use Engelsystem\Controllers\Api\ShiftsController;
|
|||
use Engelsystem\Http\Request;
|
||||
use Engelsystem\Http\Response;
|
||||
use Engelsystem\Models\Room;
|
||||
use Engelsystem\Models\Shifts\NeededAngelType;
|
||||
use Engelsystem\Models\Shifts\Shift;
|
||||
use Engelsystem\Models\Shifts\ShiftEntry;
|
||||
use Engelsystem\Models\User\Contact;
|
||||
use Engelsystem\Models\User\PersonalData;
|
||||
use Engelsystem\Models\User\User;
|
||||
use Illuminate\Database\Eloquent\Collection;
|
||||
|
||||
class ShiftsControllerTest extends ApiBaseControllerTest
|
||||
{
|
||||
/**
|
||||
* @covers \Engelsystem\Controllers\Api\ShiftsController::entriesByRoom
|
||||
* @covers \Engelsystem\Controllers\Api\ShiftsController::getNeededAngelTypes
|
||||
*/
|
||||
public function testEntriesByRoom(): void
|
||||
{
|
||||
|
@ -26,9 +29,42 @@ class ShiftsControllerTest extends ApiBaseControllerTest
|
|||
/** @var Room $room */
|
||||
$room = Room::factory()->create();
|
||||
|
||||
Shift::factory(3)
|
||||
->has(ShiftEntry::factory(2), 'shiftEntries')
|
||||
// Shifts
|
||||
/** @var Collection|Shift[] $shifts */
|
||||
$shifts = Shift::factory(2)
|
||||
->create(['room_id' => $room->id]);
|
||||
$shiftA = $shifts[0];
|
||||
|
||||
// "Empty" entry to be skipped
|
||||
NeededAngelType::factory(1)->create(['room_id' => null, 'shift_id' => $shiftA->id, 'count' => 0]);
|
||||
|
||||
// Needed entry by shift
|
||||
/** @var NeededAngelType $byShift */
|
||||
$byShift = NeededAngelType::factory(2)
|
||||
->create(['room_id' => null, 'shift_id' => $shiftA->id, 'count' => 2])
|
||||
->first();
|
||||
|
||||
// Needed entry by room
|
||||
/** @var NeededAngelType $byRoom */
|
||||
$byRoom = NeededAngelType::factory(1)
|
||||
->create(['room_id' => $room->id, 'shift_id' => null, 'count' => 3])
|
||||
->first();
|
||||
|
||||
// Added by both
|
||||
NeededAngelType::factory(1)
|
||||
->create([
|
||||
'room_id' => $room->id, 'shift_id' => null, 'angel_type_id' => $byShift->angel_type_id, 'count' => 3,
|
||||
])
|
||||
->first();
|
||||
|
||||
// By shift
|
||||
ShiftEntry::factory(2)->create(['shift_id' => $shiftA->id, 'angel_type_id' => $byShift->angel_type_id]);
|
||||
|
||||
// By room
|
||||
ShiftEntry::factory(1)->create(['shift_id' => $shiftA->id, 'angel_type_id' => $byRoom->angel_type_id]);
|
||||
|
||||
// Additional (not required by shift nor room)
|
||||
ShiftEntry::factory(1)->create(['shift_id' => $shiftA->id]);
|
||||
|
||||
foreach (User::all() as $user) {
|
||||
// Generate user data
|
||||
|
@ -50,6 +86,6 @@ class ShiftsControllerTest extends ApiBaseControllerTest
|
|||
|
||||
$data = json_decode($response->getContent(), true);
|
||||
$this->assertArrayHasKey('data', $data);
|
||||
$this->assertCount(3, $data['data']);
|
||||
$this->assertCount(2, $data['data']);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue