feat: add mobile number change functionality for doctors and clinics

- Implemented PATCH endpoints for changing the login mobile number of doctors and clinics.
- Added ChangeLoginMobileModal component for handling mobile number updates in the UI.
- Updated ClinicsPage and DoctorsPage to include buttons for changing mobile numbers.
- Enhanced AdminApiController to manage mobile number changes with validation.
- Created tests to ensure proper functionality and validation for mobile number changes.
- Updated API documentation to reflect new endpoints and their usage.
This commit is contained in:
hamed
2026-07-25 21:40:38 +03:30
parent 3cc4a59459
commit 50ba7e44ff
13 changed files with 520 additions and 38 deletions
@@ -80,6 +80,15 @@ class PaymentRepository extends ServiceEntityRepository
]);
}
/** پرداخت موفقِ یک نوبت — مبنای تقسیم مالی در لحظهٔ تأیید نوبت. */
public function findSuccessfulByAppointment(Appointment $appointment): ?Payment
{
return $this->findOneBy([
'appointment' => $appointment,
'status' => Payment::STATUS_SUCCESS,
]);
}
/**
* Batch variant of findPendingByAppointment: all pending payments for the
* given appointments in ONE query, keyed by appointment id. Avoids the N+1
+8 -11
View File
@@ -42,7 +42,6 @@ final class PaymentManager
private readonly CommissionService $commissionService,
private readonly \App\Representation\Service\DomainContextResolver $domainResolver,
private readonly JalaliDateService $jalali,
private readonly \App\Appointment\Service\AppointmentConfirmationService $appointmentConfirmation,
private readonly string $appBaseUrl,
) {}
@@ -303,25 +302,23 @@ final class PaymentManager
$this->smsWalletService->deduct($wallet, $payment->getAmountRials(), 'استرداد شارژ کیف پیامک');
}
/**
* پرداخت موفقِ نوبت آنلاین. نوبت **قطعی نمی‌شود**: در وضعیت «ثبت شده» می‌ماند تا
* پزشک/منشی آن را تأیید کند؛ فقط پنجرهٔ انقضای درگاه برداشته می‌شود تا نوبتِ
* پرداخت‌شده منقضی نشود. ساخت پرونده/مراجعه و تقسیم مالی به لحظهٔ تأیید منتقل
* شده است ({@see \App\Appointment\Service\AppointmentConfirmationService}).
*/
private function handleAppointmentConfirmation(Payment $payment): void
{
$appointment = $payment->getAppointment();
if ($appointment === null || !$appointment->canTransitionTo(Appointment::STATUS_CONFIRMED)) {
if ($appointment === null || $appointment->getStatus() !== Appointment::STATUS_PENDING) {
return;
}
$appointment->transitionTo(Appointment::STATUS_CONFIRMED);
$appointment->clearPaymentWindow();
$this->em->persist($appointment);
$this->appointmentConfirmation->onConfirmed($appointment);
$doctor = $appointment->getDoctor();
$this->commissionService->processAppointment(
$payment,
$doctor->getRepresentationId(),
$this->bookingRepresentationIdFor($payment),
$doctor->getId(),
);
$mobile = $appointment->getPatientMobile();
if ($mobile) {
$this->smsService->dispatchTemplate(SmsLog::TAG_PAYMENT, $mobile, [