Deploy Ladill Care / deploy (push) Successful in 47s
Cashiers collect via Billing only; strip POS from demo staff grants and StaffUx/launcher so the suite hub no longer offers POS for that role. Co-authored-by: Cursor <cursoragent@cursor.com>
169 lines
5.5 KiB
PHP
169 lines
5.5 KiB
PHP
<?php
|
|
|
|
namespace App\Services\Care;
|
|
|
|
use App\Models\Member;
|
|
|
|
class CarePermissions
|
|
{
|
|
/**
|
|
* Role abilities.
|
|
*
|
|
* Lab catalog pricing uses `lab.catalog.manage` (admins only via `*`).
|
|
* Lab technicians keep `lab.manage` for queue / sample / process / results —
|
|
* not catalog CRUD or price edits.
|
|
*
|
|
* @var array<string, list<string>>
|
|
*/
|
|
protected array $roleAbilities = [
|
|
'super_admin' => ['*'],
|
|
'hospital_admin' => ['*'],
|
|
'receptionist' => [
|
|
'dashboard.view', 'patients.view', 'patients.manage',
|
|
'appointments.view', 'appointments.manage', 'queue.manage',
|
|
'service_queues.console',
|
|
],
|
|
'doctor' => [
|
|
'dashboard.view', 'patients.view', 'appointments.view',
|
|
'consultations.view', 'consultations.manage',
|
|
'investigations.request', 'prescriptions.manage',
|
|
'lab.view', 'lab.results.view',
|
|
'assessments.view', 'assessments.capture', 'assessments.manage',
|
|
'pathways.manage',
|
|
'service_queues.console',
|
|
],
|
|
'nurse' => [
|
|
'dashboard.view', 'patients.view', 'appointments.view',
|
|
'consultations.view', 'vitals.manage',
|
|
'service_queues.console',
|
|
'assessments.view', 'assessments.capture',
|
|
],
|
|
'lab_technician' => [
|
|
'dashboard.view', 'patients.view', 'lab.view', 'lab.manage',
|
|
'service_queues.console',
|
|
],
|
|
'pharmacist' => [
|
|
'dashboard.view', 'patients.view', 'prescriptions.view', 'prescriptions.dispense',
|
|
'pharmacy.view', 'pharmacy.manage',
|
|
'service_queues.console',
|
|
],
|
|
// Cashiers run the Billing desk (bills / payments). They do not get
|
|
// Ladill POS app access — see filterAllowedAppSlugs() / DemoWorld.
|
|
'cashier' => [
|
|
'dashboard.view', 'patients.view', 'bills.view', 'bills.manage', 'payments.manage',
|
|
'service_queues.console',
|
|
],
|
|
'accountant' => [
|
|
'dashboard.view', 'bills.view', 'reports.finance.view', 'reports.finance.export',
|
|
'audit.view', 'audit.export',
|
|
],
|
|
];
|
|
|
|
/** @var list<string> */
|
|
protected array $adminAbilities = [
|
|
'admin.branches.view', 'admin.branches.manage',
|
|
'admin.departments.view', 'admin.departments.manage',
|
|
'admin.practitioners.view', 'admin.practitioners.manage',
|
|
'admin.members.view', 'admin.members.manage',
|
|
'settings.view', 'settings.manage',
|
|
'lab.catalog.manage',
|
|
'devices.view', 'devices.manage',
|
|
'displays.view', 'displays.manage',
|
|
'audit.view', 'audit.export',
|
|
];
|
|
|
|
public function can(?Member $member, string $ability): bool
|
|
{
|
|
if ($member === null) {
|
|
return false;
|
|
}
|
|
|
|
$abilities = $this->roleAbilities[$member->role] ?? [];
|
|
|
|
if (in_array('*', $abilities, true)) {
|
|
return true;
|
|
}
|
|
|
|
return in_array($ability, $abilities, true);
|
|
}
|
|
|
|
public function isAdmin(?Member $member): bool
|
|
{
|
|
return $member !== null && in_array($member->role, ['super_admin', 'hospital_admin'], true);
|
|
}
|
|
|
|
/**
|
|
* Floor care: queues, specialty clinics, lab/pharmacy counters.
|
|
* Facility admins manage settings/staff — they do not staff waiting lines.
|
|
*/
|
|
public function handlesFloorCare(?Member $member): bool
|
|
{
|
|
if ($member === null || $this->isAdmin($member)) {
|
|
return false;
|
|
}
|
|
|
|
return in_array($member->role, [
|
|
'doctor',
|
|
'nurse',
|
|
'lab_technician',
|
|
'pharmacist',
|
|
'receptionist',
|
|
'cashier',
|
|
], true);
|
|
}
|
|
|
|
/**
|
|
* Dedicated patient-flow board (GP Queue home / call-next board).
|
|
* Doctors only — nurses, reception, pharmacy, and other floor roles use
|
|
* specialty module lists and service queues instead.
|
|
* Facility admins manage settings/staff and do not staff this board.
|
|
*/
|
|
public function canAccessPatientQueue(?Member $member): bool
|
|
{
|
|
return $member !== null && $member->role === 'doctor';
|
|
}
|
|
|
|
/**
|
|
* Care cashiers collect via Billing, not Ladill POS. Strip POS from
|
|
* Identity app grants so the suite launcher hides it.
|
|
*
|
|
* @param list<string>|null $slugs Null = unrestricted owner access.
|
|
* @return list<string>|null
|
|
*/
|
|
public function filterAllowedAppSlugs(?Member $member, ?array $slugs): ?array
|
|
{
|
|
if ($slugs === null || $member?->role !== 'cashier') {
|
|
return $slugs;
|
|
}
|
|
|
|
return array_values(array_filter(
|
|
array_map('strval', $slugs),
|
|
fn (string $slug) => $slug !== 'pos',
|
|
));
|
|
}
|
|
|
|
/**
|
|
* @param array{full_access?: bool, apps?: list<string>, show_hub?: bool, show_billing?: bool} $access
|
|
* @return array{full_access?: bool, apps?: list<string>, show_hub?: bool, show_billing?: bool}
|
|
*/
|
|
public function filterStaffAppAccess(?Member $member, array $access): array
|
|
{
|
|
if ($member?->role !== 'cashier') {
|
|
return $access;
|
|
}
|
|
|
|
$apps = $this->filterAllowedAppSlugs($member, array_values(array_map(
|
|
'strval',
|
|
(array) ($access['apps'] ?? []),
|
|
))) ?? [];
|
|
|
|
$access['apps'] = $apps;
|
|
|
|
if (empty($access['full_access']) && count($apps) <= 1) {
|
|
$access['show_hub'] = false;
|
|
}
|
|
|
|
return $access;
|
|
}
|
|
}
|