feat(payment): canceled status, manageable origin allowlist, CORS subdomains
Unify and harden the payment flow (same API for the main site and all consumer sites; per-client difference is only frontend_address). - Payment gains STATUS_CANCELED. Gateways distinguish user-cancel from failure (Mellat ResCode=17, SEP CanceledByUser, mock cancel=1) via a new PaymentVerifyResult::canceled flag; callback sets canceled vs failed and skips the circuit-breaker on cancel. - Expiry job now cancels the pending payment when a booking lapses (AppointmentExpiryService + PaymentRepository::findPendingByAppointment). - frontend_address allowlist is read from the payment_allowed_frontend_hosts site setting (manageable via PATCH /api/v1/admin/settings), falling back to the ALLOWED_FRONTEND_HOSTS env var — so a new consumer site needs no code change. - .env: broaden CORS_ALLOW_ORIGIN to city subdomains (*.localhost / *.clinic-pro.ddev.site) and add yazd-nobat.localhost to ALLOWED_FRONTEND_HOSTS. - Update docs/api/payment.md and docs/api/admin.md. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -4,10 +4,15 @@ namespace App\Appointment\Service;
|
||||
|
||||
use App\Appointment\Entity\Appointment;
|
||||
use App\Appointment\Repository\AppointmentRepository;
|
||||
use App\Payment\Entity\Payment;
|
||||
use App\Payment\Repository\PaymentRepository;
|
||||
|
||||
class AppointmentExpiryService
|
||||
{
|
||||
public function __construct(private readonly AppointmentRepository $appointmentRepo) {}
|
||||
public function __construct(
|
||||
private readonly AppointmentRepository $appointmentRepo,
|
||||
private readonly PaymentRepository $paymentRepo,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Expire pending bookings whose payment window has lapsed or whose slot
|
||||
@@ -28,6 +33,13 @@ class AppointmentExpiryService
|
||||
foreach ($expired as $appointment) {
|
||||
$appointment->transitionTo(Appointment::STATUS_EXPIRED);
|
||||
$this->appointmentRepo->save($appointment, false);
|
||||
|
||||
$payment = $this->paymentRepo->findPendingByAppointment($appointment);
|
||||
if ($payment !== null) {
|
||||
$payment->setStatus(Payment::STATUS_CANCELED);
|
||||
$this->paymentRepo->save($payment, false);
|
||||
}
|
||||
|
||||
$count++;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user