*/ public function recallsForPatient(Organization $organization, Patient $patient, string $ownerRef, int $limit = 30): Collection { return DentalRecall::owned($ownerRef) ->where('organization_id', $organization->id) ->where('patient_id', $patient->id) ->orderBy('due_on') ->limit($limit) ->get(); } /** * @param array{due_on: string, reason?: ?string, notes?: ?string} $data */ public function schedule( Organization $organization, Patient $patient, string $ownerRef, array $data, ?string $actorRef = null, ): DentalRecall { $dueOn = (string) ($data['due_on'] ?? ''); if ($dueOn === '') { throw new \InvalidArgumentException('Recall due date is required.'); } $status = DentalRecall::STATUS_SCHEDULED; if (now()->startOfDay()->gte(\Carbon\Carbon::parse($dueOn)->startOfDay())) { $status = DentalRecall::STATUS_DUE; } $recall = DentalRecall::create([ 'owner_ref' => $ownerRef, 'organization_id' => $organization->id, 'patient_id' => $patient->id, 'due_on' => $dueOn, 'reason' => $data['reason'] ?? null, 'status' => $status, 'notes' => $data['notes'] ?? null, 'created_by' => $actorRef ?? $ownerRef, ]); AuditLogger::record($ownerRef, 'dental.recall.scheduled', $organization->id, $actorRef, DentalRecall::class, $recall->id); return $recall; } public function complete( DentalRecall $recall, string $ownerRef, ?Visit $visit = null, ?string $actorRef = null, ): DentalRecall { $recall->update([ 'status' => DentalRecall::STATUS_COMPLETED, 'linked_visit_id' => $visit?->id ?? $recall->linked_visit_id, ]); AuditLogger::record($ownerRef, 'dental.recall.completed', $recall->organization_id, $actorRef, DentalRecall::class, $recall->id); return $recall->fresh(); } public function cancel(DentalRecall $recall, string $ownerRef, ?string $actorRef = null): DentalRecall { $recall->update(['status' => DentalRecall::STATUS_CANCELLED]); AuditLogger::record($ownerRef, 'dental.recall.cancelled', $recall->organization_id, $actorRef, DentalRecall::class, $recall->id); return $recall->fresh(); } /** * @return Collection */ public function openForPatient(Organization $organization, Patient $patient, string $ownerRef): Collection { return DentalRecall::owned($ownerRef) ->where('organization_id', $organization->id) ->where('patient_id', $patient->id) ->whereIn('status', [DentalRecall::STATUS_SCHEDULED, DentalRecall::STATUS_DUE]) ->orderBy('due_on') ->get(); } }