feat(payment): confirm appointment and SMS the patient on success

The payment callback handled subscription and sms-wallet types but left
appointment payments pending. Add a TYPE_APPOINTMENT branch that
transitions the booking pending → confirmed (guarded by canTransitionTo,
so an already-expired booking is skipped) and dispatches a confirmation
SMS to the patient's mobile.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
hamed
2026-06-15 18:00:13 +03:30
co-authored by Claude Opus 4.8
parent 089badbb5a
commit a52f412cfc
@@ -16,6 +16,7 @@ use App\Payment\Repository\PaymentRepository;
use App\Payment\Service\CircuitBreakerService;
use App\Shared\Constant\ErrorCodes;
use App\Shared\Controller\BaseController;
use App\Sms\Service\SmsService;
use App\Sms\Service\SmsWalletService;
use App\Subscription\Service\SubscriptionService;
use OpenApi\Attributes as OA;
@@ -44,6 +45,7 @@ class PaymentController extends BaseController
private readonly CircuitBreakerService $circuitBreaker,
private readonly SubscriptionService $subscriptionService,
private readonly SmsWalletService $smsWalletService,
private readonly SmsService $smsService,
private readonly DoctorRepository $doctorRepo,
private readonly ClinicRepository $clinicRepo,
private readonly SiteConfigRepository $configRepo,
@@ -273,6 +275,8 @@ class PaymentController extends BaseController
$this->handleSubscriptionActivation($payment);
} elseif ($payment->getType() === Payment::TYPE_SMS_WALLET) {
$this->handleSmsWalletCharge($payment);
} elseif ($payment->getType() === Payment::TYPE_APPOINTMENT) {
$this->handleAppointmentConfirmation($payment);
}
return $this->redirectToFrontend($payment, true);
@@ -590,6 +594,26 @@ class PaymentController extends BaseController
$this->smsWalletService->charge($wallet, $payment->getAmountRials(), $payment);
}
private function handleAppointmentConfirmation(Payment $payment): void
{
$appointment = $payment->getAppointment();
if ($appointment === null || !$appointment->canTransitionTo(Appointment::STATUS_CONFIRMED)) {
return;
}
$appointment->transitionTo(Appointment::STATUS_CONFIRMED);
$this->appointmentRepo->save($appointment);
$mobile = $appointment->getPatientMobile();
if ($mobile) {
$when = date('Y-m-d H:i', $appointment->getSlotStart());
$this->smsService->dispatchAsync(
$mobile,
sprintf('نوبت شما با %s در تاریخ %s ثبت و تأیید شد.', $appointment->getDoctor()->getName(), $when)
);
}
}
private function handleSubscriptionActivation(Payment $payment): void
{
$meta = $payment->getMetadata() ?? [];