Ship commercial Dentistry suite with odontogram and treatment plans.
Deploy Ladill Care / deploy (push) Failing after 36s

Replace placeholder clinical forms with patient-level FDI charting, multi-visit plans, procedure-to-bill linking, imaging, reports, and demo seed data.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
isaacclad
2026-07-18 16:33:34 +00:00
co-authored by Cursor
parent a00a8249ad
commit 0edd653187
37 changed files with 2906 additions and 35 deletions
@@ -0,0 +1,83 @@
<?php
namespace App\Services\Care\Dentistry;
use App\Models\DentalImage;
use App\Models\Organization;
use App\Models\PatientAttachment;
use App\Models\Visit;
use App\Services\Care\AuditLogger;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
class DentalImagingService
{
/**
* @param array{modality: string, tooth_codes?: list<string>, caption?: ?string, bill_fee?: bool} $meta
*/
public function upload(
Organization $organization,
Visit $visit,
UploadedFile $file,
array $meta,
string $ownerRef,
?string $actorRef = null,
): DentalImage {
$visit->loadMissing('patient');
$modality = (string) ($meta['modality'] ?? '');
if (! array_key_exists($modality, DentalCatalog::modalities())) {
throw new \InvalidArgumentException("Invalid imaging modality [{$modality}].");
}
$toothCodes = array_values(array_filter(
$meta['tooth_codes'] ?? [],
fn ($c) => DentalCatalog::isValidToothCode((string) $c),
));
$path = $file->store("care/patients/{$visit->patient_id}/dental", 'public');
$attachment = PatientAttachment::create([
'owner_ref' => $ownerRef,
'patient_id' => $visit->patient_id,
'file_path' => $path,
'original_name' => $file->getClientOriginalName(),
'mime_type' => $file->getMimeType(),
'document_type' => 'dental_imaging_'.$modality,
'uploaded_by' => $actorRef ?? $ownerRef,
]);
$image = DentalImage::create([
'owner_ref' => $ownerRef,
'organization_id' => $organization->id,
'patient_id' => $visit->patient_id,
'visit_id' => $visit->id,
'patient_attachment_id' => $attachment->id,
'modality' => $modality,
'tooth_codes' => $toothCodes,
'caption' => $meta['caption'] ?? null,
'uploaded_by' => $actorRef ?? $ownerRef,
'captured_at' => now(),
]);
AuditLogger::record(
$ownerRef,
'dental.image.uploaded',
$organization->id,
$actorRef,
DentalImage::class,
$image->id,
);
return $image->fresh('attachment');
}
public function url(DentalImage $image): ?string
{
$path = $image->attachment?->file_path;
if (! $path) {
return null;
}
return Storage::disk('public')->url($path);
}
}