feat(api): enhance appointment retrieval and add today stats endpoint

This commit is contained in:
hamed
2026-06-11 14:32:10 +03:30
parent 45ee725820
commit 704075770b
2 changed files with 112 additions and 36 deletions
@@ -28,35 +28,35 @@ class MyAppointmentsController extends BaseController
#[IsGranted('IS_AUTHENTICATED_FULLY')]
public function myAppointments(Request $request, #[CurrentUser] User $user): JsonResponse
{
$page = max(1, (int) $request->query->get('page', 1));
$limit = min(100, max(1, (int) $request->query->get('limit', 15)));
$search = trim((string) $request->query->get('search', ''));
$status = trim((string) $request->query->get('status', ''));
$date = trim((string) $request->query->get('date', ''));
$page = max(1, (int) $request->query->get('page', 1));
$limit = min(500, max(1, (int) $request->query->get('limit', 15)));
$search = trim((string) $request->query->get('search', ''));
$status = trim((string) $request->query->get('status', ''));
$date = trim((string) $request->query->get('date', ''));
$doctorUuid = trim((string) $request->query->get('doctor_uuid', ''));
$qb = $this->em->createQueryBuilder()
->select(
'DISTINCT a.uuid, a.slotStart, a.slotEnd, a.status, a.createdAt',
'DISTINCT a.uuid, a.slotStart, a.slotEnd, a.status, a.createdAt, a.version',
'd.uuid as doctor_uuid, d.name as doctor_name',
'u.mobileNumber as patient_mobile, u.realName as patient_name',
'c.name as clinic_name'
'u.mobileNumber as patient_mobile, u.realName as patient_name'
)
->from(Appointment::class, 'a')
->join('a.doctor', 'd')
->join('a.user', 'u')
->leftJoin('App\Clinic\Entity\Clinic', 'c', 'WITH', 'd MEMBER OF c.doctors')
->orderBy('a.slotStart', 'DESC');
->orderBy('a.slotStart', 'ASC');
$roles = $user->getRoles();
if (in_array('ROLE_ADMIN', $roles, true)) {
// Admin voit tout
// Admin sees all
} elseif (in_array('ROLE_CLINIC', $roles, true)) {
$clinic = $this->clinicRepo->findByUser($user);
if ($clinic === null) {
return $this->paginated([], 0, $page, $limit);
}
$qb->andWhere('c = :clinic')
$qb->join('App\Clinic\Entity\Clinic', 'c', 'WITH', 'd MEMBER OF c.doctors')
->andWhere('c = :clinic')
->setParameter('clinic', $clinic);
} elseif (in_array('ROLE_DOCTOR', $roles, true)) {
$doctor = $this->doctorRepo->findByUser($user);
@@ -87,14 +87,15 @@ class MyAppointmentsController extends BaseController
if ($status !== '') {
$qb->andWhere('a.status = :status')->setParameter('status', $status);
}
if ($date !== '') {
$dayStart = strtotime($date . ' 00:00:00');
$dayEnd = strtotime($date . ' 23:59:59');
if ($dayStart && $dayEnd) {
$qb->andWhere('a.slotStart >= :dayStart AND a.slotStart <= :dayEnd')
->setParameter('dayStart', $dayStart)
->setParameter('dayEnd', $dayEnd);
}
if ($date !== '' && preg_match('/^\d{4}-\d{2}-\d{2}$/', $date)) {
$dayStart = (int) strtotime($date . ' 00:00:00');
$dayEnd = (int) strtotime($date . ' 23:59:59');
$qb->andWhere('a.slotStart >= :dayStart AND a.slotStart <= :dayEnd')
->setParameter('dayStart', $dayStart)
->setParameter('dayEnd', $dayEnd);
}
if ($doctorUuid !== '') {
$qb->andWhere('d.uuid = :doctorUuid')->setParameter('doctorUuid', $doctorUuid);
}
$total = (clone $qb)->select('COUNT(a.id)')->getQuery()->getSingleScalarResult();
@@ -106,16 +107,80 @@ class MyAppointmentsController extends BaseController
'uuid' => $a['uuid'],
'patient_name' => $a['patient_name'] ?? '',
'patient_mobile' => $a['patient_mobile'],
'doctor_uuid' => $a['doctor_uuid'],
'doctor_name' => $a['doctor_name'],
'clinic_name' => $a['clinic_name'] ?? null,
'slot_start' => (int) $a['slotStart'],
'slot_end' => (int) $a['slotEnd'],
'appointment_date' => date('Y-m-d', (int) $a['slotStart']),
'appointment_time' => date('H:i', (int) $a['slotStart']),
'slot_start' => (int) $a['slotStart'],
'end_time' => date('H:i', (int) $a['slotEnd']),
'status' => $a['status'],
'amount' => 0,
'version' => (int) $a['version'],
'created_at' => date('c', (int) $a['createdAt']),
], $rows);
return $this->paginated($items, (int) $total, $page, $limit);
}
#[Route('/api/v1/my/appointments/today-stats', methods: ['GET'])]
#[IsGranted('IS_AUTHENTICATED_FULLY')]
public function todayStats(Request $request, #[CurrentUser] User $user): JsonResponse
{
$date = trim((string) $request->query->get('date', date('Y-m-d')));
if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $date)) {
$date = date('Y-m-d');
}
$dayStart = (int) strtotime($date . ' 00:00:00');
$dayEnd = (int) strtotime($date . ' 23:59:59');
$qb = $this->em->createQueryBuilder()
->select('a.status, COUNT(a.id) AS cnt')
->from(Appointment::class, 'a')
->join('a.doctor', 'd')
->where('a.slotStart >= :dayStart AND a.slotStart <= :dayEnd')
->setParameter('dayStart', $dayStart)
->setParameter('dayEnd', $dayEnd)
->groupBy('a.status');
$roles = $user->getRoles();
if (in_array('ROLE_CLINIC', $roles, true)) {
$clinic = $this->clinicRepo->findByUser($user);
if ($clinic) {
$qb->join('App\Clinic\Entity\Clinic', 'c', 'WITH', 'd MEMBER OF c.doctors')
->andWhere('c = :clinic')
->setParameter('clinic', $clinic);
}
} elseif (in_array('ROLE_DOCTOR', $roles, true)) {
$doctor = $this->doctorRepo->findByUser($user);
if ($doctor) {
$qb->andWhere('a.doctor = :doctor')->setParameter('doctor', $doctor);
}
} elseif (in_array('ROLE_SECRETARY', $roles, true)) {
$rel = $this->secretaryRepo->findActiveBySecretary($user);
if ($rel) {
$qb->andWhere('a.doctor = :doctor')->setParameter('doctor', $rel->getDoctor());
}
}
$rows = $qb->getQuery()->getArrayResult();
$byStatus = [];
foreach ($rows as $row) {
$byStatus[$row['status']] = (int) $row['cnt'];
}
$total = array_sum($byStatus);
$completed = ($byStatus['completed'] ?? 0);
$cancelled = ($byStatus['cancelled_by_doctor'] ?? 0)
+ ($byStatus['cancelled_by_user'] ?? 0)
+ ($byStatus['no_show'] ?? 0)
+ ($byStatus['expired'] ?? 0);
$waiting = $total - $completed - $cancelled;
return $this->success([
'total' => $total,
'completed' => $completed,
'waiting' => max(0, $waiting),
'cancelled' => $cancelled,
]);
}
}