This commit is contained in:
@@ -205,8 +205,10 @@ no `action`; their JavaScript posts back to the **same creq URL**. So the creq U
|
||||
`destValue=token`, `selectChannel=token`, `authMethod=OOB`, `otpDest=`, `formReqType=SUBMIT`
|
||||
(keep the hidden `creq` / `otpChannels`).
|
||||
3. **POST channel** → the **OTP entry** page (`otpValue` input). Submit `otpValue=<BML token TOTP>`,
|
||||
`formReqType=SUBMIT`. A wrong/expired code re-renders the OTP page with text containing
|
||||
*"incorrect"* / *"expired"* — regenerate the TOTP and retry once.
|
||||
`formReqType=SUBMIT`. A wrong/expired code re-renders the OTP page (still with `otpValue`) and
|
||||
*"The OTP code you entered is incorrect Please try again."* — wait for the next TOTP window,
|
||||
regenerate and retry once. Rejected twice, the payment stops ("The bank rejected the BML token
|
||||
code"). The app also never sends a code with under 5 s left in its window.
|
||||
4. On success the ACS returns a form auto-posting **`cres`** to the Mastercard gateway; the gateway
|
||||
returns a form auto-posting the result (`order.id`, `result=SUCCESS`, …) to
|
||||
**`transactions/mpgsNotification/<id>`**. Follow both so the verdict is recorded.
|
||||
@@ -225,6 +227,23 @@ Poll `next-action` until the recorded verdict surfaces:
|
||||
| `TRANSACTION_CONFIRMED` | Success |
|
||||
| `TRANSACTION_FAILED` | Declined |
|
||||
|
||||
**A decline after 3-D Secure doesn't arrive this way.** In the Ooredoo capture, the card passed
|
||||
3-D Secure (`mpgsNotification` got `result=SUCCESS`, `gatewayRecommendation=PROCEED`) and was then
|
||||
declined for insufficient funds. The browser's `?wait=1` went to `?error=1` instead of the
|
||||
merchant, and the transaction stayed payable: `state` still `QR_CODE_GENERATED`, `hasError: true`,
|
||||
`allowRetry: true`, and a new `paymentErrorHistory` entry:
|
||||
|
||||
```json
|
||||
{"date":"…","vendor":"mpgs","code":"INSUFFICIENT_FUNDS",
|
||||
"reason":"Transaction declined due to insufficient funds",
|
||||
"customerVisibleDescription":"Insufficient funds. Please use another card or payment method."}
|
||||
```
|
||||
|
||||
The same link was then paid successfully after topping up the card. So while polling,
|
||||
`BmlMerchantCardPayClient` also reads the transaction (the load PATCH,
|
||||
`BmlMerchantTxnClient.paymentErrors`) and stops with `customerVisibleDescription` as soon as an
|
||||
entry newer than the ones there before the attempt shows up.
|
||||
|
||||
## 7. Return to the merchant
|
||||
|
||||
The `mpgsNotification` response is a page whose script sends the browser to
|
||||
@@ -240,13 +259,21 @@ GET transaction…/<id>?wait=1
|
||||
|
||||
(FahiPay's is `fahipay.mv/api/bml/gateway/callback/?…state=CONFIRMED`.)
|
||||
|
||||
Ooredoo's callback isn't a redirect: `my.ooredoo.mv/bml/response_new.php?…state=CONFIRMED` is a
|
||||
200 page whose `<body onload="document.forms['wtmpay'].submit()">` posts the result
|
||||
(`order_id`, `bml_transaction_id`, `bml_response=CONFIRMED`, `payment_status=success`, …) on to
|
||||
`www.ooredoo.mv/ooredoo-prod/PaymentGateway/redirect/bml`, which lands on
|
||||
`/payment-status?order_id=…&status=1`. `returnToMerchant` submits such auto-posting forms too
|
||||
(up to 2).
|
||||
|
||||
**This hop is required.** It's how at least Dhiraagu learns it was paid: a test reload that
|
||||
stopped at `TRANSACTION_CONFIRMED` charged the card but never topped up, and opening the
|
||||
`?wait=1` URL in a browser afterwards delivered it. The signature is generated by BML, so the
|
||||
hop can be replayed later from the transaction id alone.
|
||||
|
||||
`BmlMerchantCardPayClient` does it after every confirmed payment (`returnToMerchant`): a browser
|
||||
UA GET that follows the redirects, up to 3 tries, success = the chain ends on a 2xx page. The
|
||||
UA GET that follows the redirects and auto-submitted forms, up to 3 tries, success = the chain
|
||||
ends on a 2xx page. The
|
||||
merchant host may be behind Cloudflare: plain `curl` got a 403 on `dhiraagu.com.mv`, okhttp got
|
||||
through.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user