# نکات پیاده‌سازی — تسک ۱۵: ماژول پرداخت ## درگاه‌های واقعی پروژه (از کد Drupal) ### ۱. بانک ملت (Mellat) — پروتکل SOAP ```php // وب‌سرویس SOAP با متدهای: // bpPayRequest → شروع تراکنش // bpVerifyRequest → تأیید پرداخت // bpInquiryRequest → استعلام وضعیت // bpSettleRequest → تسویه // bpReversalRequest → برگشت تراکنش // پارامترهای پیکربندی: terminal_id, username, password wsdl_endpoint, gate_url test_mode (boolean) callback_url, callback_url_test ``` ### ۲. SEP (سامان) — درگاه دوم در `sep_payment/src/Plugin/MyPayment/SepPayment.php` پیاده‌سازی شده. ### پیاده‌سازی در Symfony ```php interface PaymentGatewayInterface { public function pay(array $data): array; // { success, ref_id, gateway_url } public function verify(array $callbackData, int $orderId): array; public function refund(array $data): array; } ``` پیکربندی در `.env`: ``` PAYMENT_GATEWAY=mellat # mellat | sep MELLAT_TERMINAL_ID=... MELLAT_USERNAME=... MELLAT_PASSWORD=... MELLAT_TEST_MODE=true ``` ## وضعیت پرداخت (از کد واقعی) ``` pending → بعد از ایجاد پرداخت received → بعد از تأیید موفق (نه "paid"!) failed → پرداخت ناموفق ``` ⚠️ در Drupal status موفق `received` است نه `paid`. ## شرط ایجاد پرداخت **appointment باید status=`waiting_for_payment` داشته باشد.** اگر status متفاوت باشد → 400 error. ## قیمت از Config (نه Request) ```php // مبلغ از پیکربندی خوانده می‌شود، نه از request body! $amount = $config->get('payment.settings')['price']; ``` → در `.env` یا config: ``` APPOINTMENT_PRICE=500000 ``` ## frontend_address پرداخت دارای `frontend_address` است — URL فرانت برای redirect بعد از پرداخت. این به representation مرتبط است (سیستم multi-tenant). ## Callback Mellat ``` POST /payment/callback/mellat RefId=... ResCode=0 SaleOrderId=... SaleReferenceId=... جریان: 1. ResCode === '0' باشد 2. bpVerifyRequest → اگر موفق نبود → bpInquiryRequest → اگر موفق نبود → bpReversalRequest 3. bpSettleRequest (resCode='0' یا '45' = قبلاً تسویه شده) 4. appointment.status = confirmed 5. payment.status = received 6. payment.ref_id = SaleReferenceId ``` ## Idempotency اگر callback دوبار بیاید، دوبار process نشود: ```php if ($payment->getStatus() === 'received') { return; // قبلاً پردازش شده } ``` ## مجوزها ``` POST /payment → احراز هویت‌شده GET /payment/{uuid} → owner یا ROLE_ADMIN یا دکتر مرتبط GET /my-payments → owner GET/POST callback → عمومی (درگاه پرداخت) ```