Initial commit - Physiotherapy Clinic Management System
This commit is contained in:
commit
dbb326f2cc
300 files changed
+144285
No files matched your search
@@ -0,0 +1,105 @@
|
||||
<?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();
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user