withoutMiddleware(EnsurePlatformSession::class); $this->owner = User::create([ 'public_id' => 'sp-care-owner', 'name' => 'Owner', 'email' => 'sp-care@example.com', ]); $this->organization = Organization::create([ 'owner_ref' => $this->owner->public_id, 'name' => 'Ridge Medical Centre', 'slug' => 'ridge-medical', 'settings' => [ 'onboarded' => true, 'facility_type' => 'hospital', 'plan' => 'pro', 'plan_expires_at' => now()->addMonth()->toIso8601String(), 'queue_integration_enabled' => true, ], ]); Member::create([ 'owner_ref' => $this->owner->public_id, 'organization_id' => $this->organization->id, 'user_ref' => $this->owner->public_id, 'role' => 'hospital_admin', ]); $this->branch = Branch::create([ 'owner_ref' => $this->owner->public_id, 'organization_id' => $this->organization->id, 'name' => 'Main', 'is_active' => true, ]); $this->doctorA = Practitioner::create([ 'owner_ref' => $this->owner->public_id, 'organization_id' => $this->organization->id, 'branch_id' => $this->branch->id, 'name' => 'Dr. Mensah', 'specialty' => 'General', 'room' => 'Consultation Room 4', 'user_ref' => 'doc-mensah', 'is_active' => true, ]); $this->doctorB = Practitioner::create([ 'owner_ref' => $this->owner->public_id, 'organization_id' => $this->organization->id, 'branch_id' => $this->branch->id, 'name' => 'Dr. Okai', 'specialty' => 'Pediatrics', 'room' => 'Consultation Room 5', 'user_ref' => 'doc-okai', 'is_active' => true, ]); } public function test_fixed_doctor_appointment_issues_to_that_doctors_point(): void { Http::fake(); $patient = Patient::create([ 'uuid' => (string) Str::uuid(), 'owner_ref' => $this->owner->public_id, 'organization_id' => $this->organization->id, 'branch_id' => $this->branch->id, 'patient_number' => 'P-1', 'first_name' => 'Ada', 'last_name' => 'Lovelace', ]); $appointment = Appointment::create([ 'uuid' => (string) Str::uuid(), 'owner_ref' => $this->owner->public_id, 'organization_id' => $this->organization->id, 'branch_id' => $this->branch->id, 'patient_id' => $patient->id, 'practitioner_id' => $this->doctorA->id, 'type' => Appointment::TYPE_SCHEDULED, 'status' => Appointment::STATUS_SCHEDULED, 'scheduled_at' => now()->addHour(), ]); $result = app(AppointmentService::class)->checkIn($appointment, $this->owner->public_id); $point = CareServicePoint::query() ->where('organization_id', $this->organization->id) ->where('kind', 'practitioner') ->where('ref_id', $this->doctorA->id) ->first(); $this->assertNotNull($point); $this->assertSame('C001', $result->queue_ticket_number); $this->assertSame($point->uuid, $result->queue_service_point_uuid); $this->assertSame('Consultation Room 4', $result->queue_destination); $this->assertSame('Dr. Mensah', $result->queue_staff_display_name); $this->assertSame(CareQueueContexts::ROUTING_ROUTED, $result->queue_routing_status); Http::assertNothingSent(); } public function test_walk_in_without_doctor_routes_to_default_desk(): void { Http::fake(); $patient = Patient::create([ 'uuid' => (string) Str::uuid(), 'owner_ref' => $this->owner->public_id, 'organization_id' => $this->organization->id, 'branch_id' => $this->branch->id, 'patient_number' => 'P-2', 'first_name' => 'Bob', 'last_name' => 'Builder', ]); $appointment = Appointment::create([ 'uuid' => (string) Str::uuid(), 'owner_ref' => $this->owner->public_id, 'organization_id' => $this->organization->id, 'branch_id' => $this->branch->id, 'patient_id' => $patient->id, 'practitioner_id' => null, 'type' => Appointment::TYPE_WALK_IN, 'status' => Appointment::STATUS_WAITING, 'waiting_at' => now(), ]); $result = app(CareQueueBridge::class)->issueForAppointment($this->organization, $appointment); // Native engine prefers an available desk over leaving waiters without a ticket. $this->assertNotNull($result->queue_ticket_uuid); $this->assertSame(CareQueueContexts::ROUTING_ROUTED, $result->queue_routing_status); $this->assertDatabaseHas('care_queue_tickets', [ 'uuid' => $result->queue_ticket_uuid, 'status' => CareQueueTicket::STATUS_WAITING, ]); Http::assertNothingSent(); } public function test_walk_in_with_selected_doctor_routes_only_to_that_point(): void { Http::fake(); $patient = Patient::create([ 'uuid' => (string) Str::uuid(), 'owner_ref' => $this->owner->public_id, 'organization_id' => $this->organization->id, 'branch_id' => $this->branch->id, 'patient_number' => 'P-3', 'first_name' => 'Cara', 'last_name' => 'Clinic', ]); $appointment = app(AppointmentService::class)->walkIn( $this->organization, $this->owner->public_id, [ 'branch_id' => $this->branch->id, 'patient_id' => $patient->id, 'practitioner_id' => $this->doctorB->id, 'reason' => 'Fever', ], $this->owner->public_id, ); $point = CareServicePoint::query() ->where('organization_id', $this->organization->id) ->where('kind', 'practitioner') ->where('ref_id', $this->doctorB->id) ->first(); $this->assertSame($this->doctorB->id, $appointment->practitioner_id); $this->assertSame('C001', $appointment->queue_ticket_number); $this->assertSame('Consultation Room 5', $appointment->queue_destination); $this->assertNotNull($point); $this->assertSame($point->uuid, $appointment->queue_service_point_uuid); Http::assertNothingSent(); } public function test_pharmacist_call_next_uses_pharmacy_point(): void { Http::fake(); $pharmacist = Member::create([ 'owner_ref' => $this->owner->public_id, 'organization_id' => $this->organization->id, 'user_ref' => 'pharm-1', 'role' => 'pharmacist', 'branch_id' => $this->branch->id, ]); app(CareQueueProvisioner::class)->ensure( $this->organization->fresh(), CareQueueContexts::PHARMACY, $this->branch->id, ); $queue = CareServiceQueue::query() ->where('organization_id', $this->organization->id) ->where('context', CareQueueContexts::PHARMACY) ->where('branch_id', $this->branch->id) ->firstOrFail(); $point = CareServicePoint::query() ->where('service_queue_id', $queue->id) ->where('kind', 'member') ->where('ref_id', $pharmacist->id) ->firstOrFail(); CareQueueTicket::create([ 'owner_ref' => $this->owner->public_id, 'organization_id' => $this->organization->id, 'service_queue_id' => $queue->id, 'service_point_id' => $point->id, 'ticket_number' => 'P001', 'status' => CareQueueTicket::STATUS_WAITING, 'priority' => 'walk_in', 'customer_name' => 'Pharmacy Patient', ]); $result = app(CareQueueBridge::class)->callNext( $this->organization->fresh(), CareQueueContexts::PHARMACY, $this->branch->id, $pharmacist, ); $this->assertSame('P001', $result['ticket']['ticket_number'] ?? null); $this->assertSame('called', $result['ticket']['status'] ?? null); $this->assertSame($point->uuid, $result['ticket']['assigned_counter']['uuid'] ?? null); Http::assertNothingSent(); } public function test_integration_off_preserves_behavior_without_ticket_issuance(): void { $settings = $this->organization->settings; $settings['queue_integration_enabled'] = false; $this->organization->update(['settings' => $settings]); Http::fake(); $patient = Patient::create([ 'uuid' => (string) Str::uuid(), 'owner_ref' => $this->owner->public_id, 'organization_id' => $this->organization->id, 'branch_id' => $this->branch->id, 'patient_number' => 'P-4', 'first_name' => 'Dee', 'last_name' => 'Demo', ]); $appointment = Appointment::create([ 'uuid' => (string) Str::uuid(), 'owner_ref' => $this->owner->public_id, 'organization_id' => $this->organization->id, 'branch_id' => $this->branch->id, 'patient_id' => $patient->id, 'practitioner_id' => $this->doctorA->id, 'type' => Appointment::TYPE_SCHEDULED, 'status' => Appointment::STATUS_SCHEDULED, 'scheduled_at' => now()->addHour(), ]); $result = app(AppointmentService::class)->checkIn($appointment, $this->owner->public_id); $this->assertNull($result->queue_ticket_uuid); Http::assertNothingSent(); } public function test_provisioner_builds_one_point_per_practitioner_idempotently(): void { Http::fake(); app(CareQueueProvisioner::class)->provisionOrganization($this->organization->fresh()); $first = data_get($this->organization->fresh()->settings, 'department_queue_provisioning.consultation.queues.0.points'); $this->assertIsArray($first); $this->assertGreaterThanOrEqual(2, count($first)); $this->assertDatabaseHas('care_service_queues', [ 'organization_id' => $this->organization->id, 'branch_id' => $this->branch->id, 'context' => CareQueueContexts::CONSULTATION, ]); $this->assertEquals( 2, CareServicePoint::query() ->where('organization_id', $this->organization->id) ->where('kind', 'practitioner') ->whereIn('ref_id', [$this->doctorA->id, $this->doctorB->id]) ->count(), ); app(CareQueueProvisioner::class)->provisionOrganization($this->organization->fresh()); $second = data_get($this->organization->fresh()->settings, 'department_queue_provisioning.consultation.queues.0.points'); $this->assertCount(count($first), $second); Http::assertNothingSent(); } }