Add workflow-centric patient journey with financial gates.
Deploy Ladill Care / deploy (push) Failing after 45s

Introduces a facility workflow engine as Care's primary configuration
object: onboarding now leads with a facility category (which modules to
enable) and a workflow template (how patients move + where money is
collected), including standard herbal hospital/clinic templates.

Templates materialize into care_facility_workflows/care_workflow_stages.
The engine tracks a visit's position via care_visit_stage_advances and,
with FinancialGateService, gates a stage's queue behind a cleared
FinancialObligation (paid/authorized/waived/deferred) for "before"
payment timing while leaving "after" (pay-at-exit) flows unblocked.
Gated behavior is opt-in behind the workflow_engine/financial_gates
rollout flags; legacy orgs keep current behavior.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
isaacclad
2026-07-17 20:47:33 +00:00
co-authored by Cursor
parent c319692b33
commit 86bfce1e17
16 changed files with 1564 additions and 27 deletions
+66 -18
View File
@@ -1,30 +1,84 @@
<x-app-layout title="Set up Care">
<div class="mx-auto max-w-xl">
<div class="mx-auto max-w-2xl">
<h1 class="text-2xl font-semibold text-slate-900">Welcome to Ladill Care</h1>
<p class="mt-2 text-sm text-slate-600">Set up your healthcare facility to get started.</p>
<p class="mt-2 text-sm text-slate-600">Two quick choices shape your facility: what you do (category) and how patients move through it (workflow).</p>
<form method="POST" action="{{ route('care.onboarding.store') }}" enctype="multipart/form-data" class="mt-8 space-y-5 rounded-2xl border border-slate-200 bg-white p-6">
@php
$categoryDefaults = [];
foreach ($categories as $key => $category) {
$categoryDefaults[$key] = $category['default_template'] ?? $defaultTemplate;
}
@endphp
<form
method="POST"
action="{{ route('care.onboarding.store') }}"
enctype="multipart/form-data"
class="mt-8 space-y-6 rounded-2xl border border-slate-200 bg-white p-6"
x-data="{
category: @js(old('facility_category', array_key_first($categories))),
template: @js(old('workflow_template', $defaultTemplate)),
defaults: @js($categoryDefaults),
pickCategory(key) {
this.category = key;
if (this.defaults[key]) this.template = this.defaults[key];
},
}"
>
@csrf
<div>
<label class="block text-sm font-medium text-slate-700">Facility / organization name</label>
<input type="text" name="organization_name" value="{{ old('organization_name', $user->name."'s Clinic") }}" required
<input type="text" name="organization_name" value="{{ old('organization_name', $user->name."'s Facility") }}" required
class="mt-1 w-full rounded-lg border-slate-300 text-sm">
@error('organization_name') <p class="mt-1 text-sm text-rose-600">{{ $message }}</p> @enderror
</div>
<div>
<label class="block text-sm font-medium text-slate-700">Facility type</label>
<select name="facility_type" class="mt-1 w-full rounded-lg border-slate-300 text-sm">
@foreach ($facilityTypes as $value => $label)
<option value="{{ $value }}" @selected(old('facility_type', 'clinic') === $value)>{{ $label }}</option>
<p class="text-sm font-medium text-slate-700">1. Facility category</p>
<p class="text-xs text-slate-500">Decides which modules (lab, pharmacy, imaging, billing) are turned on.</p>
<input type="hidden" name="facility_category" :value="category">
<div class="mt-3 grid grid-cols-2 gap-2 sm:grid-cols-3">
@foreach ($categories as $key => $category)
<button type="button" @click="pickCategory(@js($key))"
class="rounded-xl border px-3 py-2 text-left text-sm transition"
:class="category === @js($key) ? 'border-sky-500 bg-sky-50 text-sky-900 ring-1 ring-sky-500' : 'border-slate-200 text-slate-700 hover:border-slate-300'">
{{ $category['label'] }}
</button>
@endforeach
</select>
</div>
@error('facility_category') <p class="mt-1 text-sm text-rose-600">{{ $message }}</p> @enderror
</div>
<div>
<label class="block text-sm font-medium text-slate-700">Primary branch</label>
<input type="text" name="branch_name" value="{{ old('branch_name', 'Main Branch') }}" required
class="mt-1 w-full rounded-lg border-slate-300 text-sm">
<p class="text-sm font-medium text-slate-700">2. Workflow template</p>
<p class="text-xs text-slate-500">Defines the patient journey and where payments are collected. You can customize this later.</p>
<div class="mt-3 space-y-2">
@foreach ($templates as $key => $template)
<label class="flex cursor-pointer items-start gap-3 rounded-xl border px-3 py-3 transition"
:class="template === @js($key) ? 'border-sky-500 bg-sky-50 ring-1 ring-sky-500' : 'border-slate-200 hover:border-slate-300'">
<input type="radio" name="workflow_template" value="{{ $key }}" x-model="template" class="mt-1 text-sky-600">
<span>
<span class="block text-sm font-medium text-slate-800">{{ $template['label'] }}</span>
<span class="block text-xs text-slate-500">{{ $template['description'] ?? '' }}</span>
</span>
</label>
@endforeach
</div>
@error('workflow_template') <p class="mt-1 text-sm text-rose-600">{{ $message }}</p> @enderror
</div>
<div class="grid gap-4 sm:grid-cols-2">
<div>
<label class="block text-sm font-medium text-slate-700">Primary branch</label>
<input type="text" name="branch_name" value="{{ old('branch_name', 'Main Branch') }}" required
class="mt-1 w-full rounded-lg border-slate-300 text-sm">
</div>
<div>
<label class="block text-sm font-medium text-slate-700">Branch phone</label>
<input type="tel" name="branch_phone" value="{{ old('branch_phone') }}"
class="mt-1 w-full rounded-lg border-slate-300 text-sm">
</div>
</div>
<div>
@@ -33,12 +87,6 @@
class="mt-1 w-full rounded-lg border-slate-300 text-sm">
</div>
<div>
<label class="block text-sm font-medium text-slate-700">Branch phone</label>
<input type="tel" name="branch_phone" value="{{ old('branch_phone') }}"
class="mt-1 w-full rounded-lg border-slate-300 text-sm">
</div>
<div>
<label class="block text-sm font-medium text-slate-700">Logo (optional)</label>
<input type="file" name="logo" accept="image/png,image/jpeg,image/webp,image/svg+xml"