Fix nurse onboarding redirects and specialty Documents 404s.
Deploy Ladill Care / deploy (push) Successful in 36s
Deploy Ladill Care / deploy (push) Successful in 36s
Resolve staff memberships by invite/demo email as well as public_id so nurses stay on their employer org; block staff from owner onboarding; keep Documents viewable with module access while upload stays manage-gated. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -26,6 +26,10 @@ class OnboardingController extends Controller
|
||||
return redirect()->route('care.dashboard');
|
||||
}
|
||||
|
||||
if (! $this->organizations->canCompleteOnboarding($request->user())) {
|
||||
abort(403, 'Your facility setup is incomplete. Ask an administrator to finish onboarding.');
|
||||
}
|
||||
|
||||
return view('care.onboarding.show', [
|
||||
'user' => $request->user(),
|
||||
'timezones' => timezone_identifiers_list(),
|
||||
@@ -41,6 +45,10 @@ class OnboardingController extends Controller
|
||||
return redirect()->route('care.dashboard');
|
||||
}
|
||||
|
||||
if (! $this->organizations->canCompleteOnboarding($request->user())) {
|
||||
abort(403, 'Your facility setup is incomplete. Ask an administrator to finish onboarding.');
|
||||
}
|
||||
|
||||
$categoryKeys = array_keys($this->workflows->categories());
|
||||
$templateKeys = array_keys($this->workflows->templates());
|
||||
|
||||
|
||||
@@ -347,6 +347,7 @@ class SpecialtyModuleController extends Controller
|
||||
|
||||
$organization = $this->organization($request);
|
||||
$member = $this->member($request);
|
||||
// Viewing docs is workspace GET (memberCanAccess / memberCanView). Upload needs manage.
|
||||
abort_unless($modules->memberCanAccess($organization, $member, $module), 403);
|
||||
abort_unless($modules->memberCanManage($organization, $member, $module), 403);
|
||||
abort_unless($visit->organization_id === $organization->id, 404);
|
||||
|
||||
@@ -25,6 +25,11 @@ class EnsureOrganizationSetup
|
||||
}
|
||||
|
||||
if (! $this->organizations->isOnboarded($user)) {
|
||||
// Staff already attached to a tenant must not see owner onboarding.
|
||||
if ($this->organizations->membershipFor($user)) {
|
||||
abort(403, 'Your facility setup is incomplete. Ask an administrator to finish onboarding.');
|
||||
}
|
||||
|
||||
return redirect()->route('care.onboarding.show');
|
||||
}
|
||||
|
||||
|
||||
@@ -670,17 +670,54 @@ class DemoTenantSeeder
|
||||
$branch = $branches[$index % count($branches)];
|
||||
}
|
||||
|
||||
Member::query()->updateOrCreate(
|
||||
[
|
||||
'organization_id' => $organization->id,
|
||||
'user_ref' => strtolower($staff['email']),
|
||||
],
|
||||
[
|
||||
$email = strtolower((string) $staff['email']);
|
||||
// Prefer remapped public_id when the staff user already exists locally,
|
||||
// so reseeds do not orphan SSO sessions keyed by public_id.
|
||||
$publicId = User::query()
|
||||
->whereRaw('LOWER(email) = ?', [$email])
|
||||
->value('public_id');
|
||||
$userRef = is_string($publicId) && $publicId !== '' ? $publicId : $email;
|
||||
|
||||
$existing = Member::query()
|
||||
->where('organization_id', $organization->id)
|
||||
->where(function ($query) use ($email, $publicId) {
|
||||
$query->where('user_ref', $email);
|
||||
if (is_string($publicId) && $publicId !== '') {
|
||||
$query->orWhere('user_ref', $publicId);
|
||||
}
|
||||
})
|
||||
->orderByRaw('CASE WHEN user_ref = ? THEN 0 ELSE 1 END', [$userRef])
|
||||
->first();
|
||||
|
||||
if ($existing) {
|
||||
$existing->forceFill([
|
||||
'user_ref' => $userRef,
|
||||
'owner_ref' => $ownerRef,
|
||||
'role' => $role,
|
||||
'branch_id' => $role === 'hospital_admin' ? null : $branch?->id,
|
||||
],
|
||||
);
|
||||
])->save();
|
||||
|
||||
Member::query()
|
||||
->where('organization_id', $organization->id)
|
||||
->where('id', '!=', $existing->id)
|
||||
->where(function ($query) use ($email, $publicId) {
|
||||
$query->where('user_ref', $email);
|
||||
if (is_string($publicId) && $publicId !== '') {
|
||||
$query->orWhere('user_ref', $publicId);
|
||||
}
|
||||
})
|
||||
->delete();
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
Member::query()->create([
|
||||
'organization_id' => $organization->id,
|
||||
'user_ref' => $userRef,
|
||||
'owner_ref' => $ownerRef,
|
||||
'role' => $role,
|
||||
'branch_id' => $role === 'hospital_admin' ? null : $branch?->id,
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -17,9 +17,7 @@ class OrganizationResolver
|
||||
{
|
||||
public function resolveForUser(User $user): ?Organization
|
||||
{
|
||||
$ref = $user->ownerRef();
|
||||
|
||||
$member = Member::where('user_ref', $ref)->first();
|
||||
$member = $this->membershipFor($user);
|
||||
if ($member) {
|
||||
$organization = Organization::query()->find($member->organization_id);
|
||||
if ($organization) {
|
||||
@@ -27,7 +25,7 @@ class OrganizationResolver
|
||||
}
|
||||
}
|
||||
|
||||
return Organization::owned($ref)->first();
|
||||
return Organization::owned($user->ownerRef())->first();
|
||||
}
|
||||
|
||||
public function forUser(User $user): Organization
|
||||
@@ -44,6 +42,40 @@ class OrganizationResolver
|
||||
&& (bool) data_get($organization->settings, 'onboarded', false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Any Care membership for this user (public_id or invite/demo email key).
|
||||
* Remaps email-keyed rows to public_id when found so staff stay linked after SSO.
|
||||
*/
|
||||
public function membershipFor(User $user): ?Member
|
||||
{
|
||||
$member = Member::query()->where('user_ref', $user->ownerRef())->first();
|
||||
if ($member) {
|
||||
return $member;
|
||||
}
|
||||
|
||||
$email = strtolower(trim((string) $user->email));
|
||||
if ($email === '' || $email === $user->ownerRef()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$member = Member::query()->where('user_ref', $email)->first();
|
||||
|
||||
return $member ? $this->remapMemberUserRef($member, $user) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* True when the user may run owner onboarding (create a facility).
|
||||
* Staff already attached to a tenant must not create a second org.
|
||||
*/
|
||||
public function canCompleteOnboarding(User $user): bool
|
||||
{
|
||||
if ($this->membershipFor($user)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return ! $this->isOnboarded($user);
|
||||
}
|
||||
|
||||
public function memberFor(User $user, ?Organization $organization = null): ?Member
|
||||
{
|
||||
$organization ??= $this->resolveForUser($user);
|
||||
@@ -51,9 +83,52 @@ class OrganizationResolver
|
||||
return null;
|
||||
}
|
||||
|
||||
return Member::where('organization_id', $organization->id)
|
||||
$member = Member::query()
|
||||
->where('organization_id', $organization->id)
|
||||
->where('user_ref', $user->ownerRef())
|
||||
->first();
|
||||
if ($member) {
|
||||
return $member;
|
||||
}
|
||||
|
||||
$email = strtolower(trim((string) $user->email));
|
||||
if ($email === '') {
|
||||
return null;
|
||||
}
|
||||
|
||||
$member = Member::query()
|
||||
->where('organization_id', $organization->id)
|
||||
->where('user_ref', $email)
|
||||
->first();
|
||||
|
||||
return $member ? $this->remapMemberUserRef($member, $user) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Promote invite/demo email user_ref keys to the stable OIDC public_id.
|
||||
*/
|
||||
protected function remapMemberUserRef(Member $member, User $user): Member
|
||||
{
|
||||
$ref = $user->ownerRef();
|
||||
if ($member->user_ref === $ref) {
|
||||
return $member;
|
||||
}
|
||||
|
||||
$conflict = Member::query()
|
||||
->where('organization_id', $member->organization_id)
|
||||
->where('user_ref', $ref)
|
||||
->where('id', '!=', $member->id)
|
||||
->first();
|
||||
|
||||
if ($conflict) {
|
||||
$member->delete();
|
||||
|
||||
return $conflict;
|
||||
}
|
||||
|
||||
$member->forceFill(['user_ref' => $ref])->save();
|
||||
|
||||
return $member->fresh() ?? $member;
|
||||
}
|
||||
|
||||
public function ensureOwnerMember(User $user, Organization $organization): Member
|
||||
|
||||
@@ -88,7 +88,7 @@
|
||||
<h3 class="text-sm font-semibold text-slate-900">Documents</h3>
|
||||
<p class="mt-1 text-xs text-slate-500">Specialty documents attach to the patient chart for this episode.</p>
|
||||
|
||||
@if ($canManageClinical ?? $canManageSpecialty ?? true)
|
||||
@if ($canManageClinical ?? $canManageSpecialty ?? false)
|
||||
<form method="POST" action="{{ route('care.specialty.documents.upload', ['module' => $moduleKey, 'visit' => $workspaceVisit]) }}" enctype="multipart/form-data" class="mt-4 space-y-3">
|
||||
@csrf
|
||||
<input type="file" name="attachment" required accept=".pdf,.jpg,.jpeg,.png,.webp" class="block w-full text-sm">
|
||||
|
||||
@@ -0,0 +1,384 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Http\Middleware\EnsurePlatformSession;
|
||||
use App\Models\Appointment;
|
||||
use App\Models\Branch;
|
||||
use App\Models\Department;
|
||||
use App\Models\Member;
|
||||
use App\Models\Organization;
|
||||
use App\Models\Patient;
|
||||
use App\Models\User;
|
||||
use App\Models\Visit;
|
||||
use App\Services\Care\OrganizationResolver;
|
||||
use App\Services\Care\SpecialtyModuleService;
|
||||
use Illuminate\Foundation\Testing\RefreshDatabase;
|
||||
use Tests\TestCase;
|
||||
|
||||
class CareNurseOrgAccessTest extends TestCase
|
||||
{
|
||||
use RefreshDatabase;
|
||||
|
||||
public function test_nurse_with_email_user_ref_membership_is_not_sent_to_onboarding(): void
|
||||
{
|
||||
$this->withoutMiddleware(EnsurePlatformSession::class);
|
||||
|
||||
$owner = User::create([
|
||||
'public_id' => 'owner-pid',
|
||||
'name' => 'Owner',
|
||||
'email' => 'owner@example.com',
|
||||
]);
|
||||
|
||||
$nurse = User::create([
|
||||
'public_id' => 'nurse-pid',
|
||||
'name' => 'Nurse',
|
||||
'email' => 'demo-pro-nurse@ladill.com',
|
||||
]);
|
||||
|
||||
$organization = Organization::create([
|
||||
'owner_ref' => $owner->public_id,
|
||||
'name' => 'Clinic',
|
||||
'slug' => 'clinic',
|
||||
'settings' => [
|
||||
'onboarded' => true,
|
||||
'plan' => 'pro',
|
||||
'plan_expires_at' => now()->addMonth()->toIso8601String(),
|
||||
],
|
||||
]);
|
||||
|
||||
Member::create([
|
||||
'owner_ref' => $owner->public_id,
|
||||
'organization_id' => $organization->id,
|
||||
'user_ref' => $owner->public_id,
|
||||
'role' => 'hospital_admin',
|
||||
]);
|
||||
|
||||
// Demo seeder style: staff member keyed by email until SSO remaps.
|
||||
Member::create([
|
||||
'owner_ref' => $owner->public_id,
|
||||
'organization_id' => $organization->id,
|
||||
'user_ref' => strtolower($nurse->email),
|
||||
'role' => 'nurse',
|
||||
]);
|
||||
|
||||
$resolver = app(OrganizationResolver::class);
|
||||
$this->assertTrue($resolver->isOnboarded($nurse));
|
||||
$this->assertFalse($resolver->canCompleteOnboarding($nurse));
|
||||
$this->assertSame($organization->id, $resolver->resolveForUser($nurse)?->id);
|
||||
|
||||
// Remap sticks so later requests resolve by public_id.
|
||||
$this->assertDatabaseHas('care_members', [
|
||||
'organization_id' => $organization->id,
|
||||
'user_ref' => $nurse->public_id,
|
||||
'role' => 'nurse',
|
||||
]);
|
||||
|
||||
$this->actingAs($nurse)
|
||||
->get(route('care.dashboard'))
|
||||
->assertOk();
|
||||
|
||||
$this->actingAs($nurse)
|
||||
->get(route('care.onboarding.show'))
|
||||
->assertRedirect(route('care.dashboard'));
|
||||
}
|
||||
|
||||
public function test_nurse_who_wrongly_owns_empty_org_still_uses_employer_membership(): void
|
||||
{
|
||||
$this->withoutMiddleware(EnsurePlatformSession::class);
|
||||
|
||||
$owner = User::create([
|
||||
'public_id' => 'employer-owner',
|
||||
'name' => 'Owner',
|
||||
'email' => 'employer@example.com',
|
||||
]);
|
||||
|
||||
$nurse = User::create([
|
||||
'public_id' => 'orphan-nurse',
|
||||
'name' => 'Nurse',
|
||||
'email' => 'orphan-nurse@example.com',
|
||||
]);
|
||||
|
||||
$employer = Organization::create([
|
||||
'owner_ref' => $owner->public_id,
|
||||
'name' => 'Employer Clinic',
|
||||
'slug' => 'employer-clinic',
|
||||
'settings' => [
|
||||
'onboarded' => true,
|
||||
'plan' => 'pro',
|
||||
'plan_expires_at' => now()->addMonth()->toIso8601String(),
|
||||
'specialty_modules' => ['emergency' => true],
|
||||
],
|
||||
]);
|
||||
|
||||
// Orphan org from completing owner onboarding while membership was unresolved.
|
||||
Organization::create([
|
||||
'owner_ref' => $nurse->public_id,
|
||||
'name' => 'Nurse Own Clinic',
|
||||
'slug' => 'nurse-own-clinic',
|
||||
'settings' => ['onboarded' => true],
|
||||
]);
|
||||
|
||||
Member::create([
|
||||
'owner_ref' => $owner->public_id,
|
||||
'organization_id' => $employer->id,
|
||||
'user_ref' => strtolower($nurse->email),
|
||||
'role' => 'nurse',
|
||||
]);
|
||||
|
||||
$branch = Branch::create([
|
||||
'owner_ref' => $owner->public_id,
|
||||
'organization_id' => $employer->id,
|
||||
'name' => 'Main',
|
||||
'is_active' => true,
|
||||
]);
|
||||
|
||||
app(SpecialtyModuleService::class)->activate($employer, $owner->public_id, 'emergency');
|
||||
$dept = Department::query()->where('type', 'emergency')->where('branch_id', $branch->id)->firstOrFail();
|
||||
|
||||
$patient = Patient::create([
|
||||
'owner_ref' => $owner->public_id,
|
||||
'organization_id' => $employer->id,
|
||||
'branch_id' => $branch->id,
|
||||
'patient_number' => 'P-ORPHAN',
|
||||
'first_name' => 'Ama',
|
||||
'last_name' => 'Patient',
|
||||
'gender' => 'female',
|
||||
'date_of_birth' => '1990-01-01',
|
||||
]);
|
||||
|
||||
$visit = Visit::create([
|
||||
'owner_ref' => $owner->public_id,
|
||||
'organization_id' => $employer->id,
|
||||
'branch_id' => $branch->id,
|
||||
'patient_id' => $patient->id,
|
||||
'status' => Visit::STATUS_IN_PROGRESS,
|
||||
'checked_in_at' => now(),
|
||||
]);
|
||||
|
||||
Appointment::create([
|
||||
'owner_ref' => $owner->public_id,
|
||||
'organization_id' => $employer->id,
|
||||
'branch_id' => $branch->id,
|
||||
'patient_id' => $patient->id,
|
||||
'department_id' => $dept->id,
|
||||
'visit_id' => $visit->id,
|
||||
'type' => Appointment::TYPE_WALK_IN,
|
||||
'status' => Appointment::STATUS_IN_CONSULTATION,
|
||||
'scheduled_at' => now(),
|
||||
'checked_in_at' => now(),
|
||||
'started_at' => now(),
|
||||
]);
|
||||
|
||||
$this->assertSame($employer->id, app(OrganizationResolver::class)->resolveForUser($nurse)?->id);
|
||||
|
||||
$this->actingAs($nurse)
|
||||
->get(route('care.specialty.workspace', [
|
||||
'module' => 'emergency',
|
||||
'visit' => $visit,
|
||||
'tab' => 'documents',
|
||||
]))
|
||||
->assertOk()
|
||||
->assertSee('Documents')
|
||||
->assertSee('Upload document');
|
||||
}
|
||||
|
||||
public function test_nurse_can_open_emergency_documents_tab(): void
|
||||
{
|
||||
$this->withoutMiddleware(EnsurePlatformSession::class);
|
||||
|
||||
$owner = User::create([
|
||||
'public_id' => 'er-docs-owner',
|
||||
'name' => 'Owner',
|
||||
'email' => 'er-docs-owner@example.com',
|
||||
]);
|
||||
|
||||
$nurse = User::create([
|
||||
'public_id' => 'er-docs-nurse',
|
||||
'name' => 'Nurse',
|
||||
'email' => 'er-docs-nurse@example.com',
|
||||
]);
|
||||
|
||||
$organization = Organization::create([
|
||||
'owner_ref' => $owner->public_id,
|
||||
'name' => 'ER Clinic',
|
||||
'slug' => 'er-docs-clinic',
|
||||
'settings' => [
|
||||
'onboarded' => true,
|
||||
'plan' => 'pro',
|
||||
'plan_expires_at' => now()->addMonth()->toIso8601String(),
|
||||
'specialty_modules' => ['emergency' => true],
|
||||
],
|
||||
]);
|
||||
|
||||
Member::create([
|
||||
'owner_ref' => $owner->public_id,
|
||||
'organization_id' => $organization->id,
|
||||
'user_ref' => $owner->public_id,
|
||||
'role' => 'hospital_admin',
|
||||
]);
|
||||
|
||||
Member::create([
|
||||
'owner_ref' => $owner->public_id,
|
||||
'organization_id' => $organization->id,
|
||||
'user_ref' => $nurse->public_id,
|
||||
'role' => 'nurse',
|
||||
]);
|
||||
|
||||
$branch = Branch::create([
|
||||
'owner_ref' => $owner->public_id,
|
||||
'organization_id' => $organization->id,
|
||||
'name' => 'Main',
|
||||
'is_active' => true,
|
||||
]);
|
||||
|
||||
app(SpecialtyModuleService::class)->activate($organization, $owner->public_id, 'emergency');
|
||||
|
||||
$dept = Department::query()->where('type', 'emergency')->where('branch_id', $branch->id)->firstOrFail();
|
||||
|
||||
$patient = Patient::create([
|
||||
'owner_ref' => $owner->public_id,
|
||||
'organization_id' => $organization->id,
|
||||
'branch_id' => $branch->id,
|
||||
'patient_number' => 'P-DOCS',
|
||||
'first_name' => 'Ama',
|
||||
'last_name' => 'Docs',
|
||||
'gender' => 'female',
|
||||
'date_of_birth' => '1990-01-01',
|
||||
]);
|
||||
|
||||
$visit = Visit::create([
|
||||
'owner_ref' => $owner->public_id,
|
||||
'organization_id' => $organization->id,
|
||||
'branch_id' => $branch->id,
|
||||
'patient_id' => $patient->id,
|
||||
'status' => Visit::STATUS_IN_PROGRESS,
|
||||
'checked_in_at' => now(),
|
||||
]);
|
||||
|
||||
Appointment::create([
|
||||
'owner_ref' => $owner->public_id,
|
||||
'organization_id' => $organization->id,
|
||||
'branch_id' => $branch->id,
|
||||
'patient_id' => $patient->id,
|
||||
'department_id' => $dept->id,
|
||||
'visit_id' => $visit->id,
|
||||
'type' => Appointment::TYPE_WALK_IN,
|
||||
'status' => Appointment::STATUS_IN_CONSULTATION,
|
||||
'scheduled_at' => now(),
|
||||
'checked_in_at' => now(),
|
||||
'started_at' => now(),
|
||||
]);
|
||||
|
||||
$this->actingAs($nurse)
|
||||
->get(route('care.specialty.workspace', [
|
||||
'module' => 'emergency',
|
||||
'visit' => $visit,
|
||||
'tab' => 'documents',
|
||||
]))
|
||||
->assertOk()
|
||||
->assertSee('Documents')
|
||||
->assertSee('Upload document');
|
||||
}
|
||||
|
||||
public function test_view_only_staff_sees_documents_without_upload(): void
|
||||
{
|
||||
$this->withoutMiddleware(EnsurePlatformSession::class);
|
||||
|
||||
$owner = User::create([
|
||||
'public_id' => 'view-docs-owner',
|
||||
'name' => 'Owner',
|
||||
'email' => 'view-docs-owner@example.com',
|
||||
]);
|
||||
|
||||
$lab = User::create([
|
||||
'public_id' => 'view-docs-lab',
|
||||
'name' => 'Lab',
|
||||
'email' => 'view-docs-lab@example.com',
|
||||
]);
|
||||
|
||||
$organization = Organization::create([
|
||||
'owner_ref' => $owner->public_id,
|
||||
'name' => 'Cardio Clinic',
|
||||
'slug' => 'cardio-docs-clinic',
|
||||
'settings' => [
|
||||
'onboarded' => true,
|
||||
'plan' => 'pro',
|
||||
'plan_expires_at' => now()->addMonth()->toIso8601String(),
|
||||
],
|
||||
]);
|
||||
|
||||
Member::create([
|
||||
'owner_ref' => $owner->public_id,
|
||||
'organization_id' => $organization->id,
|
||||
'user_ref' => $owner->public_id,
|
||||
'role' => 'hospital_admin',
|
||||
]);
|
||||
|
||||
Member::create([
|
||||
'owner_ref' => $owner->public_id,
|
||||
'organization_id' => $organization->id,
|
||||
'user_ref' => $lab->public_id,
|
||||
'role' => 'lab_technician',
|
||||
]);
|
||||
|
||||
$branch = Branch::create([
|
||||
'owner_ref' => $owner->public_id,
|
||||
'organization_id' => $organization->id,
|
||||
'name' => 'Main',
|
||||
'is_active' => true,
|
||||
]);
|
||||
|
||||
$modules = app(SpecialtyModuleService::class);
|
||||
$modules->activate($organization, $owner->public_id, 'cardiology');
|
||||
|
||||
$dept = Department::query()->where('type', 'cardiology')->where('branch_id', $branch->id)->firstOrFail();
|
||||
|
||||
$patient = Patient::create([
|
||||
'owner_ref' => $owner->public_id,
|
||||
'organization_id' => $organization->id,
|
||||
'branch_id' => $branch->id,
|
||||
'patient_number' => 'P-VIEW-DOCS',
|
||||
'first_name' => 'Kofi',
|
||||
'last_name' => 'View',
|
||||
'gender' => 'male',
|
||||
'date_of_birth' => '1985-01-01',
|
||||
]);
|
||||
|
||||
$visit = Visit::create([
|
||||
'owner_ref' => $owner->public_id,
|
||||
'organization_id' => $organization->id,
|
||||
'branch_id' => $branch->id,
|
||||
'patient_id' => $patient->id,
|
||||
'status' => Visit::STATUS_IN_PROGRESS,
|
||||
'checked_in_at' => now(),
|
||||
]);
|
||||
|
||||
Appointment::create([
|
||||
'owner_ref' => $owner->public_id,
|
||||
'organization_id' => $organization->id,
|
||||
'branch_id' => $branch->id,
|
||||
'patient_id' => $patient->id,
|
||||
'department_id' => $dept->id,
|
||||
'visit_id' => $visit->id,
|
||||
'type' => Appointment::TYPE_WALK_IN,
|
||||
'status' => Appointment::STATUS_IN_CONSULTATION,
|
||||
'scheduled_at' => now(),
|
||||
'checked_in_at' => now(),
|
||||
'started_at' => now(),
|
||||
]);
|
||||
|
||||
$labMember = Member::query()->where('user_ref', $lab->public_id)->firstOrFail();
|
||||
$this->assertSame('view', $modules->memberAccessLevel($organization, $labMember, 'cardiology'));
|
||||
|
||||
$this->actingAs($lab)
|
||||
->get(route('care.specialty.workspace', [
|
||||
'module' => 'cardiology',
|
||||
'visit' => $visit,
|
||||
'tab' => 'documents',
|
||||
]))
|
||||
->assertOk()
|
||||
->assertSee('Documents')
|
||||
->assertDontSee('Upload document');
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user