Add shift templates, unit duty roster grid, and Nursing Services hub.
Deploy Ladill Care / deploy (push) Successful in 1m0s
Deploy Ladill Care / deploy (push) Successful in 1m0s
Phase 3 staff management: real shift entities, week roster linked to temporary assignments, and a nursing ops module surface (registry, today’s allocation, unit shortcuts). Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Care;
|
||||
|
||||
use App\Http\Controllers\Controller;
|
||||
use App\Http\Controllers\Care\Concerns\ScopesToAccount;
|
||||
use App\Models\CareUnit;
|
||||
use App\Models\Member;
|
||||
use App\Models\RosterEntry;
|
||||
use App\Models\Shift;
|
||||
use App\Services\Care\CarePermissions;
|
||||
use App\Services\Care\RosterService;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\RedirectResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\View\View;
|
||||
|
||||
class RosterController extends Controller
|
||||
{
|
||||
use ScopesToAccount;
|
||||
|
||||
public function show(Request $request, CareUnit $careUnit, RosterService $roster): View
|
||||
{
|
||||
$this->authorizeAbility($request, 'nursing.roster.view');
|
||||
$this->authorizeOwner($request, $careUnit);
|
||||
abort_unless((int) $careUnit->organization_id === (int) $this->organization($request)->id, 404);
|
||||
|
||||
$weekStart = $request->filled('week')
|
||||
? Carbon::parse($request->input('week'))->startOfWeek(Carbon::MONDAY)
|
||||
: now()->startOfWeek(Carbon::MONDAY);
|
||||
|
||||
$grid = $roster->unitWeekGrid($careUnit, $this->ownerRef($request), $weekStart);
|
||||
$canManage = app(CarePermissions::class)->can($this->member($request), 'nursing.roster.manage');
|
||||
|
||||
return view('care.nursing.roster', [
|
||||
'unit' => $careUnit->load('department.branch'),
|
||||
'weekStart' => $grid['week_start'],
|
||||
'days' => $grid['days'],
|
||||
'shifts' => $grid['shifts'],
|
||||
'cells' => $grid['cells'],
|
||||
'members' => $grid['members'],
|
||||
'memberLabels' => $grid['member_labels'],
|
||||
'canManage' => $canManage,
|
||||
'statuses' => config('care.roster_entry_statuses'),
|
||||
'prevWeek' => $grid['week_start']->copy()->subWeek()->toDateString(),
|
||||
'nextWeek' => $grid['week_start']->copy()->addWeek()->toDateString(),
|
||||
]);
|
||||
}
|
||||
|
||||
public function store(Request $request, CareUnit $careUnit, RosterService $roster): RedirectResponse
|
||||
{
|
||||
$this->authorizeAbility($request, 'nursing.roster.manage');
|
||||
$this->authorizeOwner($request, $careUnit);
|
||||
$organization = $this->organization($request);
|
||||
abort_unless((int) $careUnit->organization_id === (int) $organization->id, 404);
|
||||
|
||||
$validated = $request->validate([
|
||||
'shift_id' => ['required', 'integer', 'exists:care_shifts,id'],
|
||||
'member_id' => ['required', 'integer', 'exists:care_members,id'],
|
||||
'duty_date' => ['required', 'date'],
|
||||
'notes' => ['nullable', 'string', 'max:1000'],
|
||||
]);
|
||||
|
||||
$shift = Shift::owned($this->ownerRef($request))
|
||||
->where('organization_id', $organization->id)
|
||||
->findOrFail($validated['shift_id']);
|
||||
$member = Member::owned($this->ownerRef($request))
|
||||
->where('organization_id', $organization->id)
|
||||
->findOrFail($validated['member_id']);
|
||||
|
||||
$roster->assign(
|
||||
$careUnit,
|
||||
$shift,
|
||||
$member,
|
||||
$validated['duty_date'],
|
||||
$this->ownerRef($request),
|
||||
$this->actorRef($request),
|
||||
$validated['notes'] ?? null,
|
||||
);
|
||||
|
||||
return redirect()
|
||||
->route('care.care-units.roster', [
|
||||
'careUnit' => $careUnit,
|
||||
'week' => Carbon::parse($validated['duty_date'])->startOfWeek(Carbon::MONDAY)->toDateString(),
|
||||
])
|
||||
->with('success', 'Staff added to roster.');
|
||||
}
|
||||
|
||||
public function destroy(Request $request, CareUnit $careUnit, RosterEntry $rosterEntry, RosterService $roster): RedirectResponse
|
||||
{
|
||||
$this->authorizeAbility($request, 'nursing.roster.manage');
|
||||
$this->authorizeOwner($request, $careUnit);
|
||||
$this->authorizeOwner($request, $rosterEntry);
|
||||
abort_unless((int) $rosterEntry->care_unit_id === (int) $careUnit->id, 404);
|
||||
|
||||
$week = $rosterEntry->duty_date->copy()->startOfWeek(Carbon::MONDAY)->toDateString();
|
||||
$roster->cancel($rosterEntry, $this->ownerRef($request), $this->actorRef($request));
|
||||
|
||||
return redirect()
|
||||
->route('care.care-units.roster', ['careUnit' => $careUnit, 'week' => $week])
|
||||
->with('success', 'Roster entry cancelled.');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user