Remove Care cashier access to Ladill POS.
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>
This commit is contained in:
isaacclad
2026-07-18 23:47:07 +00:00
co-authored by Cursor
parent 4ad3a8a901
commit f82964b2a0
5 changed files with 164 additions and 9 deletions
@@ -286,6 +286,9 @@ class SsoLoginController extends Controller
{
try {
$access = $identity->appAccess($user->ownerRef(), $intended);
$member = app(\App\Services\Care\OrganizationResolver::class)->memberFor($user);
$access = app(\App\Services\Care\CarePermissions::class)
->filterStaffAppAccess($member, $access);
\App\Support\StaffUx::remember($access);
return $access['url'] !== '' ? $access['url'] : $intended;
+34 -7
View File
@@ -74,16 +74,43 @@ class AppServiceProvider extends ServiceProvider
View::composer(['partials.launcher', 'partials.topbar-desktop-widgets', 'components.app-layout'], function () {
$user = auth()->user();
if (! $user || session()->has(\App\Support\StaffUx::SESSION_KEY)) {
if (! $user) {
return;
}
try {
$access = app(\App\Services\Identity\IdentityTeamClient::class)
->appAccess($user->ownerRef());
\App\Support\StaffUx::remember($access);
} catch (\Throwable) {
// Leave fail-open defaults until Identity is available.
$member = app(\App\Services\Care\OrganizationResolver::class)->memberFor($user);
$permissions = app(\App\Services\Care\CarePermissions::class);
if (! session()->has(\App\Support\StaffUx::SESSION_KEY)) {
try {
$access = app(\App\Services\Identity\IdentityTeamClient::class)
->appAccess($user->ownerRef());
\App\Support\StaffUx::remember(
$permissions->filterStaffAppAccess($member, $access)
);
} catch (\Throwable) {
// Leave fail-open defaults until Identity is available.
}
return;
}
// Stale Identity grants may still list POS — strip for Care cashiers.
$cached = session(\App\Support\StaffUx::SESSION_KEY);
if (! is_array($cached) || ! empty($cached['full_access'])) {
return;
}
$filtered = $permissions->filterStaffAppAccess($member, [
'full_access' => false,
'apps' => array_values(array_map('strval', (array) ($cached['apps'] ?? []))),
'show_hub' => (bool) ($cached['show_hub'] ?? false),
'show_billing' => (bool) ($cached['show_billing'] ?? false),
]);
if ($filtered['apps'] !== array_values(array_map('strval', (array) ($cached['apps'] ?? [])))
|| (bool) ($filtered['show_hub'] ?? false) !== (bool) ($cached['show_hub'] ?? false)) {
\App\Support\StaffUx::remember($filtered);
}
});
}
+45
View File
@@ -47,6 +47,8 @@ class CarePermissions
'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',
@@ -120,4 +122,47 @@ class CarePermissions
{
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;
}
}
+20 -2
View File
@@ -286,9 +286,18 @@ final class DemoWorld
'key' => 'cashier',
'email' => 'demo-pro-cashier@ladill.com',
'name' => 'Kojo Cashier (Pro)',
'apps' => ['care', 'pos'],
// Care cashiers collect via Billing — not Ladill POS.
'apps' => ['care'],
'roles' => [
'care' => 'cashier',
],
],
[
'key' => 'pos_cashier',
'email' => 'demo-pro-pos-cashier@ladill.com',
'name' => 'Kofi POS Cashier (Pro)',
'apps' => ['pos'],
'roles' => [
'pos' => 'cashier',
],
],
@@ -365,9 +374,18 @@ final class DemoWorld
'key' => 'cashier',
'email' => 'demo-enterprise-cashier@ladill.com',
'name' => 'Kojo Cashier',
'apps' => ['care', 'pos'],
// Care cashiers collect via Billing — not Ladill POS.
'apps' => ['care'],
'roles' => [
'care' => 'cashier',
],
],
[
'key' => 'pos_cashier',
'email' => 'demo-enterprise-pos-cashier@ladill.com',
'name' => 'Kofi POS Cashier',
'apps' => ['pos'],
'roles' => [
'pos' => 'cashier',
],
],