physiotherapy-clinic/app/Services/AppointmentService.php

106 lines
3.3 KiB
PHP

<?php
namespace App\Services;
use App\Models\Appointment;
use App\Models\Patient;
use App\Models\User;
use Carbon\Carbon;
class AppointmentService
{
/**
* Check for conflicting appointments for a therapist
*/
public function hasConflict(int $therapistId, Carbon $startTime, int $duration, ?int $excludeId = null): bool
{
$endTime = $startTime->copy()->addMinutes($duration);
$query = Appointment::where('user_id', $therapistId)
->whereIn('status', ['scheduled', 'confirmed', 'in_progress'])
->where(function ($q) use ($startTime, $endTime) {
// Check if any appointment overlaps with the requested time
$q->whereBetween('appointment_date', [$startTime, $endTime->copy()->subSecond()])
->orWhereRaw("datetime(appointment_date, '+' || duration_minutes || ' minutes') BETWEEN ? AND ?", [$startTime, $endTime]);
});
if ($excludeId) {
$query->where('id', '!=', $excludeId);
}
return $query->exists();
}
/**
* Check for patient double-booking
*/
public function hasPatientConflict(int $patientId, Carbon $startTime, int $duration, ?int $excludeId = null): bool
{
$endTime = $startTime->copy()->addMinutes($duration);
$query = Appointment::where('patient_id', $patientId)
->whereIn('status', ['scheduled', 'confirmed', 'in_progress'])
->whereBetween('appointment_date', [$startTime, $endTime->copy()->subSecond()]);
if ($excludeId) {
$query->where('id', '!=', $excludeId);
}
return $query->exists();
}
/**
* Get available time slots for a therapist on a given date
*/
public function getAvailableSlots(int $therapistId, string $date, int $duration = 60): array
{
$workingHours = ['09:00', '17:00']; // 9 AM to 5 PM
$slotInterval = 30; // minutes
$slots = [];
$start = Carbon::parse("$date {$workingHours[0]}");
$end = Carbon::parse("$date {$workingHours[1]}");
while ($start->lt($end)) {
$slotEnd = $start->copy()->addMinutes($duration);
if ($slotEnd->lte($end) && !$this->hasConflict($therapistId, $start, $duration)) {
$slots[] = $start->format('H:i');
}
$start->addMinutes($slotInterval);
}
return $slots;
}
/**
* Get calendar feed for a date range
*/
public function getCalendarFeed(string $startDate, string $endDate, ?int $therapistId = null): array
{
$query = Appointment::with(['patient', 'user'])
->whereBetween('appointment_date', [$startDate, $endDate]);
if ($therapistId) {
$query->where('user_id', $therapistId);
}
return $query->orderBy('appointment_date')->get()->toArray();
}
/**
* Consume a package session for an appointment
*/
public function consumePackageSession(Appointment $appointment, int $patientPackageId): bool
{
$patientPackage = \App\Models\PatientPackage::find($patientPackageId);
if (!$patientPackage || $patientPackage->patient_id !== $appointment->patient_id) {
return false;
}
return $patientPackage->consumeSession();
}
}