Deploy Ladill Care / deploy (push) Successful in 46s
Nurses can no longer pick a shift on the form; the server sets it from today's unit roster, falling back to the current clock window. Co-authored-by: Cursor <cursoragent@cursor.com>
283 lines
9.3 KiB
PHP
283 lines
9.3 KiB
PHP
<?php
|
|
|
|
namespace Tests\Feature;
|
|
|
|
use App\Http\Middleware\EnsurePlatformSession;
|
|
use App\Models\Bed;
|
|
use App\Models\Branch;
|
|
use App\Models\CareUnit;
|
|
use App\Models\Department;
|
|
use App\Models\MarAdministration;
|
|
use App\Models\MarOrder;
|
|
use App\Models\Member;
|
|
use App\Models\Organization;
|
|
use App\Models\Patient;
|
|
use App\Models\Prescription;
|
|
use App\Models\PrescriptionItem;
|
|
use App\Models\User;
|
|
use App\Models\Visit;
|
|
use App\Models\WardHandover;
|
|
use App\Services\Care\MarService;
|
|
use App\Services\Care\VisitPlacementService;
|
|
use Illuminate\Foundation\Testing\RefreshDatabase;
|
|
use Tests\TestCase;
|
|
|
|
class CareMarAndNursingTest extends TestCase
|
|
{
|
|
use RefreshDatabase;
|
|
|
|
protected User $owner;
|
|
|
|
protected Organization $organization;
|
|
|
|
protected Branch $branch;
|
|
|
|
protected CareUnit $unit;
|
|
|
|
protected Visit $visit;
|
|
|
|
protected PrescriptionItem $item;
|
|
|
|
protected function setUp(): void
|
|
{
|
|
parent::setUp();
|
|
$this->withoutMiddleware(EnsurePlatformSession::class);
|
|
|
|
$this->owner = User::create([
|
|
'public_id' => 'mar-nursing-owner',
|
|
'name' => 'Owner',
|
|
'email' => 'mar-owner@example.com',
|
|
]);
|
|
|
|
$this->organization = Organization::create([
|
|
'owner_ref' => $this->owner->public_id,
|
|
'name' => 'MAR Hospital',
|
|
'slug' => 'mar-hospital',
|
|
'settings' => [
|
|
'onboarded' => true,
|
|
'facility_type' => 'hospital',
|
|
'plan' => 'pro',
|
|
'plan_expires_at' => now()->addMonth()->toIso8601String(),
|
|
],
|
|
]);
|
|
|
|
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,
|
|
]);
|
|
|
|
$department = Department::create([
|
|
'owner_ref' => $this->owner->public_id,
|
|
'branch_id' => $this->branch->id,
|
|
'name' => 'Medicine',
|
|
'type' => 'general',
|
|
'is_active' => true,
|
|
]);
|
|
|
|
$this->unit = CareUnit::create([
|
|
'owner_ref' => $this->owner->public_id,
|
|
'organization_id' => $this->organization->id,
|
|
'department_id' => $department->id,
|
|
'name' => 'Medical Ward',
|
|
'kind' => 'inpatient',
|
|
'is_active' => true,
|
|
]);
|
|
|
|
$bed = Bed::create([
|
|
'owner_ref' => $this->owner->public_id,
|
|
'organization_id' => $this->organization->id,
|
|
'care_unit_id' => $this->unit->id,
|
|
'label' => 'MW-01',
|
|
'status' => 'available',
|
|
'is_active' => true,
|
|
]);
|
|
|
|
$patient = Patient::create([
|
|
'owner_ref' => $this->owner->public_id,
|
|
'organization_id' => $this->organization->id,
|
|
'branch_id' => $this->branch->id,
|
|
'patient_number' => 'P-MAR-1',
|
|
'first_name' => 'Kofi',
|
|
'last_name' => 'Asante',
|
|
'gender' => 'male',
|
|
]);
|
|
|
|
$this->visit = Visit::create([
|
|
'owner_ref' => $this->owner->public_id,
|
|
'organization_id' => $this->organization->id,
|
|
'branch_id' => $this->branch->id,
|
|
'patient_id' => $patient->id,
|
|
'status' => Visit::STATUS_IN_PROGRESS,
|
|
'checked_in_at' => now(),
|
|
]);
|
|
|
|
app(VisitPlacementService::class)->place(
|
|
$this->visit,
|
|
$this->unit,
|
|
$bed,
|
|
$this->owner->public_id,
|
|
$this->owner->public_id,
|
|
);
|
|
|
|
$rx = Prescription::create([
|
|
'owner_ref' => $this->owner->public_id,
|
|
'organization_id' => $this->organization->id,
|
|
'visit_id' => $this->visit->id,
|
|
'patient_id' => $patient->id,
|
|
'status' => Prescription::STATUS_ACTIVE,
|
|
'prescribed_by' => $this->owner->public_id,
|
|
]);
|
|
|
|
$this->item = PrescriptionItem::create([
|
|
'owner_ref' => $this->owner->public_id,
|
|
'prescription_id' => $rx->id,
|
|
'name' => 'Paracetamol',
|
|
'dosage' => '1g',
|
|
'frequency' => 'TDS',
|
|
'route' => 'oral',
|
|
'sort_order' => 1,
|
|
]);
|
|
}
|
|
|
|
public function test_mar_syncs_orders_and_records_given(): void
|
|
{
|
|
$mar = app(MarService::class);
|
|
$orders = $mar->syncOrdersForVisit($this->visit->fresh(), $this->owner->public_id);
|
|
$this->assertCount(1, $orders);
|
|
$this->assertSame('tds', $orders->first()->frequency_code);
|
|
|
|
$order = $orders->first();
|
|
$scheduled = now()->startOfDay()->setTime(8, 0);
|
|
|
|
$this->actingAs($this->owner)
|
|
->post(route('care.mar.administer', $order), [
|
|
'status' => 'given',
|
|
'scheduled_for' => $scheduled->toDateTimeString(),
|
|
])
|
|
->assertRedirect();
|
|
|
|
$this->assertDatabaseHas('care_mar_administrations', [
|
|
'mar_order_id' => $order->id,
|
|
'status' => MarAdministration::STATUS_GIVEN,
|
|
]);
|
|
|
|
$this->actingAs($this->owner)
|
|
->get(route('care.care-units.mar', $this->unit))
|
|
->assertOk()
|
|
->assertSee('Paracetamol')
|
|
->assertSee('Kofi');
|
|
}
|
|
|
|
public function test_hold_requires_reason(): void
|
|
{
|
|
$order = app(MarService::class)
|
|
->syncOrdersForVisit($this->visit->fresh(), $this->owner->public_id)
|
|
->first();
|
|
|
|
$this->actingAs($this->owner)
|
|
->from(route('care.visits.mar', $this->visit))
|
|
->post(route('care.mar.administer', $order), [
|
|
'status' => 'held',
|
|
'scheduled_for' => now()->startOfDay()->setTime(8, 0)->toDateTimeString(),
|
|
])
|
|
->assertRedirect()
|
|
->assertSessionHasErrors('reason');
|
|
}
|
|
|
|
public function test_nursing_note_and_handover(): void
|
|
{
|
|
$this->travelTo(now()->setTime(16, 30));
|
|
|
|
$this->actingAs($this->owner)
|
|
->get(route('care.care-units.notes', $this->unit))
|
|
->assertOk()
|
|
->assertSee('Evening shift')
|
|
->assertDontSee('name="shift_code"', false);
|
|
|
|
$this->actingAs($this->owner)
|
|
->post(route('care.care-units.notes.store', $this->unit), [
|
|
'visit_id' => $this->visit->id,
|
|
'note_type' => 'progress',
|
|
'shift_code' => 'night', // ignored — duty/clock sets shift
|
|
'body' => 'Vitals stable; pain controlled.',
|
|
])
|
|
->assertRedirect(route('care.care-units.notes', [$this->unit, 'visit' => $this->visit->id]));
|
|
|
|
$this->assertDatabaseHas('care_nursing_notes', [
|
|
'visit_id' => $this->visit->id,
|
|
'body' => 'Vitals stable; pain controlled.',
|
|
'shift_code' => 'evening',
|
|
]);
|
|
|
|
$this->actingAs($this->owner)
|
|
->post(route('care.care-units.handovers.store', $this->unit), [
|
|
'from_shift' => 'day',
|
|
'to_shift' => 'night',
|
|
'situation' => 'Quiet ward',
|
|
'background' => '4 patients',
|
|
'assessment' => 'Stable',
|
|
'recommendation' => 'Continue observations',
|
|
'complete' => '1',
|
|
])
|
|
->assertRedirect(route('care.care-units.handovers', $this->unit));
|
|
|
|
$this->assertDatabaseHas('care_ward_handovers', [
|
|
'care_unit_id' => $this->unit->id,
|
|
'status' => WardHandover::STATUS_COMPLETED,
|
|
'from_shift' => 'day',
|
|
'to_shift' => 'night',
|
|
]);
|
|
|
|
$this->actingAs($this->owner)
|
|
->get(route('care.care-units.notes', $this->unit))
|
|
->assertOk()
|
|
->assertSee('Vitals stable');
|
|
|
|
$this->actingAs($this->owner)
|
|
->get(route('care.care-units.notes', [$this->unit, 'visit' => $this->visit->id]))
|
|
->assertOk()
|
|
->assertSee('value="'.$this->visit->id.'" selected', false);
|
|
|
|
$this->actingAs($this->owner)
|
|
->get(route('care.care-units.handovers', $this->unit))
|
|
->assertOk()
|
|
->assertSee('Completed');
|
|
}
|
|
|
|
public function test_duplicate_scheduled_dose_rejected(): void
|
|
{
|
|
$order = app(MarService::class)
|
|
->syncOrdersForVisit($this->visit->fresh(), $this->owner->public_id)
|
|
->first();
|
|
$scheduled = now()->startOfDay()->setTime(8, 0)->toDateTimeString();
|
|
|
|
$this->actingAs($this->owner)
|
|
->post(route('care.mar.administer', $order), [
|
|
'status' => 'given',
|
|
'scheduled_for' => $scheduled,
|
|
])
|
|
->assertRedirect();
|
|
|
|
$this->actingAs($this->owner)
|
|
->from(route('care.visits.mar', $this->visit))
|
|
->post(route('care.mar.administer', $order), [
|
|
'status' => 'given',
|
|
'scheduled_for' => $scheduled,
|
|
])
|
|
->assertRedirect()
|
|
->assertSessionHasErrors('scheduled_for');
|
|
|
|
$this->assertSame(1, MarAdministration::query()->where('mar_order_id', $order->id)->count());
|
|
$this->assertSame(1, MarOrder::query()->where('visit_id', $this->visit->id)->count());
|
|
}
|
|
}
|