feat: implement filtered and paginated appointment retrieval for doctors

This commit is contained in:
hamed
2026-07-19 11:41:43 +03:30
parent f1d147f9ef
commit 8420a1a6c2
4 changed files with 279 additions and 8 deletions
@@ -182,6 +182,65 @@ class AppointmentRepository extends ServiceEntityRepository
return $this->findBy($criteria, ['slotStart' => 'ASC']);
}
/**
* Filtered + paginated appointment list for one doctor — backs the doctor
* dashboard filter bar. Kept separate from findByDoctor() so existing
* unfiltered callers keep their plain-array contract.
*
* @param string[] $statuses empty = no status restriction
* @return array{items: Appointment[], total: int}
*/
public function searchByDoctor(
Doctor $doctor,
array $statuses = [],
?Clinic $clinic = null,
?int $from = null,
?int $to = null,
?string $query = null,
?string $serviceUuid = null,
int $page = 1,
int $limit = 20,
): array {
$qb = $this->createQueryBuilder('a')
->join('a.user', 'u')
->where('a.doctor = :doctor')
->setParameter('doctor', $doctor);
if ($statuses !== []) {
$qb->andWhere('a.status IN (:statuses)')->setParameter('statuses', $statuses);
}
// همان محدودسازی محیط که findByDoctor دارد: نوبت مطب شخصی به کلینیک نشت نکند.
if ($clinic !== null) {
$qb->andWhere('a.clinic = :clinic')->setParameter('clinic', $clinic);
}
if ($from !== null) {
$qb->andWhere('a.slotStart >= :from')->setParameter('from', $from);
}
if ($to !== null) {
$qb->andWhere('a.slotStart <= :to')->setParameter('to', $to);
}
if ($serviceUuid !== null && $serviceUuid !== '') {
$qb->join('a.serviceItem', 'si')
->andWhere('si.uuid = :serviceUuid')
->setParameter('serviceUuid', $serviceUuid);
}
// نام/موبایل هم روی فیلدهای خودِ نوبت ذخیره می‌شود و هم روی کاربر؛ هر دو جست‌وجو می‌شوند.
if ($query !== null && trim($query) !== '') {
$qb->andWhere('a.patientName LIKE :q OR a.patientMobile LIKE :q OR u.realName LIKE :q OR u.mobileNumber LIKE :q')
->setParameter('q', '%' . trim($query) . '%');
}
$total = (int) (clone $qb)->select('COUNT(a.id)')->getQuery()->getSingleScalarResult();
$items = $qb->orderBy('a.slotStart', 'ASC')
->setFirstResult(max(0, ($page - 1) * $limit))
->setMaxResults($limit)
->getQuery()
->getResult();
return ['items' => $items, 'total' => $total];
}
/**
* نوبت‌های یک بیمار در یک کلینیک — بر پایهٔ خودِ محیطِ ثبت‌شدهٔ نوبت، تا غیرفعال
* شدنِ بعدیِ پزشک تاریخچه را از پروندهٔ کلینیک حذف نکند.