Restrict care unit and department setup to admins.
Deploy Ladill Care / deploy (push) Successful in 48s

Nurses keep Nursing Services for clinical work but can no longer browse or create structural units and departments.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
isaacclad
2026-07-20 11:33:38 +00:00
co-authored by Cursor
parent 7c32b34715
commit 82a2b1a9a7
7 changed files with 54 additions and 9 deletions
@@ -20,9 +20,11 @@ class CareUnitController extends Controller
public function index(Request $request): View
{
$this->authorizeCareUnitView($request);
$this->authorizeAbility($request, 'admin.departments.view');
$organization = $this->organization($request);
$owner = $this->ownerRef($request);
$member = $this->member($request);
$permissions = app(CarePermissions::class);
$units = CareUnit::owned($owner)
->where('organization_id', $organization->id)
@@ -43,6 +45,7 @@ class CareUnitController extends Controller
'organization' => $organization,
'kinds' => config('care.care_unit_kinds'),
'heroStats' => $heroStats,
'canManage' => $permissions->can($member, 'admin.departments.manage'),
]);
}
@@ -7,6 +7,7 @@ use App\Http\Controllers\Care\Concerns\ScopesToAccount;
use App\Models\Branch;
use App\Models\Department;
use App\Services\Care\AuditLogger;
use App\Services\Care\CarePermissions;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\View\View;
@@ -20,6 +21,8 @@ class DepartmentController extends Controller
$this->authorizeAbility($request, 'admin.departments.view');
$organization = $this->organization($request);
$owner = $this->ownerRef($request);
$member = $this->member($request);
$permissions = app(CarePermissions::class);
$departments = Department::owned($owner)
->whereHas('branch', fn ($q) => $q->where('organization_id', $organization->id))
@@ -38,6 +41,7 @@ class DepartmentController extends Controller
'organization' => $organization,
'types' => config('care.department_types'),
'heroStats' => $heroStats,
'canManage' => $permissions->can($member, 'admin.departments.manage'),
]);
}
@@ -11,7 +11,9 @@
['value' => number_format($heroStats['active']), 'label' => 'Active'],
]">
<x-slot name="actions">
@if ($canManage ?? false)
<a href="{{ route('care.care-units.create') }}" class="btn-primary">Add care unit</a>
@endif
</x-slot>
</x-care.page-hero>
@@ -11,7 +11,9 @@
]">
<x-slot name="actions">
<a href="{{ route('care.care-units.index') }}" class="btn-secondary">Care units</a>
@if ($canManage ?? false)
<a href="{{ route('care.departments.create') }}" class="btn-primary">Add department</a>
@endif
</x-slot>
</x-care.page-hero>
@@ -27,7 +29,9 @@
<td class="px-4 py-3">{{ $types[$department->type] ?? $department->type }}</td>
<td class="px-4 py-3">{{ $department->branch?->name }}</td>
<td class="px-4 py-3 text-right">
@if ($canManage ?? false)
<a href="{{ route('care.departments.edit', $department) }}" class="text-sky-600">Edit</a>
@endif
</td>
</tr>
@empty
@@ -127,7 +127,7 @@
</div>
</div>
@empty
<p class="text-sm text-slate-500 sm:col-span-2 lg:col-span-3">No care units yet create units under Care units.</p>
<p class="text-sm text-slate-500 sm:col-span-2 lg:col-span-3">No care units yet ask an administrator to set them up.</p>
@endforelse
</div>
</div>
@@ -132,9 +132,6 @@
if ($permissions->can($member, 'admin.departments.view')) {
$adminNav[] = ['name' => 'Care units', 'route' => route('care.care-units.index'), 'active' => request()->routeIs('care.care-units.*'),
'icon' => '<path stroke-linecap="round" stroke-linejoin="round" d="M2.25 21h19.5m-18-18v18m10.5-18v18m6-13.5V21M6.75 6.75h.75m-.75 3h.75m-.75 3h.75m3-6h.75m-.75 3h.75m-.75 3h.75M6.75 21v-3.375c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125V21M3 3h12m-.75 4.5H21m-3.75 3h.008v.008h-.008v-.008Zm0 3h.008v.008h-.008v-.008Zm0 3h.008v.008h-.008v-.008Z" />'];
} elseif ($permissions->can($member, 'nursing.services.view') && $permissions->can($member, 'inpatient.placement.view')) {
$adminNav[] = ['name' => 'Care units', 'route' => route('care.care-units.index'), 'active' => request()->routeIs('care.care-units.*'),
'icon' => '<path stroke-linecap="round" stroke-linejoin="round" d="M2.25 21h19.5m-18-18v18m10.5-18v18m6-13.5V21M6.75 6.75h.75m-.75 3h.75m-.75 3h.75m3-6h.75m-.75 3h.75m-.75 3h.75M6.75 21v-3.375c0-.621.504-1.125 1.125-1.125h2.25c.621 0 1.125.504 1.125 1.125V21M3 3h12m-.75 4.5H21m-3.75 3h.008v.008h-.008v-.008Zm0 3h.008v.008h-.008v-.008Zm0 3h.008v.008h-.008v-.008Z" />'];
}
if ($permissions->can($member, 'nursing.services.view')) {
$adminNav[] = ['name' => 'Nursing Services', 'route' => route('care.nursing.services'), 'active' => request()->routeIs('care.nursing.*') || request()->routeIs('care.shifts.*'),
@@ -156,15 +156,50 @@ class CareMyShiftsAndNavPermissionsTest extends TestCase
public function test_nurse_still_gets_nursing_services_access(): void
{
$user = User::create([
'public_id' => 'nurse-hub',
'name' => 'Ward Nurse',
'email' => 'nurse-hub@example.com',
]);
$member = Member::create([
'owner_ref' => $this->owner->public_id,
'organization_id' => $this->organization->id,
'user_ref' => 'nurse-hub',
'user_ref' => $user->public_id,
'role' => 'nurse',
'branch_id' => $this->branch->id,
]);
$permissions = app(CarePermissions::class);
$this->assertTrue($permissions->can($member, 'nursing.services.view'));
$this->assertTrue($permissions->can($member, 'inpatient.placement.view'));
$this->assertFalse($permissions->can($member, 'admin.departments.view'));
$this->assertFalse($permissions->can($member, 'admin.departments.manage'));
$this->actingAs($user)
->get(route('care.care-units.index'))
->assertForbidden();
$this->actingAs($user)
->get(route('care.care-units.create'))
->assertForbidden();
$this->actingAs($user)
->get(route('care.departments.index'))
->assertForbidden();
$this->actingAs($user)
->get(route('care.departments.create'))
->assertForbidden();
$this->actingAs($user)
->get(route('care.nursing.services'))
->assertOk();
$this->actingAs($user)
->get(route('care.dashboard'))
->assertOk()
->assertDontSee('>Care units<', false)
->assertDontSee('>Departments<', false)
->assertSee('>Nursing Services<', false);
}
}