# Account Display Parser Architecture ## Overview Each bank's API returns account data in different formats and uses different field names for balances, product types, and status. To keep screens bank-agnostic, each bank has a dedicated parser that translates raw `MibAccount` model data into a standard `AccountListDisplay` object. Screens consume only `AccountListDisplay` — they never inspect `bank` or `profileType` or apply bank-specific logic. ## Bank Discriminator — `MibAccount.bank` All dispatchers route by `account.bank`, a string set explicitly by each login flow at account creation time: | `bank` value | Set by | |--------------|-------------------| | `"MIB"` | `MibLoginFlow` | | `"BML"` | `BmlLoginFlow` | | `"FAHIPAY"` | `FahipayLoginFlow`| `profileType` is a bank-internal value (e.g. MIB's numeric profile ID, or BML's `"BML_PREPAID"`) and is **never** used for bank routing. Card-type checks within BML still use `profileType` (`"BML_PREPAID"` / `"BML_CREDIT"`). `cifType` (MIB only) is the human-readable profile category name returned by the `operatingProfiles` API (e.g. `"Individual"`, `"Sole Propr"`). It is stored on `MibAccount` and surfaced in the accounts list section header and settings. It is **never hardcoded** in the app. ## Standard Output Model ```kotlin // util/AccountListDisplay.kt data class AccountListDisplay( val name: String, // account or card display name val number: String, // account/card number val typeLabel: String, // human-friendly product type (e.g. "Savings", "Visa Platinum") val balance: String, // formatted balance string (e.g. "MVR 1,234.56") val isCard: Boolean, // true → use card layout; false → use account layout val cardBrandIcon: Int, // drawable res for card brand logo (Visa / Mastercard / Amex) val statusLabel: String? // null = active; non-null = shown as status label (e.g. "Inactive") ) ``` ## Dispatcher ```kotlin // util/AccountListParser.kt AccountListParser.from(account: MibAccount): AccountListDisplay? ``` Routes to the correct parser based on `account.bank`. Returns `null` for unknown banks — never falls back to a specific bank. | `account.bank` | Parser | |----------------|-------------------------| | `"BML"` | `BmlDashboardParser` | | `"FAHIPAY"` | `FahipayAccountParser` | | `"MIB"` | `MibAccountParser` | | anything else | `null` | ## Bank Parsers ### BML — `util/bmlapi/BmlDashboardParser` Handles both CASA accounts and prepaid/credit cards. - **CASA balance**: uses `ledgerBalance` (working balance) — mapped to `account.currentBalance` - **Card balance**: uses `availableBalance` (available limit from `cardBalance.AvailableLimit`) - **Card brand**: resolved from product name (`VISA` / `MASTERCARD` / `AMEX`) - **Status**: cards with `statusDesc != "Active"` surface `statusLabel`; active cards return `null` ### MIB — `util/mibapi/MibAccountParser` - **Balance**: `availableBalance` from the MIB API directly - Known product names (`SAVING ACCOUNT`, `CURRENT ACCOUNT`) mapped to short labels - `cifType` (e.g. `"Individual"`, `"Sole Propr"`) comes from `MibProfile.cifType`, stored on `MibAccount`, displayed in section headers ### Fahipay — `util/fahipayapi/FahipayAccountParser` - Single wallet account per user; `accountTypeName` is always `"Digital Wallet"` - **Balance**: `availableBalance` ## Adding a New Bank 1. Create `util/api/AccountParser.kt` with a `displayData(account: MibAccount): AccountListDisplay` function 2. Set `bank = ""` in the new login flow when creating `MibAccount` objects 3. Add a `when` branch in `AccountListParser.from()` (and other dispatchers) for the new bank value 4. No changes needed in any screen or adapter ## Usage in Screens `AccountsAdapter` calls `AccountListParser.from(account)` once per item (skipping `null` results) and binds the resulting `AccountListDisplay` directly. The adapter has zero bank-specific logic. The transfer screen dropdown (`TransferFragment`) also uses `AccountListParser.from(acc)?.balance` for the source account balance display.