feat(payment): unify payment callback endpoint for all gateways and types
This commit is contained in:
+27
-14
@@ -58,7 +58,7 @@
|
||||
|
||||
**کمیسیون دامنهمحور (post-action):** نمایندهی مبدأ از `payment.frontend_address` با `DomainContextResolver` تعیین میشود؛ کمیسیون (نوبت و اشتراک) فقط وقتی ثبت میشود که این نماینده فعال باشد **و** پزشک/کلینیک موضوع خرید `representation_id` همان نماینده را داشته باشد — جزئیات در `docs/api/representation.md` §قانون کمیسیون دامنهمحور.
|
||||
|
||||
**یکدستیِ typeها:** هر سه نوع (`appointment`/`subscription`/`sms_wallet`) از همان `GET /payment/pay/{orderId}` عبور میکنند؛ `PaymentManager::callbackUrl()` پیشوند callback را بر اساس `type` انتخاب میکند. POST این endpointها فقط `Payment` pending میسازد و `pay_url` برمیگرداند (نه `redirect_url`).
|
||||
**یکدستیِ typeها:** هر سه نوع (`appointment`/`subscription`/`sms_wallet`) از همان `GET /payment/pay/{orderId}` عبور میکنند و روی همان یک `POST|GET /api/v1/payment/callback` برمیگردند؛ `PaymentManager::callbackUrl()` دیگر بر اساس `type` شاخه نمیزند. POST این endpointها فقط `Payment` pending میسازد و `pay_url` برمیگرداند (نه `redirect_url`).
|
||||
|
||||
**افزودن درگاه جدید (Open/Closed):** یک کلاس جدید implements `PaymentGatewayInterface` بساز، در `GatewayFactory::$gateways` + `LABELS` ثبت کن. `PaymentController`/`PaymentManager` تغییر نمیکنند.
|
||||
|
||||
@@ -268,23 +268,37 @@ Initiate payment for an appointment. Returns a redirect URL to the payment gatew
|
||||
|
||||
---
|
||||
|
||||
## POST `/api/v1/payment/callback/{gateway}`
|
||||
## GET `/api/v1/payment/callback/{gateway}`
|
||||
## POST `/api/v1/payment/callback`
|
||||
## GET `/api/v1/payment/callback`
|
||||
|
||||
Payment gateway callback. Called by the bank after user completes (or cancels) payment. هر درگاه callback مخصوص خودش را دارد؛ URL آن هنگام `initiate` از `APP_BASE_URL` ساخته میشود:
|
||||
Payment gateway callback. Called by the bank after user completes (or cancels) payment.
|
||||
|
||||
**یک آدرس برای همه.** همهٔ درگاهها (`mellat`، `sep`، `mock`) و همهٔ نوعهای پرداخت
|
||||
(`appointment`، `subscription`، `sms_wallet`) روی همین یک مسیر برمیگردند؛ درگاه و سفارش
|
||||
بهصورت query param میروند. URL هنگام `initiate` در `PaymentManager::callbackUrl()` از
|
||||
`APP_BASE_URL` و ثابت `PaymentManager::CALLBACK_PATH` ساخته میشود:
|
||||
|
||||
```
|
||||
{APP_BASE_URL}/api/v1/payment/callback/{gateway}?order_id={orderId}
|
||||
{APP_BASE_URL}/api/v1/payment/callback?gateway={gateway}&order_id={orderId}
|
||||
```
|
||||
|
||||
دلیل: مسیر ثابت میماند، پس آدرسِ ثبتشده در پنل پذیرندگی بانک با اضافهشدن درگاه یا نوع
|
||||
پرداخت جدید عوض نمیشود.
|
||||
|
||||
> **Breaking change.** دو مسیر قدیمی حذف شدهاند و `404` میدهند:
|
||||
> `POST|GET /api/v1/payment/callback/{gateway}` و
|
||||
> `POST|GET /api/v1/subscription-payment/callback/{gateway}`.
|
||||
> آدرس ثبتشده در پنل ملت و سپ باید به مسیر جدید بهروز شود.
|
||||
|
||||
**نکته IPG ملت:** طبق راهنمای درگاه ملت، `callBackUrl` باید روی **دامنهٔ ثبتشدهٔ پذیرنده** باشد و **IP مجاز نیست** (در غیر این صورت کد پاسخ `62` — «مسیر back call در دامنهٔ ثبتشده نیست»). بنابراین `APP_BASE_URL` در پروداکشن باید دقیقاً `https://clinic-pro.ir` (دامنهٔ ثبتشده نزد ملت/شاپرک) باشد.
|
||||
|
||||
**Permission:** `PUBLIC`. **نکتهٔ مهم:** درگاههای **ملت و سپ** نتیجه را با **ریدایرکتِ مرورگرِ کاربر** (POST/GET) برمیگردانند، نه server-to-server؛ پس IP دریافتی، IPِ کاربر است و **allowlist شاپرک اعمال نمیشود** (برای `gateway ∈ {mellat, sep}` و نیز `test_mode`). در غیر این صورت هر callback واقعی — از جمله «لغو» توسط کاربر — با «دسترسی غیرمجاز» رد میشد. امنیت از طریق **چک ضد-دستکاری** (`RefId==gateway_token`، `SaleOrderId==payment.id`) و **verify سمت بانک** در `PaymentManager` تأمین میشود. `isAllowedCallbackIp` فقط برای درگاههای آیندهٔ server-to-server معنی دارد.
|
||||
|
||||
### Path Parameters
|
||||
| Param | Type | Description |
|
||||
|-------|------|-------------|
|
||||
| `gateway` | string | `mellat` or `sep` |
|
||||
### Query Parameters
|
||||
| Param | Type | Required | Description |
|
||||
|-------|------|----------|-------------|
|
||||
| `order_id` | string | yes | شناسهٔ سفارش (`ORD-…`)؛ در نبودش `ResNum` خوانده میشود |
|
||||
| `gateway` | string | no | `mellat` \| `sep` \| `mock`. در نبودش از فیلد `gateway` همان رکورد پرداخت خوانده میشود |
|
||||
|
||||
### Request (varies by gateway)
|
||||
**Mellat POST fields:**
|
||||
@@ -350,7 +364,7 @@ Initiate a subscription / wallet top-up payment (not tied to a specific appointm
|
||||
}
|
||||
```
|
||||
|
||||
> مثل appointment: کلاینت مرورگر را به `pay_url` هدایت میکند؛ init درگاه در `GET /api/v1/payment/pay/{orderId}` انجام میشود (نه در این POST). Callback این نوع به `/api/v1/subscription-payment/callback/` میرود.
|
||||
> مثل appointment: کلاینت مرورگر را به `pay_url` هدایت میکند؛ init درگاه در `GET /api/v1/payment/pay/{orderId}` انجام میشود (نه در این POST). Callback این نوع هم به همان `/api/v1/payment/callback` میرود.
|
||||
|
||||
### Errors
|
||||
| Code | HTTP | Description |
|
||||
@@ -371,11 +385,10 @@ Initiate a subscription / wallet top-up payment (not tied to a specific appointm
|
||||
|
||||
---
|
||||
|
||||
## POST/GET `/api/v1/subscription-payment/callback/{gateway}`
|
||||
## ~~POST/GET `/api/v1/subscription-payment/callback/{gateway}`~~ — حذف شد
|
||||
|
||||
Callback for subscription payments. Same behavior as appointment callback but credits wallet instead.
|
||||
|
||||
**Permission:** `PUBLIC`
|
||||
پرداخت اشتراک callback اختصاصی ندارد. از [`/api/v1/payment/callback`](#post-apiv1paymentcallback)
|
||||
استفاده کنید؛ نوع پرداخت از خودِ رکورد `Payment` خوانده میشود.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -168,9 +168,11 @@
|
||||
|
||||
---
|
||||
|
||||
## GET /api/v1/subscription-payment/callback/{gateway}
|
||||
## POST|GET /api/v1/payment/callback
|
||||
|
||||
callback درگاه پرداخت — پس از پرداخت موفق، `ClinicSubscription` به صورت خودکار ایجاد میشود (بر اساس `period_uuid` ذخیرهشده در metadata پرداخت).
|
||||
callback مشترک همهٔ درگاهها و همهٔ نوعهای پرداخت — پس از پرداخت موفق، `ClinicSubscription` به صورت خودکار ایجاد میشود (بر اساس `period_uuid` ذخیرهشده در metadata پرداخت).
|
||||
|
||||
مسیر اختصاصی قبلی `/api/v1/subscription-payment/callback/{gateway}` حذف شده و `404` میدهد. قرارداد کامل: [payment.md](payment.md#post-apiv1paymentcallback).
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user