forked from thijooree/android
update docs
This commit is contained in:
+1
-1
@@ -17,5 +17,5 @@
|
||||
| [bmlapi/](bmlapi/README.md) | Bank of Maldives — hybrid web/OAuth login, dashboard, transfers, cards, QR payments, tap-to-pay |
|
||||
| [mibapi/](mibapi/README.md) | MIB Faisanet — Blowfish-encrypted API + WebView session, accounts, transfers, contacts |
|
||||
| [fahipayapi/](fahipayapi/README.md) | Fahipay digital wallet — login, balance, history, contacts |
|
||||
| [dhiraaguapi/](dhiraaguapi/README.md) | Dhiraagu Easy Pay — number lookup for reload / bill pay |
|
||||
| [dhiraaguapi/](dhiraaguapi/README.md) | Dhiraagu Easy Pay / Easy TopUp — number lookup, reload by BML card |
|
||||
| [ooredooapi/](ooredooapi/README.md) | Ooredoo Quick Pay — number validation for Raastas / bill pay |
|
||||
|
||||
@@ -73,6 +73,8 @@ POST <ACS creq url> otpValue=<token TOTP> → auto-POST form (cres → gateway)
|
||||
POST <gateway callback> cres → auto-POST form (→ mpgsNotification)
|
||||
POST transactions/mpgsNotification/<id> → records the verdict
|
||||
POST …next-action POLL → TRANSACTION_CONFIRMED
|
||||
GET transaction…/<id>?wait=1 → 302 merchant redirectUrl (?…&state=CONFIRMED&signature=…)
|
||||
→ 302 merchant receipt page
|
||||
```
|
||||
|
||||
---
|
||||
@@ -223,8 +225,30 @@ Poll `next-action` until the recorded verdict surfaces:
|
||||
| `TRANSACTION_CONFIRMED` | Success |
|
||||
| `TRANSACTION_FAILED` | Declined |
|
||||
|
||||
The merchant's own backend is also notified out-of-band (e.g.
|
||||
`fahipay.mv/api/bml/gateway/callback/?…state=CONFIRMED`).
|
||||
## 7. Return to the merchant
|
||||
|
||||
The `mpgsNotification` response is a page whose script sends the browser to
|
||||
`https://transaction.merchants.bankofmaldives.com.mv/<id>?wait=1`. Once the transaction is
|
||||
confirmed, that 302s to the merchant's `redirectUrl` with a BML-signed result, then on to the
|
||||
merchant's own receipt page:
|
||||
|
||||
```
|
||||
GET transaction…/<id>?wait=1
|
||||
→ 302 https://www.dhiraagu.com.mv/api/dhiraagu-bml-response.aspx?transactionId=<id>&state=CONFIRMED&signature=<sha1>
|
||||
→ 302 https://www.dhiraagu.com.mv/services/reload-receipt?pyid=<paymentId>
|
||||
```
|
||||
|
||||
(FahiPay's is `fahipay.mv/api/bml/gateway/callback/?…state=CONFIRMED`.)
|
||||
|
||||
**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
|
||||
merchant host may be behind Cloudflare: plain `curl` got a 403 on `dhiraagu.com.mv`, okhttp got
|
||||
through.
|
||||
|
||||
---
|
||||
|
||||
@@ -243,6 +267,7 @@ learn of breakage from a failed live payment.
|
||||
| **Merchant detection** | BML adds other card providers (UnionPay, Apple/Google Pay); non-`mpgs` card provider | Misroute to the wrong flow |
|
||||
| **`window.appData` parsing** | Key moved/obfuscated or made dynamically signed | No `pomeloJsKey` |
|
||||
| **Double-charge** | Confirm poll times out but the charge went through | Retry risks paying twice |
|
||||
| **Return to merchant** | The merchant's `redirectUrl` host blocks the client (Cloudflare) or is down | Charged but not delivered — `Success(merchantNotified = false)`, the app toasts the BML transaction id; opening `…/<id>?wait=1` in a browser delivers it |
|
||||
|
||||
**Maintenance:** re-capture a HAR whenever any party updates; expect to touch the ACS form parser
|
||||
most often; the flow is effectively untestable in CI (no deterministic 3-D Secure double). Keep the
|
||||
|
||||
@@ -0,0 +1,175 @@
|
||||
# Reload (Easy TopUp, paid by BML card)
|
||||
|
||||
Top up a Dhiraagu prepaid number through the dhiraagu.com.mv **Easy TopUp** page. Dhiraagu only
|
||||
builds the order: the money moves on a **BML Merchant Services transaction** that Dhiraagu creates
|
||||
for it, which is then paid exactly like any card-only BML merchant link
|
||||
([BML API → Merchant Card Payment](../bmlapi/16-card-payment.md)).
|
||||
|
||||
Reconstructed from `docs/dhiraaguapi/tmp/dhiraagu_reload_gateway.md` (a Firefox HAR).
|
||||
|
||||
---
|
||||
|
||||
## Flow overview
|
||||
|
||||
```
|
||||
GET /services/easy-topup → nonce #1
|
||||
POST cart&act=recharge (nonce #1) → cartId
|
||||
GET /services/payment-v2?cartid=<cartId> → nonce #2
|
||||
POST merchant&act=form (nonce #2) → BML gateway's merchantId
|
||||
POST payment&act=create (nonce #2) → paymentId, oid
|
||||
POST bml&act=createV2 (nonce #2) → BML transaction url ──┐
|
||||
│
|
||||
── from here: the BML card-only merchant flow ── │
|
||||
GET transaction.merchants…/<id>/paynow ←─────────────────────────────┘
|
||||
… Pomelo tokenise, next-action, Wibmo 3-D Secure, MPGS … → TRANSACTION_CONFIRMED
|
||||
GET transaction.merchants…/<id>?wait=1 → 302 dhiraagu-bml-response.aspx (tops up)
|
||||
→ 302 /services/reload-receipt
|
||||
```
|
||||
|
||||
After the payment the browser is sent `transaction…/<id>?wait=1` →
|
||||
`dhiraagu-bml-response.aspx?transactionId=<id>&state=CONFIRMED&signature=…` →
|
||||
`/services/reload-receipt?pyid=<paymentId>`. **This is what makes Dhiraagu top up the number** —
|
||||
a payment that stopped at BML's `TRANSACTION_CONFIRMED` was charged but not delivered until that
|
||||
URL was opened. The card flow follows it for every merchant, see
|
||||
[BML API → Return to the merchant](../bmlapi/16-card-payment.md#7-return-to-the-merchant).
|
||||
|
||||
**Recovering a stuck reload:** open `https://transaction.merchants.bankofmaldives.com.mv/<id>?wait=1`
|
||||
in a browser. BML signs the callback, so the transaction id is all that's needed. (`curl` gets a
|
||||
Cloudflare 403 on the Dhiraagu hop; a browser works.)
|
||||
|
||||
---
|
||||
|
||||
## Common
|
||||
|
||||
All API calls are `POST https://www.dhiraagu.com.mv/api/sdk-dhr-webapi.ashx?website_id=CA2BB809-3A22-485B-A518-DA6B6DE653A5&sub=<sub>&act=<act>`
|
||||
with a JSON body and these headers:
|
||||
|
||||
| Header | Value |
|
||||
|---|---|
|
||||
| `User-Agent` | a browser UA (same as [Number Lookup](01-number-lookup.md)) |
|
||||
| `Content-Type` | `application/json` |
|
||||
| `X-Requested-With` | `XMLHttpRequest` |
|
||||
| `Origin` | `https://www.dhiraagu.com.mv` |
|
||||
| `nonce` | `var nonce = "…"` from the page that makes the call |
|
||||
|
||||
Every response is `{"respStatus":"OK","resp":…}` on success.
|
||||
|
||||
Each page has its own nonce: the cart call uses the Easy TopUp page's, the rest use the payment
|
||||
page's.
|
||||
|
||||
---
|
||||
|
||||
## 1. Settings (optional)
|
||||
|
||||
`GET …&sub=setting&act=reload` — the page reads its limits from here. Thijooree hardcodes them.
|
||||
|
||||
```json
|
||||
{"gstRate":0.08,"dailyLimit":3000,
|
||||
"amountLimit":{"min":20,"max":1080,"message":"Enter a whole number amount between MVR 20 and 1000"},
|
||||
"reloadPerDay":{"easyTopUp":4,"myAccount":6}, …}
|
||||
```
|
||||
|
||||
| Rule | Value |
|
||||
|---|---|
|
||||
| Amount | whole MVR, **20 – 1000** (the message says 1000; `max` says 1080 — Thijooree uses 1000) |
|
||||
| GST | 8%, **included** in the amount |
|
||||
| Per day | MVR 3000, 4 Easy TopUps |
|
||||
|
||||
GST, as the page works it out: `gst = round2(amount × 0.08 / 1.08)`, credited `amount − gst`
|
||||
(MVR 20 → GST 1.48, credited 18.52).
|
||||
|
||||
---
|
||||
|
||||
## 2. Cart
|
||||
|
||||
`sub=cart&act=recharge`, nonce from `GET /services/easy-topup`.
|
||||
|
||||
```json
|
||||
{"formId":2,"serviceNumber":"7XXXXXX","amount":20,"amountGST":1.48,"amountRecharge":18.52,
|
||||
"gstRate":0.08,"memberId":"","memberName":"","memberNId":"","customerId":"","customerCode":"","version":2}
|
||||
```
|
||||
```json
|
||||
{"cartId":"002773ed-…","formId":2,"cartAmount":20.00,"cartExpiry":"…",
|
||||
"paymentUrl":"https://www.dhiraagu.com.mv/services/payment-v2?cartid=002773ed-…", …}
|
||||
```
|
||||
|
||||
The page also calls `sub=dhiraaguIO&act=infoSubscriberStatus` (`{"number"}`) before this, to show
|
||||
the number's status and balance. Thijooree skips it — [Number Lookup](01-number-lookup.md) has
|
||||
already confirmed a prepaid number.
|
||||
|
||||
---
|
||||
|
||||
## 3. Payment gateway
|
||||
|
||||
`sub=merchant&act=form`, `{"formId":2}`, nonce from `GET /services/payment-v2?cartid=<cartId>`.
|
||||
Lists the gateways; **`gatewayId: 1` is Bank of Maldives** (2 = MIB, 3 = DhiraaguPay).
|
||||
|
||||
```json
|
||||
[{"merchantId":"98de333c-…","merchantId2":"3f5cf6b7-…","formId":2,"gatewayId":1,
|
||||
"gatewayName":"Bank of Maldives", …}, …]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. Payment
|
||||
|
||||
`sub=payment&act=create`
|
||||
|
||||
```json
|
||||
{"formId":2,"cartId":"<cartId>","gatewayId":1,"dhiraaguPayNumber":"","amount":"20.00",
|
||||
"paymentMerchantId":"<BML merchantId>","memberId":"","tokenize":"","paymentType":"",
|
||||
"recurringFrequency":"","bmlTokenId":""}
|
||||
```
|
||||
```json
|
||||
{"paymentId":"3ea4351b-…","oid":"ET20260006911381","gatewayId":1,"amount":20.00,"paymentStatus":0, …}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 5. BML transaction
|
||||
|
||||
`sub=bml&act=createV2`, `{"paymentId":"<paymentId>"}`. Returns the BML Merchant Services
|
||||
transaction (amounts in cents):
|
||||
|
||||
```json
|
||||
{"state":"INITIATED","amount":2000,"currency":"MVR","localId":"ET20260006911381",
|
||||
"url":"https://transaction.merchants.bankofmaldives.com.mv/6abfec7afd7f4a4360fc1df4",
|
||||
"redirectUrl":"https://www.dhiraagu.com.mv/api/dhiraagu-bml-response.aspx",
|
||||
"expires":"…(10 min)…","customerReference":"WebApp - Topup", …}
|
||||
```
|
||||
|
||||
The 24-hex id at the end of `url` is the transaction. Its `/paynow` page offers **UnionPay +
|
||||
MPGS cards only, no BML Pay**, so it's paid by card + 3-D Secure.
|
||||
|
||||
---
|
||||
|
||||
## Reload record
|
||||
|
||||
`sub=reload&act=list`, `{"paymentId"}`, nonce from the receipt page — what the receipt page shows:
|
||||
|
||||
```json
|
||||
{"oid":"ET20260006911381","transId":"<BML txn id>","serviceNumber":"7XXXXXX",
|
||||
"amountPay":20.00,"amountTopup":18.52,"amountGST":1.48,
|
||||
"paidStatus":1,"topupStatus":1,"reloadStatusDesc":"Successful", …}
|
||||
```
|
||||
|
||||
Not used by Thijooree yet.
|
||||
|
||||
---
|
||||
|
||||
## Cloudflare
|
||||
|
||||
`www.dhiraagu.com.mv` is behind Cloudflare. The browser capture carries a `cf_clearance` cookie,
|
||||
but [Number Lookup](01-number-lookup.md) already works from the app with plain okhttp and a browser
|
||||
UA, so these calls are made the same way.
|
||||
|
||||
---
|
||||
|
||||
|
||||
|
||||
---
|
||||
|
||||
**Related:** [Number Lookup](01-number-lookup.md) · [BML Merchant Card Payment](../bmlapi/16-card-payment.md) ·
|
||||
App side: [Transfer Flows](../thijooree/20-transfer-flows.md#carrier-services-by-bml-card)
|
||||
|
||||
[← Number Lookup](01-number-lookup.md)
|
||||
@@ -96,6 +96,7 @@ The API only returns a valid result for numbers currently on the Dhiraagu networ
|
||||
| # | File | Description |
|
||||
|---|---|---|
|
||||
| 1 | [Number Lookup](01-number-lookup.md) | Validate a Dhiraagu number and determine account type |
|
||||
| 2 | [Reload](02-reload.md) | Easy TopUp order → BML merchant transaction, paid by card |
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Transfer
|
||||
|
||||
The transfer screen initiates account-to-account fund transfers. It supports MIB, BML, and Fahipay as source banks and handles all bank-specific authentication and OTP steps.
|
||||
The transfer screen initiates account-to-account fund transfers and phone payments. It supports MIB, BML, Fahipay and M-Faisa as sources and handles all bank-specific authentication and OTP steps. A phone number can also be paid as a carrier service (reload, Raastas, bill pay) from the Fahipay wallet or, for Dhiraagu Reload, a verified BML card.
|
||||
|
||||
---
|
||||
|
||||
@@ -38,11 +38,12 @@ A dropdown lists all visible accounts parsed via `AccountListParser.from(acc)?.b
|
||||
|
||||
## Recipient Entry
|
||||
|
||||
The user can specify a recipient in three ways:
|
||||
The user can specify a recipient in these ways:
|
||||
|
||||
1. **Manual entry** — type an account number directly
|
||||
2. **Contact picker** — opens `ContactPickerSheetFragment` to select a saved contact
|
||||
1. **Manual entry** — type an account number or phone number directly
|
||||
2. **Contact picker** — opens `ContactPickerSheetFragment` to select a saved contact. A Fahipay favourite opens as its payout service straight away
|
||||
3. **QR scan** — launches [QrScannerActivity](25-qr-scanner.md); a PayMV QR result pre-fills the account number, amount, and remarks; a BML ebanking / pay.bml URL switches the form into [BML QR merchant payment](20-transfer-flows.md#bml-qr-merchant-payment-flow) mode
|
||||
4. **BML Merchant Services transaction ID or link** — paid through BML Pay (QR flow) or, for card-only merchants, a verified card ([Card Verification & Merchant Card Pay](29-card-verification-and-merchant-card-pay.md))
|
||||
|
||||
---
|
||||
|
||||
@@ -64,10 +65,22 @@ After the user finishes entering a recipient account number, the app calls the s
|
||||
|
||||
- **MIB**: account name lookup via MIB API
|
||||
- **BML**: beneficiary lookup via BML API
|
||||
- **Fahipay**: account name resolution via Fahipay API
|
||||
- **Fahipay**: phone numbers only — the Dhiraagu / Ooredoo carrier lookup decides which payout services apply
|
||||
|
||||
The resolved name is displayed below the account number field for the user to confirm.
|
||||
|
||||
### Phone numbers — Transfer Type picker
|
||||
|
||||
A phone number searched with no source yet (or from a BML card that can pay by card) is looked up every way it can be paid, in parallel: Favara (MIB / BML), and the carrier lookup when the user has a Fahipay wallet or a verified BML card. Each result is a **transfer type**:
|
||||
|
||||
| Type | Example | Pays from |
|
||||
|---|---|---|
|
||||
| Favara Transfer | bank account behind the number | MIB or BML account |
|
||||
| Fahipay service | Raastas, Ooredoo Bill Pay, Dhiraagu Reload, Dhiraagu Bill Pay | Fahipay wallet |
|
||||
| Card service | Dhiraagu Reload (BML badge) | Verified BML card |
|
||||
|
||||
One option is applied straight away; with more, a picker opens and Send stays disabled until one is chosen. Picking a type also picks a source that can pay it. Fahipay and card services clear and disable the Remarks field and apply their own amount rules (minimum, maximum, whole amounts, 8% GST note). Details: [Transfer Flows → Transfer Type picker](20-transfer-flows.md#transfer-type-picker).
|
||||
|
||||
---
|
||||
|
||||
## Biometric Gate
|
||||
@@ -100,18 +113,33 @@ When the source is a BML USD account and the destination is a MIB account but no
|
||||
5. Re-submits with OTP
|
||||
6. On success, shows `TransferReceiptFragment`
|
||||
|
||||
### Fahipay Transfer
|
||||
### Fahipay Payout (reload, Raastas, bill pay)
|
||||
|
||||
1. Validates fields
|
||||
2. (If biometric gate) prompts biometrics
|
||||
3. Submits via Fahipay API using stored `authID` + session cookie
|
||||
4. On success, shows `TransferReceiptFragment`
|
||||
1. Checks the amount against the picked service's rules
|
||||
2. Confirm dialog (with the GST note for Raastas), then the biometric gate if enabled
|
||||
3. One POST to the service's Fahipay payment endpoint ([Fahipay API → Payments](../fahipayapi/09-payments.md))
|
||||
4. On success, the result shows inside the dialog (no receipt page yet), then the form clears
|
||||
|
||||
See [Transfer Flows → Fahipay source](20-transfer-flows.md#fahipay-source).
|
||||
|
||||
### Carrier Service by BML Card (Dhiraagu Reload)
|
||||
|
||||
1. Checks the amount against Dhiraagu's rules (MVR 20–1000, whole amounts, 8% GST included)
|
||||
2. A "Processing..." dialog shows while Dhiraagu creates the order and its BML merchant transaction ([Dhiraagu API → Reload](../dhiraaguapi/02-reload.md))
|
||||
3. From there it is the card-only merchant flow: the same confirm dialog and warning, biometric gate, card + 3-D Secure payment, and the return to Dhiraagu (`?wait=1`) that tops the number up
|
||||
4. On success, the result shows inside the dialog; if Dhiraagu couldn't be notified, a toast gives the BML transaction id
|
||||
|
||||
See [Transfer Flows → Carrier services by BML card](20-transfer-flows.md#carrier-services-by-bml-card).
|
||||
|
||||
### BML Merchant Payment (QR / card-only link)
|
||||
|
||||
A BML QR, or a BML Merchant Services link whose merchant takes BML Pay, is paid from a BML card through the QR flow. A card-only merchant link is paid with a verified card (Pomelo + 3-D Secure), followed by the return to the merchant. Neither saves a receipt. See [Transfer Flows → BML QR Merchant Payment Flow](20-transfer-flows.md#bml-qr-merchant-payment-flow) and [Card Verification & Merchant Card Pay](29-card-verification-and-merchant-card-pay.md).
|
||||
|
||||
---
|
||||
|
||||
## Transfer Receipt
|
||||
|
||||
On success the fragment navigates to `TransferReceiptFragment` passing the completed transfer details.
|
||||
On success of a bank transfer (MIB, BML, M-Faisa) the fragment navigates to `TransferReceiptFragment` passing the completed transfer details. Fahipay payouts, card services and merchant payments show their result inside the confirm dialog instead.
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -49,11 +49,13 @@ Each option is a `TransferType` (`ui/home/transfer/TransferType.kt`):
|
||||
|---|---|---|---|
|
||||
| `Favara(info)` | Favara Transfer | `favara_logo` | MIB or BML account |
|
||||
| `Fahipay(service, ownerName)` | the service's label, e.g. Raastas | `FahipayService.iconRes`: `ooredoo_logo` / `dhiraagu_logo` | Fahipay wallet |
|
||||
| `Card(service, ownerName, cards)` | the service's label, e.g. Dhiraagu Reload | `CardPayoutService.iconRes`, with a BML badge | One of `cards`: verified BML cards that can pay by card (see [Carrier services by BML card](#carrier-services-by-bml-card)) |
|
||||
|
||||
Picking an option also picks the source (`TransferFragment.applyTransferType`). If the selected source can't pay that type, Thijooree switches it:
|
||||
|
||||
- **Favara:** the default account, if it's MIB or BML. Otherwise the source is cleared and the user is asked to pick one.
|
||||
- **Fahipay:** the user's Fahipay wallet.
|
||||
- **Card:** the default card, if it's one of the type's cards. Otherwise the first of them.
|
||||
|
||||
Then the recipient card is filled in. The options, the number they were looked up for and the pick are kept in `TransferDraft`. If the view is recreated while the popup is still unanswered, it opens again.
|
||||
|
||||
@@ -64,9 +66,11 @@ The options are dropped when the "To" number is edited, the recipient is cleared
|
||||
Two lookups run in parallel:
|
||||
|
||||
- **Favara / IPS lookup.** Uses any logged-in MIB or BML session. The default account's bank goes first, the other is the fallback.
|
||||
- **Carrier lookup** (see Fahipay source below). Only runs when the user has a Fahipay wallet.
|
||||
- **Carrier lookup** (`CarrierLookup.query`, see Fahipay source below). Only runs when the user has a Fahipay wallet or a BML card that can pay by card. One lookup feeds both.
|
||||
|
||||
Everything that resolves is offered as a transfer type. Favara comes first, then the Fahipay services. If nothing resolves, the Favara lookup's error is shown as a toast.
|
||||
Everything that resolves is offered as a transfer type. Favara comes first, then the Fahipay services, then the card services.
|
||||
|
||||
The same lookup runs when the source is already a BML card that can pay by card and a phone number is searched. If nothing resolves, the Favara lookup's error is shown as a toast.
|
||||
|
||||
Any other input with no source selected falls back to the default account as the source, and then the normal lookup for that bank runs.
|
||||
|
||||
@@ -144,6 +148,49 @@ When the amount breaks a rule, the error replaces the helper text.
|
||||
|
||||
None of the Fahipay services take a reference. Picking one clears the Reference field and disables it, the same way BML merchant QR payments do. Clearing the service turns the field back on.
|
||||
|
||||
### Carrier services by BML card
|
||||
|
||||
A carrier service can also be paid with a verified BML card, through the carrier's own website
|
||||
and its BML merchant gateway, instead of the Fahipay wallet. Only **Dhiraagu Reload** so far
|
||||
(`CardPayoutService`, `ui/home/transfer/CardPayoutTransferHandler.kt`).
|
||||
|
||||
**Which cards.** A card qualifies when it's verified and its BML login has an OTP seed, the same
|
||||
rule as card-only merchant links (`BmlVerifiedCards`, see
|
||||
[Card Verification & Merchant Card Pay](29-card-verification-and-merchant-card-pay.md)). The
|
||||
type remembers those cards (`TransferType.Card.cards`). Picking a card that isn't one of them
|
||||
drops the pick, like any other source that can't pay the picked type.
|
||||
|
||||
**Which services.**
|
||||
|
||||
| Carrier result | Service |
|
||||
|---|---|
|
||||
| Dhiraagu `RELOAD` | Dhiraagu Reload |
|
||||
|
||||
**Amount rules.** The carrier website's, not Fahipay's. They're checked the same way, through
|
||||
the shared `PayoutAmountField`:
|
||||
|
||||
| Service | Min (MVR) | Max (MVR) | Decimals | GST |
|
||||
|---|---|---|---|---|
|
||||
| Dhiraagu Reload | 20 | 1,000 | no | 8%, included (credit = amount − round2(amount × 0.08 / 1.08)) |
|
||||
|
||||
**Reference.** None. The field is cleared and disabled, as for the Fahipay services.
|
||||
|
||||
**Sending.** The only part that differs from paying a card-only BML merchant link is where the
|
||||
BML transaction comes from:
|
||||
|
||||
1. `CardPayoutTransferHandler.submit()` has the carrier create it for the number and amount
|
||||
(`DhiraaguReloadClient.createBmlTransaction`, see [Dhiraagu API → Reload](../dhiraaguapi/02-reload.md)).
|
||||
That takes a few round trips, so the payment's "Processing..." box shows meanwhile
|
||||
(`TransferFragment.showProcessingDialog`) and closes before the confirm dialog opens.
|
||||
2. Its payment page is loaded (`BmlMerchantTxnClient.fetchPayPage`). If it doesn't take cards, or
|
||||
its amount isn't the one typed, the payment stops with a toast.
|
||||
3. The page goes to `BmlTransferHandler.confirmCardMerchant`, so from here it's the merchant-link
|
||||
card flow: the same confirm dialog and warning, biometric gate, Pomelo + 3-D Secure payment,
|
||||
and success / failure handling.
|
||||
|
||||
Nothing is charged before the confirm dialog. A cancelled confirm leaves an unpaid Dhiraagu order,
|
||||
which expires on its own.
|
||||
|
||||
### BML source
|
||||
|
||||
1. If the input type is `MIB_ACCOUNT`, calls `BmlValidateClient.verifyMibAccount()`.
|
||||
@@ -208,6 +255,13 @@ Source: Fahipay
|
||||
FAHIPAY_TRANSFER, RAASTAS, OOREDOO_BILL, DHIRAAGU_RELOAD, DHIRAAGU_BILL
|
||||
```
|
||||
|
||||
```
|
||||
Transfer type: Card (verified BML card)
|
||||
|
||||
└── Carrier creates a BML merchant transaction → card-only merchant flow
|
||||
DHIRAAGU_RELOAD
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Rejected Combinations
|
||||
@@ -336,6 +390,7 @@ The transfer button is only enabled when all of the following are true:
|
||||
- Amount is greater than `0`
|
||||
- If transfer types are on offer, one has been picked
|
||||
- For a Fahipay service, the amount meets that service's rules (see [Amount rules](#amount-rules))
|
||||
- For a carrier service by card, the amount meets that service's rules (see [Carrier services by BML card](#carrier-services-by-bml-card))
|
||||
- No connectivity error for `NO_INTERNET` or for the source bank
|
||||
|
||||
---
|
||||
|
||||
@@ -7,7 +7,9 @@ Two linked features:
|
||||
full card details (PAN, expiry, CVV) encrypted on-device.
|
||||
2. **Merchant card payment** — on [Transfer](07-transfer.md), a BML Merchant Services transaction ID
|
||||
whose merchant has **no BML Pay** is paid with a verified card via the Pomelo + 3-D Secure flow
|
||||
([BML API → Merchant Card Payment](../bmlapi/16-card-payment.md)).
|
||||
([BML API → Merchant Card Payment](../bmlapi/16-card-payment.md)). The same flow pays
|
||||
[carrier services by BML card](20-transfer-flows.md#carrier-services-by-bml-card) (Dhiraagu
|
||||
Reload), once the carrier has created the transaction.
|
||||
|
||||
> ⚠️ The merchant card flow is scraped browser/ACS traffic, not a stable API. Storing the CVV is a
|
||||
> security/PCI liability. See the API doc's
|
||||
@@ -106,23 +108,28 @@ into the Transfer screen rather than a one-off dialog, mirroring the BML QR merc
|
||||
and empties the amount and re-enables remarks.
|
||||
|
||||
A card is only offered when it is **both** verified **and** belongs to a BML login the app has an
|
||||
OTP seed for (`verifiedCardCandidates`, `:428`; `isCardVerified`, `:463`) — the 3-D Secure step
|
||||
needs that seed.
|
||||
OTP seed for (`BmlVerifiedCards.payable` / `isPayable`, `ui/home/transfer/BmlVerifiedCards.kt`) —
|
||||
the 3-D Secure step needs that seed.
|
||||
|
||||
### Send
|
||||
|
||||
`submitCardPayment` (`:496`) → `confirmCardMerchant` (`:506`) shows the shared transfer confirm
|
||||
dialog (biometric-gated), then `executeCardMerchant` (`:534`) runs, off the main thread:
|
||||
`submitCardPayment` → `confirmCardMerchant` shows the shared transfer confirm dialog
|
||||
(biometric-gated), then `executeCardMerchant` runs, off the main thread.
|
||||
`CardPayoutTransferHandler` calls `confirmCardMerchant` directly with the page of the
|
||||
transaction a carrier created:
|
||||
|
||||
```
|
||||
BmlMerchantCardPayClient().pay(page, card) { Totp.generate(otpSeed) }
|
||||
```
|
||||
|
||||
where `card` comes from `VerifiedCardStore` (expiry split `MM/YY` → month/year) and `otpSeed` is the
|
||||
card's BML login seed. The client (`api/bml/BmlMerchantCardPayClient.kt`) performs the whole
|
||||
where `card` and `otpSeed` come from `BmlVerifiedCards.load` — the `VerifiedCardStore` entry
|
||||
(expiry split `MM/YY` → month/year) and the card's BML login seed. The client (`api/bml/BmlMerchantCardPayClient.kt`) performs the whole
|
||||
Pomelo + MPGS + Wibmo 3-D Secure sequence — feeding the BML token TOTP into the ACS OTP form
|
||||
automatically, retrying once if the first code expired. Outcome is shown in the shared
|
||||
processing/success dialog; failures surface as a toast.
|
||||
automatically, retrying once if the first code expired. Once BML confirms, it loads
|
||||
`<id>?wait=1` and follows the redirects to the merchant, which is how the merchant learns it was
|
||||
paid (Dhiraagu doesn't top up without it). Outcome is shown in the shared processing/success
|
||||
dialog; failures surface as a toast. If the merchant couldn't be reached, success also toasts
|
||||
the merchant name and BML transaction id (`bml_card_pay_merchant_not_notified`).
|
||||
|
||||
### Key assumption
|
||||
|
||||
@@ -145,6 +152,8 @@ another login/person, or a card whose 3-D Secure only offers SMS/email OTP.
|
||||
| `api/bml/BmlMerchantTxnClient.kt` | `fetchPayPage` (merchant-type detection), `announceBrowser`, QR payload |
|
||||
| `api/bml/BmlMerchantCardPayClient.kt` | Pomelo tokenise + 3-D Secure card payment |
|
||||
| `ui/home/transfer/BmlTransferHandler.kt` | On-screen card merchant mode + payment |
|
||||
| `ui/home/transfer/BmlVerifiedCards.kt` | Which cards can pay by card; loads their details |
|
||||
| `ui/home/transfer/CardPayoutTransferHandler.kt` | Carrier services by card: carrier creates the transaction, then `confirmCardMerchant` |
|
||||
| `ui/home/TransferFragment.kt` | Transaction-ID lookup + routing |
|
||||
|
||||
---
|
||||
|
||||
@@ -15,7 +15,7 @@ Documentation for app-specific logic — UI flows, routing decisions, and busine
|
||||
| [04 — Accounts](04-accounts.md) | Account list grouped display, AccountsAdapter, profile images, quick-transfer shortcut |
|
||||
| [05 — Account History](05-account-history.md) | Paginated transaction history, search, infinite scroll |
|
||||
| [06 — Transfer History](06-transfer-history.md) | Multi-bank merged transfer history, parallel loading |
|
||||
| [07 — Transfer](07-transfer.md) | Recipient lookup, MIB/BML/Fahipay transfer flows, QR, biometric gate, BML OTP |
|
||||
| [07 — Transfer](07-transfer.md) | Recipient lookup, transfer type picker, MIB/BML/Fahipay transfers, Fahipay payouts, Dhiraagu Reload by BML card, QR, biometric gate, BML OTP |
|
||||
| [08 — Contacts](08-contacts.md) | Contact list, add/edit/delete, categories, contact picker sheet |
|
||||
| [09 — Activities](09-activities.md) | Local transfer log, TransferReceiptFragment, share/save receipt |
|
||||
| [10 — OTP Screen](10-otp-screen.md) | TOTP display, real-time countdown, enrolled bank authenticators |
|
||||
@@ -34,7 +34,7 @@ Documentation for app-specific logic — UI flows, routing decisions, and busine
|
||||
| [26 — Circular Nav](26-circular-nav.md) | Radial 4-slot wheel UI with lock centre |
|
||||
| [27 — Settings: Notifications](27-settings-notifications.md) | Opt-in flow: permission → battery opt → service start |
|
||||
| [28 — Settings: About](28-settings-about.md) | Version, T&Cs, donate buttons |
|
||||
| [29 — Card Verification & Merchant Card Pay](29-card-verification-and-merchant-card-pay.md) | NFC/manual card verification + card-only BML merchant payment |
|
||||
| [29 — Card Verification & Merchant Card Pay](29-card-verification-and-merchant-card-pay.md) | NFC/manual card verification + card-only BML merchant payment (links and carrier services), return to merchant |
|
||||
|
||||
## Reference
|
||||
|
||||
@@ -42,5 +42,5 @@ Documentation for app-specific logic — UI flows, routing decisions, and busine
|
||||
|---|---|
|
||||
| [18 — PayMV QR Format](18-paymv-qr-format.md) | Decimal TLV encoding, all tags, CRC-16, per-bank references, real samples, Fahipay WIP, parsing reference |
|
||||
| [19 — Parsers](19-parsers.md) | Account display parser architecture — how raw bank API data is normalised into a unified `AccountListDisplay` model |
|
||||
| [20 — Transfer Flows](20-transfer-flows.md) | TransferFragment entry points, recipient lookup, transfer type routing, rejected combinations, BML business OTP flow, BML QR merchant payments |
|
||||
| [20 — Transfer Flows](20-transfer-flows.md) | TransferFragment entry points, recipient lookup, transfer type picker, Fahipay services, carrier services by BML card, routing, rejected combinations, BML business OTP flow, BML QR merchant payments |
|
||||
| [AI Security Audit](AI_SECURITY_CHECK.md) | Full source security audit — credential storage, network layer, manifest, data privacy |
|
||||
|
||||
Reference in New Issue
Block a user