feat: add patient appointment interface and endpoints
- Introduced `PatientAppointment` interface to define appointment structure. - Implemented `findByUserAndDoctorIds` method in `AppointmentRepository` to retrieve appointments for a user filtered by doctor IDs. - Added `acceptedDoctorIdsByClinic` method in `ClinicDoctorInvitationRepository` to get accepted doctor IDs for a clinic. - Created new endpoint in `PatientController` to fetch appointments for a patient, ensuring only relevant doctors' appointments are displayed.
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -502,6 +502,17 @@ export interface SessionServiceLine {
|
|||||||
created_at: number;
|
created_at: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface PatientAppointment {
|
||||||
|
uuid: string;
|
||||||
|
starts_at: number;
|
||||||
|
ends_at: number | null;
|
||||||
|
status: string;
|
||||||
|
doctor_name: string | null;
|
||||||
|
service_name: string | null;
|
||||||
|
price_rials: number | null;
|
||||||
|
created_at: number;
|
||||||
|
}
|
||||||
|
|
||||||
export interface PatientSession {
|
export interface PatientSession {
|
||||||
uuid: string;
|
uuid: string;
|
||||||
record_uuid: string;
|
record_uuid: string;
|
||||||
|
|||||||
@@ -128,6 +128,29 @@ class AppointmentRepository extends ServiceEntityRepository
|
|||||||
return $this->findBy($criteria, ['slotStart' => 'DESC']);
|
return $this->findBy($criteria, ['slotStart' => 'DESC']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* نوبتهای یک بیمار (کاربر) که با پزشک(های) مشخص گرفته شدهاند — برای نمایش در
|
||||||
|
* پروندهٔ بیمار. اگر لیست پزشک خالی باشد، آرایهٔ خالی برمیگرداند.
|
||||||
|
*
|
||||||
|
* @param int[] $doctorIds
|
||||||
|
* @return Appointment[]
|
||||||
|
*/
|
||||||
|
public function findByUserAndDoctorIds(User $user, array $doctorIds): array
|
||||||
|
{
|
||||||
|
if ($doctorIds === []) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->createQueryBuilder('a')
|
||||||
|
->where('a.user = :user')
|
||||||
|
->andWhere('a.doctor IN (:doctorIds)')
|
||||||
|
->setParameter('user', $user)
|
||||||
|
->setParameter('doctorIds', $doctorIds)
|
||||||
|
->orderBy('a.slotStart', 'DESC')
|
||||||
|
->getQuery()
|
||||||
|
->getResult();
|
||||||
|
}
|
||||||
|
|
||||||
/** Whether the user had a confirmed appointment with this doctor within the last $sinceDays days. */
|
/** Whether the user had a confirmed appointment with this doctor within the last $sinceDays days. */
|
||||||
public function hasRecentConfirmed(User $user, Doctor $doctor, int $sinceDays = 30): bool
|
public function hasRecentConfirmed(User $user, Doctor $doctor, int $sinceDays = 30): bool
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -46,6 +46,26 @@ class ClinicDoctorInvitationRepository extends ServiceEntityRepository
|
|||||||
->getResult();
|
->getResult();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* شناسهٔ پزشکانی که دعوت پذیرفتهشده در این کلینیک دارند.
|
||||||
|
*
|
||||||
|
* @return int[]
|
||||||
|
*/
|
||||||
|
public function acceptedDoctorIdsByClinic(int $clinicId): array
|
||||||
|
{
|
||||||
|
$rows = $this->createQueryBuilder('i')
|
||||||
|
->select('IDENTITY(i.doctor) AS doctorId')
|
||||||
|
->where('i.clinic = :clinicId')
|
||||||
|
->andWhere('i.status = :accepted')
|
||||||
|
->andWhere('i.doctor IS NOT NULL')
|
||||||
|
->setParameter('clinicId', $clinicId)
|
||||||
|
->setParameter('accepted', ClinicDoctorInvitation::STATUS_ACCEPTED)
|
||||||
|
->getQuery()
|
||||||
|
->getScalarResult();
|
||||||
|
|
||||||
|
return array_map(static fn(array $r) => (int) $r['doctorId'], $rows);
|
||||||
|
}
|
||||||
|
|
||||||
public function save(ClinicDoctorInvitation $invitation): void
|
public function save(ClinicDoctorInvitation $invitation): void
|
||||||
{
|
{
|
||||||
$em = $this->getEntityManager();
|
$em = $this->getEntityManager();
|
||||||
|
|||||||
@@ -47,6 +47,8 @@ class PatientController extends BaseController
|
|||||||
private readonly InvoiceService $invoiceService,
|
private readonly InvoiceService $invoiceService,
|
||||||
private readonly ClaimService $claimService,
|
private readonly ClaimService $claimService,
|
||||||
private readonly InvoiceRepository $invoiceRepo,
|
private readonly InvoiceRepository $invoiceRepo,
|
||||||
|
private readonly \App\Appointment\Repository\AppointmentRepository $appointmentRepo,
|
||||||
|
private readonly \App\ClinicInvitation\Repository\ClinicDoctorInvitationRepository $invitationRepo,
|
||||||
private readonly LoggerInterface $logger,
|
private readonly LoggerInterface $logger,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
@@ -318,6 +320,37 @@ class PatientController extends BaseController
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[Route('/api/v1/patient/{uuid}/appointments', methods: ['GET'])]
|
||||||
|
public function appointments(string $uuid, #[CurrentUser] User $user): JsonResponse
|
||||||
|
{
|
||||||
|
[$entityType, $entityId] = $this->resolveEntity($user);
|
||||||
|
$this->assertPatientGate($entityType, $entityId);
|
||||||
|
|
||||||
|
$record = $this->recordRepo->findByUuid($uuid);
|
||||||
|
if ($record === null || !$this->ownsRecord($record, $entityType, $entityId)) {
|
||||||
|
return $this->error(ErrorCodes::ERR_PATIENT_NOT_FOUND, ErrorCodes::message(ErrorCodes::ERR_PATIENT_NOT_FOUND), 404);
|
||||||
|
}
|
||||||
|
|
||||||
|
// نوبتهای این بیمار فقط با پزشک(های) همین ارائهدهنده نمایش داده میشوند تا
|
||||||
|
// نوبتهای او با کلینیکهای دیگر نشت نکند.
|
||||||
|
$doctorIds = $entityType === 'doctor'
|
||||||
|
? [$entityId]
|
||||||
|
: $this->invitationRepo->acceptedDoctorIdsByClinic($entityId);
|
||||||
|
|
||||||
|
$appointments = $this->appointmentRepo->findByUserAndDoctorIds($record->getUser(), $doctorIds);
|
||||||
|
|
||||||
|
return $this->success(array_map(fn(\App\Appointment\Entity\Appointment $a) => [
|
||||||
|
'uuid' => $a->getUuid(),
|
||||||
|
'starts_at' => $a->getSlotStart(),
|
||||||
|
'ends_at' => $a->getSlotEnd(),
|
||||||
|
'status' => $a->getStatus(),
|
||||||
|
'doctor_name' => $a->getDoctor()->getName(),
|
||||||
|
'service_name' => null,
|
||||||
|
'price_rials' => null,
|
||||||
|
'created_at' => $a->getSlotStart(),
|
||||||
|
], $appointments));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* خروجی session بههمراه خلاصهی صورتحساب: uuid فاکتور (در صورت وجود) و
|
* خروجی session بههمراه خلاصهی صورتحساب: uuid فاکتور (در صورت وجود) و
|
||||||
* ماندهی بدهیِ سهم بیمار. اگر session تسویه شده باشد (payment_method != pending)
|
* ماندهی بدهیِ سهم بیمار. اگر session تسویه شده باشد (payment_method != pending)
|
||||||
|
|||||||
Reference in New Issue
Block a user