Deploy Ladill Care / deploy (push) Successful in 1m22s
Replace internal design jargon (Layer 1, narrative source of truth, pathway instruments) with plain clinical language on consultations, patient charts, settings, and nav.
200 lines
7.1 KiB
PHP
200 lines
7.1 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature;
|
|
|
|
use App\Http\Middleware\EnsurePlatformSession;
|
|
use App\Models\Assessment;
|
|
use App\Models\AssessmentQuestion;
|
|
use App\Models\AssessmentTemplate;
|
|
use App\Models\Branch;
|
|
use App\Models\Consultation;
|
|
use App\Models\Member;
|
|
use App\Models\Organization;
|
|
use App\Models\Patient;
|
|
use App\Models\User;
|
|
use App\Models\Visit;
|
|
use App\Services\Care\CareFeatures;
|
|
use Database\Seeders\AssessmentTemplateSeeder;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Illuminate\Support\Str;
|
|
use Tests\TestCase;
|
|
|
|
class CareUniversalIntakeTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
protected User $user;
|
|
|
|
protected Organization $organization;
|
|
|
|
protected Branch $branch;
|
|
|
|
protected Patient $patient;
|
|
|
|
protected Member $member;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
$this->withoutMiddleware(EnsurePlatformSession::class);
|
|
|
|
$this->user = User::create([
|
|
'public_id' => 'universal-intake-user',
|
|
'name' => 'Intake User',
|
|
'email' => 'intake@example.com',
|
|
]);
|
|
|
|
$this->organization = Organization::create([
|
|
'owner_ref' => $this->user->public_id,
|
|
'name' => 'Intake Clinic',
|
|
'slug' => 'intake-clinic',
|
|
'timezone' => 'UTC',
|
|
'settings' => [
|
|
'onboarded' => true,
|
|
'rollout' => [CareFeatures::ASSESSMENTS_ENGINE => true],
|
|
],
|
|
]);
|
|
|
|
$this->member = Member::create([
|
|
'owner_ref' => $this->user->public_id,
|
|
'organization_id' => $this->organization->id,
|
|
'user_ref' => $this->user->public_id,
|
|
'role' => 'nurse',
|
|
]);
|
|
|
|
$this->branch = Branch::create([
|
|
'owner_ref' => $this->user->public_id,
|
|
'organization_id' => $this->organization->id,
|
|
'name' => 'Main',
|
|
'is_active' => true,
|
|
]);
|
|
|
|
$this->patient = Patient::create([
|
|
'uuid' => (string) Str::uuid(),
|
|
'owner_ref' => $this->user->public_id,
|
|
'organization_id' => $this->organization->id,
|
|
'branch_id' => $this->branch->id,
|
|
'patient_number' => 'LC-INTAKE-001',
|
|
'first_name' => 'Kwame',
|
|
'last_name' => 'Boateng',
|
|
]);
|
|
}
|
|
|
|
public function test_assessment_template_seeder_loads_universal_intake_pack(): void
|
|
{
|
|
$this->seed(AssessmentTemplateSeeder::class);
|
|
|
|
$template = AssessmentTemplate::currentSystemByCode('universal_intake');
|
|
$this->assertNotNull($template);
|
|
$this->assertSame(1, $template->version);
|
|
$this->assertSame(AssessmentTemplate::CATEGORY_UNIVERSAL, $template->category);
|
|
$this->assertNull($template->organization_id);
|
|
$this->assertSame(['doctor', 'nurse'], $template->meta['capture_roles'] ?? null);
|
|
|
|
$codes = $template->questions()->pluck('code')->all();
|
|
$this->assertContains('chief_complaint', $codes);
|
|
$this->assertContains('hpi', $codes);
|
|
$this->assertContains('pain_score', $codes);
|
|
$this->assertContains('smoking_status', $codes);
|
|
$this->assertContains('mobility', $codes);
|
|
$this->assertContains('baseline_labs_summary', $codes);
|
|
|
|
$chief = $template->questions()->where('code', 'chief_complaint')->first();
|
|
$this->assertTrue($chief->is_required);
|
|
$this->assertSame(AssessmentQuestion::TYPE_TEXTAREA, $chief->answer_type);
|
|
}
|
|
|
|
public function test_seeder_is_idempotent_and_replaces_questions(): void
|
|
{
|
|
$this->seed(AssessmentTemplateSeeder::class);
|
|
$firstId = AssessmentTemplate::currentSystemByCode('universal_intake')->id;
|
|
$questionCount = AssessmentQuestion::where('template_id', $firstId)->count();
|
|
|
|
$this->seed(AssessmentTemplateSeeder::class);
|
|
|
|
$this->assertSame(1, AssessmentTemplate::where('code', 'universal_intake')->count());
|
|
$this->assertSame($firstId, AssessmentTemplate::currentSystemByCode('universal_intake')->id);
|
|
$this->assertSame($questionCount, AssessmentQuestion::where('template_id', $firstId)->count());
|
|
}
|
|
|
|
public function test_nurse_can_complete_seeded_universal_intake_on_consultation(): void
|
|
{
|
|
$this->seed(AssessmentTemplateSeeder::class);
|
|
|
|
$visit = Visit::create([
|
|
'owner_ref' => $this->user->public_id,
|
|
'organization_id' => $this->organization->id,
|
|
'branch_id' => $this->branch->id,
|
|
'patient_id' => $this->patient->id,
|
|
'status' => Visit::STATUS_OPEN,
|
|
'checked_in_at' => now(),
|
|
]);
|
|
|
|
$consultation = Consultation::create([
|
|
'owner_ref' => $this->user->public_id,
|
|
'visit_id' => $visit->id,
|
|
'patient_id' => $this->patient->id,
|
|
'status' => Consultation::STATUS_DRAFT,
|
|
'started_at' => now(),
|
|
'symptoms' => 'Free-text headache narrative',
|
|
]);
|
|
|
|
// Nurse has vitals + assessments.capture; free-text symptoms fields require consultations.manage.
|
|
$this->actingAs($this->user)
|
|
->get(route('care.consultations.show', $consultation))
|
|
->assertOk()
|
|
->assertSee('Patient history form')
|
|
->assertSee('do not overwrite each other', false)
|
|
->assertSee('Start patient history form');
|
|
|
|
$this->actingAs($this->user)
|
|
->post(route('care.consultations.assessments.store', $consultation), [
|
|
'template_code' => 'universal_intake',
|
|
])
|
|
->assertRedirect();
|
|
|
|
$assessment = Assessment::first();
|
|
$this->assertNotNull($assessment);
|
|
$this->assertSame($consultation->id, $assessment->consultation_id);
|
|
$this->assertSame('universal_intake', $assessment->template->code);
|
|
|
|
$this->actingAs($this->user)
|
|
->put(route('care.assessments.update', $assessment), [
|
|
'answers' => [
|
|
'chief_complaint' => 'Severe headache for 2 days',
|
|
'pain_score' => 7,
|
|
'smoking_status' => 'never',
|
|
'mobility' => 'independent',
|
|
],
|
|
])
|
|
->assertRedirect();
|
|
|
|
$this->actingAs($this->user)
|
|
->post(route('care.assessments.complete', $assessment))
|
|
->assertRedirect();
|
|
|
|
$assessment->refresh();
|
|
$this->assertTrue($assessment->isCompleted());
|
|
|
|
// Dual narrative: free-text symptoms unchanged by structured intake.
|
|
$this->assertSame('Free-text headache narrative', $consultation->fresh()->symptoms);
|
|
|
|
$this->actingAs($this->user)
|
|
->get(route('care.patients.show', $this->patient))
|
|
->assertOk()
|
|
->assertSee('Patient history form')
|
|
->assertSee('Severe headache for 2 days');
|
|
}
|
|
|
|
public function test_create_form_lists_seeded_universal_for_nurse(): void
|
|
{
|
|
$this->seed(AssessmentTemplateSeeder::class);
|
|
|
|
$this->actingAs($this->user)
|
|
->get(route('care.assessments.create', $this->patient))
|
|
->assertOk()
|
|
->assertSee('Universal Intake')
|
|
->assertSee('universal_intake');
|
|
}
|
|
}
|