Files
ladill-care/app/Services/Care/CareFeatures.php
T
isaaccladandCursor 86bfce1e17
Deploy Ladill Care / deploy (push) Failing after 45s
Add workflow-centric patient journey with financial gates.
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>
2026-07-17 20:47:33 +00:00

92 lines
2.7 KiB
PHP

<?php
namespace App\Services\Care;
use App\Models\AssessmentTemplate;
use App\Models\Organization;
use Database\Seeders\AssessmentTemplateSeeder;
use Database\Seeders\ClinicalPathwaySeeder;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\Schema;
/**
* Product rollout flags stored under organization settings.rollout.*
* Distinct from PlanService entitlements (lab/pharmacy/billing plan features).
*/
class CareFeatures
{
public const ASSESSMENTS_ENGINE = 'assessments_engine';
public const PATHWAY_SUGGESTIONS = 'pathway_suggestions';
public const ASSESSMENT_REQUIRED_ON_COMPLETE = 'assessment_required_on_complete';
/** Workflow-centric patient journey + financial gates (opt-in). */
public const WORKFLOW_ENGINE = 'workflow_engine';
/** Enforce financial gates (block gated stages until obligations clear). */
public const FINANCIAL_GATES = 'financial_gates';
/**
* Flags that default ON when unset (opt-out). Others default OFF (opt-in).
*
* @var list<string>
*/
protected array $defaultOn = [
self::ASSESSMENTS_ENGINE,
];
public function enabled(Organization $organization, string $flag): bool
{
$settings = $organization->settings ?? [];
$rollout = is_array($settings['rollout'] ?? null) ? $settings['rollout'] : [];
if (array_key_exists($flag, $rollout)) {
return (bool) $rollout[$flag];
}
return in_array($flag, $this->defaultOn, true);
}
/**
* @param array<string, mixed> $flags
*/
public function setFlags(Organization $organization, array $flags): Organization
{
$settings = $organization->settings ?? [];
$rollout = is_array($settings['rollout'] ?? null) ? $settings['rollout'] : [];
$settings['rollout'] = array_merge($rollout, $flags);
$organization->settings = $settings;
$organization->save();
return $organization->fresh();
}
/**
* Ensure platform assessment/pathway catalog exists (idempotent seed).
* Call when the engine is enabled so consult/patient UI has templates.
*/
public function ensureAssessmentCatalog(): void
{
if (! Schema::hasTable('care_assessment_templates')) {
return;
}
if (AssessmentTemplate::query()->whereNull('organization_id')->exists()) {
return;
}
Artisan::call('db:seed', [
'--class' => AssessmentTemplateSeeder::class,
'--force' => true,
]);
if (Schema::hasTable('care_clinical_pathways')) {
Artisan::call('db:seed', [
'--class' => ClinicalPathwaySeeder::class,
'--force' => true,
]);
}
}
}