diff --git a/docs/README.md b/docs/README.md index f480427..6dcf2d9 100644 --- a/docs/README.md +++ b/docs/README.md @@ -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 | diff --git a/docs/bmlapi/16-card-payment.md b/docs/bmlapi/16-card-payment.md index 25f0c70..227bbb7 100644 --- a/docs/bmlapi/16-card-payment.md +++ b/docs/bmlapi/16-card-payment.md @@ -73,6 +73,8 @@ POST otpValue= → auto-POST form (cres → gateway) POST cres → auto-POST form (→ mpgsNotification) POST transactions/mpgsNotification/ → records the verdict POST …next-action POLL → TRANSACTION_CONFIRMED +GET transaction…/?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/?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…/?wait=1 +→ 302 https://www.dhiraagu.com.mv/api/dhiraagu-bml-response.aspx?transactionId=&state=CONFIRMED&signature= +→ 302 https://www.dhiraagu.com.mv/services/reload-receipt?pyid= +``` + +(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 `…/?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 diff --git a/docs/dhiraaguapi/02-reload.md b/docs/dhiraaguapi/02-reload.md new file mode 100644 index 0000000..a9ddf6e --- /dev/null +++ b/docs/dhiraaguapi/02-reload.md @@ -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= → 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…//paynow ←─────────────────────────────┘ +… Pomelo tokenise, next-action, Wibmo 3-D Secure, MPGS … → TRANSACTION_CONFIRMED +GET transaction.merchants…/?wait=1 → 302 dhiraagu-bml-response.aspx (tops up) + → 302 /services/reload-receipt +``` + +After the payment the browser is sent `transaction…/?wait=1` → +`dhiraagu-bml-response.aspx?transactionId=&state=CONFIRMED&signature=…` → +`/services/reload-receipt?pyid=`. **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/?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=&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=`. +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":"","gatewayId":1,"dhiraaguPayNumber":"","amount":"20.00", + "paymentMerchantId":"","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":""}`. 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":"","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) diff --git a/docs/dhiraaguapi/README.md b/docs/dhiraaguapi/README.md index 4564526..11ae713 100644 --- a/docs/dhiraaguapi/README.md +++ b/docs/dhiraaguapi/README.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 | --- diff --git a/docs/thijooree/07-transfer.md b/docs/thijooree/07-transfer.md index 553a886..d8ece92 100644 --- a/docs/thijooree/07-transfer.md +++ b/docs/thijooree/07-transfer.md @@ -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. --- diff --git a/docs/thijooree/20-transfer-flows.md b/docs/thijooree/20-transfer-flows.md index 21b755b..d0636f6 100644 --- a/docs/thijooree/20-transfer-flows.md +++ b/docs/thijooree/20-transfer-flows.md @@ -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 --- diff --git a/docs/thijooree/29-card-verification-and-merchant-card-pay.md b/docs/thijooree/29-card-verification-and-merchant-card-pay.md index 75b1e7d..b02e49d 100644 --- a/docs/thijooree/29-card-verification-and-merchant-card-pay.md +++ b/docs/thijooree/29-card-verification-and-merchant-card-pay.md @@ -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 +`?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 | --- diff --git a/docs/thijooree/README.md b/docs/thijooree/README.md index 7a16dc2..0a384a5 100644 --- a/docs/thijooree/README.md +++ b/docs/thijooree/README.md @@ -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 |