Activate Care workflows across check-in and financial clearance.
Deploy Ladill Care / deploy (push) Failing after 1m9s
Deploy Ladill Care / deploy (push) Failing after 1m9s
Enforce service-queue gates, cashier settlements, and clinical stage progression so patient journeys cannot bypass configured payment or authorization rules. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -6,6 +6,8 @@ use App\Models\Appointment;
|
||||
use App\Models\Organization;
|
||||
use App\Models\Patient;
|
||||
use App\Models\Visit;
|
||||
use App\Services\Care\Workflow\WorkflowQueueGate;
|
||||
use App\Services\Care\Workflow\WorkflowStageCompletionService;
|
||||
use App\Services\Meet\MeetClient;
|
||||
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
@@ -20,8 +22,15 @@ class AppointmentService
|
||||
protected VisitService $visits,
|
||||
protected AppointmentPatientNotifier $notifier,
|
||||
protected CareQueueBridge $queueBridge,
|
||||
protected WorkflowQueueGate $workflowGate,
|
||||
protected WorkflowStageCompletionService $workflowCompletion,
|
||||
) {}
|
||||
|
||||
public function queueContextFor(Organization $organization, Appointment $appointment): string
|
||||
{
|
||||
return $this->queueBridge->contextForAppointment($organization, $appointment);
|
||||
}
|
||||
|
||||
public function queryForOrganization(string $ownerRef, int $organizationId): Builder
|
||||
{
|
||||
return Appointment::owned($ownerRef)->where('organization_id', $organizationId);
|
||||
@@ -67,7 +76,7 @@ class AppointmentService
|
||||
$query = Appointment::owned($ownerRef)
|
||||
->where('branch_id', $branchId)
|
||||
->whereIn('status', [Appointment::STATUS_WAITING, Appointment::STATUS_CHECKED_IN])
|
||||
->with(['patient', 'practitioner'])
|
||||
->with(['patient', 'practitioner', 'visit', 'organization'])
|
||||
->orderBy('queue_position')
|
||||
->orderBy('waiting_at')
|
||||
->orderBy('checked_in_at');
|
||||
@@ -78,7 +87,20 @@ class AppointmentService
|
||||
});
|
||||
}
|
||||
|
||||
return $query->get();
|
||||
return $query->get()
|
||||
->filter(function (Appointment $appointment) {
|
||||
$organization = $appointment->organization;
|
||||
if (! $organization) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->workflowGate->canRelease(
|
||||
$organization,
|
||||
$appointment->visit,
|
||||
$this->queueBridge->contextForAppointment($organization, $appointment),
|
||||
);
|
||||
})
|
||||
->values();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -218,6 +240,15 @@ class AppointmentService
|
||||
$appointment->update(['visit_id' => $visit->id, 'checked_in_at' => now()]);
|
||||
}
|
||||
|
||||
$appointment->loadMissing(['organization', 'visit']);
|
||||
if ($appointment->organization && ! $this->workflowGate->canRelease(
|
||||
$appointment->organization,
|
||||
$appointment->visit,
|
||||
$this->queueBridge->contextForAppointment($appointment->organization, $appointment),
|
||||
)) {
|
||||
throw new InvalidArgumentException('This visit has not reached a financially cleared consultation stage.');
|
||||
}
|
||||
|
||||
$appointment->visit->update(['status' => Visit::STATUS_IN_PROGRESS]);
|
||||
|
||||
$appointment->update([
|
||||
@@ -245,9 +276,11 @@ class AppointmentService
|
||||
'completed_at' => now(),
|
||||
]);
|
||||
|
||||
if ($appointment->visit) {
|
||||
$this->visits->complete($appointment->visit, $ownerRef, $actorRef);
|
||||
}
|
||||
$visit = $appointment->visit;
|
||||
$organization = $appointment->organization;
|
||||
$workflowEnabled = $visit
|
||||
&& $organization
|
||||
&& $this->workflowGate->enabled($organization);
|
||||
|
||||
AuditLogger::record($ownerRef, 'appointment.completed', $appointment->organization_id, $actorRef, Appointment::class, $appointment->id);
|
||||
|
||||
@@ -256,6 +289,18 @@ class AppointmentService
|
||||
$this->queueBridge->complete($appointment->organization, $appointment);
|
||||
}
|
||||
|
||||
if ($workflowEnabled && $visit && $organization) {
|
||||
$this->workflowCompletion->complete(
|
||||
$organization,
|
||||
$visit,
|
||||
$this->queueBridge->contextForAppointment($organization, $appointment),
|
||||
$ownerRef,
|
||||
$actorRef,
|
||||
);
|
||||
} elseif ($visit) {
|
||||
$this->visits->complete($visit, $ownerRef, $actorRef);
|
||||
}
|
||||
|
||||
return $appointment->fresh(['patient', 'practitioner', 'visit']);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user