add BML usd limits to dashboard and optmize login flow/session expirey

This commit is contained in:
2026-05-14 05:24:33 +05:00
parent 8119d554cf
commit 25bbbe926f
10 changed files with 506 additions and 55 deletions
@@ -19,6 +19,8 @@ import java.security.SecureRandom
import java.util.Base64
import java.util.concurrent.TimeUnit
class AuthExpiredException : Exception("Session expired")
class BmlLoginFlow {
private val BASE_URL = "https://www.bankofmaldives.com.mv/internetbanking"
@@ -162,9 +164,43 @@ class BmlLoginFlow {
fun fetchAccounts(session: BmlSession): List<MibAccount> {
val resp = apiClient.newCall(apiRequest(session, "$BASE_URL/api/mobile/dashboard")).execute()
val json = resp.body?.string() ?: return emptyList()
val code = resp.code
val json = resp.body?.string()
resp.close()
return parseDashboard(json, "bml_${session.deviceId}")
if (code == 401 || code == 419) throw AuthExpiredException()
return parseDashboard(json ?: return emptyList(), "bml_${session.deviceId}")
}
fun fetchForeignLimits(session: BmlSession): List<BmlForeignLimit> {
val resp = apiClient.newCall(
Request.Builder().url("https://app.bankofmaldives.com.mv/api/v2/foreign-limits")
.header("Authorization", "Bearer ${session.accessToken}")
.header("User-Agent", APP_USER_AGENT)
.header("x-app-version", APP_VERSION)
.header("Accept", "application/json")
.build()
).execute()
val code = resp.code
val json = resp.body?.string()
resp.close()
if (code == 401 || code == 419) throw AuthExpiredException()
return parseForeignLimits(json ?: return emptyList())
}
fun fetchUserInfo(session: BmlSession): String {
val resp = apiClient.newCall(apiRequest(session, "$BASE_URL/api/mobile/userinfo")).execute()
val json = resp.body?.string() ?: return ""
resp.close()
return try {
val root = JSONObject(json)
if (!root.optBoolean("success")) return ""
val payload = root.optJSONObject("payload") ?: return ""
payload.optString("name").ifBlank {
payload.optString("fullName").ifBlank {
payload.optString("customer_name")
}
}
} catch (_: Exception) { "" }
}
fun fetchContacts(session: BmlSession): List<MibBeneficiary> {
@@ -243,6 +279,37 @@ class BmlLoginFlow {
return casaAccounts + prepaidCards
}
private fun parseForeignLimits(json: String): List<BmlForeignLimit> {
return try {
val root = JSONObject(json)
if (!root.optBoolean("success")) return emptyList()
val payload = root.optJSONArray("payload") ?: return emptyList()
(0 until payload.length()).map { i ->
val item = payload.getJSONObject(i)
val usage = item.optJSONObject("usageByCategory") ?: JSONObject()
val atm = usage.optJSONObject("ATM") ?: JSONObject()
val ecom = usage.optJSONObject("ECOM") ?: JSONObject()
val pos = usage.optJSONObject("POS") ?: JSONObject()
BmlForeignLimit(
type = item.optString("type", "Debit"),
used = item.optDouble("used", 0.0),
totalLimit = item.optDouble("totalLimit", 0.0),
generalCap = item.optDouble("generalCap", 0.0),
generalRemaining = item.optDouble("generalRemaining", 0.0),
medicalRemaining = item.optDouble("medicalRemaining", 0.0),
isAtmEnabled = item.optBoolean("isAtmEnabled", false),
isPosEnabled = item.optBoolean("isPosEnabled", false),
atmRemaining = atm.optDouble("remaining", 0.0),
atmLimit = atm.optDouble("limit", 0.0),
ecomRemaining = ecom.optDouble("remaining", 0.0),
ecomLimit = ecom.optDouble("limit", 0.0),
posRemaining = pos.optDouble("remaining", 0.0),
posLimit = pos.optDouble("limit", 0.0)
)
}
} catch (_: Exception) { emptyList() }
}
private fun parseContacts(json: String): List<MibBeneficiary> {
val root = JSONObject(json)
if (!root.optBoolean("success")) return emptyList()
@@ -4,3 +4,20 @@ data class BmlSession(
val accessToken: String,
val deviceId: String
)
data class BmlForeignLimit(
val type: String,
val used: Double,
val totalLimit: Double,
val generalCap: Double,
val generalRemaining: Double,
val medicalRemaining: Double,
val isAtmEnabled: Boolean,
val isPosEnabled: Boolean,
val atmRemaining: Double,
val atmLimit: Double,
val ecomRemaining: Double,
val ecomLimit: Double,
val posRemaining: Double,
val posLimit: Double
)