forked from shihaam/thijooree
add support for mib loans view
This commit is contained in:
@@ -0,0 +1,82 @@
|
||||
package sh.sar.basedbank.api.mib
|
||||
|
||||
import android.util.Log
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.math.ceil
|
||||
|
||||
class MibFinancingClient {
|
||||
|
||||
private val TAG = "MibFinancingClient"
|
||||
private val BASE_WV_URL = "https://faisamobilex-wv.mib.com.mv"
|
||||
|
||||
private val client = OkHttpClient.Builder()
|
||||
.connectTimeout(30, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
.build()
|
||||
|
||||
fun fetchFinancing(session: MibSession): List<MibFinanceDeal> {
|
||||
val cookieHeader = "mbmodel=IOS-1.0; " +
|
||||
"xxid=${session.xxid}; " +
|
||||
"IBSID=${session.xxid}; " +
|
||||
"mbnonce=${session.nonceGenerator}; " +
|
||||
"time-tracker=597"
|
||||
|
||||
val request = Request.Builder()
|
||||
.url("$BASE_WV_URL/financing?dashurl=1")
|
||||
.header("Cookie", cookieHeader)
|
||||
.header(
|
||||
"User-Agent",
|
||||
"Mozilla/5.0 (Linux; Android 14; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/129.0.6668.70 Mobile Safari/537.36"
|
||||
)
|
||||
.header("X-Requested-With", "mv.com.mib.faisamobilex")
|
||||
.get()
|
||||
.build()
|
||||
|
||||
val html = client.newCall(request).execute().use { response ->
|
||||
Log.d(TAG, "fetchFinancing: HTTP ${response.code}")
|
||||
if (!response.isSuccessful) return emptyList()
|
||||
response.body?.string() ?: return emptyList()
|
||||
}
|
||||
|
||||
return parseFinancingHtml(html)
|
||||
}
|
||||
|
||||
private fun parseFinancingHtml(html: String): List<MibFinanceDeal> {
|
||||
val cardPattern = Regex("""finance-card-holder[^>]+>""")
|
||||
val attrPattern = Regex("""data-(\w+)\s*=\s*"([^"]*)"""")
|
||||
|
||||
return cardPattern.findAll(html).mapNotNull { cardMatch ->
|
||||
val attrs = attrPattern.findAll(cardMatch.value)
|
||||
.associate { it.groupValues[1] to it.groupValues[2] }
|
||||
|
||||
val dealNo = attrs["dealNo"] ?: return@mapNotNull null
|
||||
|
||||
MibFinanceDeal(
|
||||
dealNo = dealNo,
|
||||
productDesc = attrs["productDesc"] ?: "",
|
||||
dealStatus = attrs["dealStatus"] ?: "",
|
||||
statusDesc = attrs["statusDesc"] ?: "",
|
||||
dealAmount = attrs["dealAmount"]?.toDoubleOrNull() ?: 0.0,
|
||||
paidAmount = attrs["paidAmount"]?.toDoubleOrNull() ?: 0.0,
|
||||
outstandingAmount = attrs["outstandingAmount"]?.toDoubleOrNull() ?: 0.0,
|
||||
dealDate = attrs["dealDate"] ?: "",
|
||||
overdueAmount = attrs["overdueAmount"]?.toDoubleOrNull() ?: 0.0,
|
||||
installmentAmount = attrs["installmentAmount"]?.toDoubleOrNull() ?: 0.0,
|
||||
noOfInstallments = attrs["noOfInstallments"]?.toIntOrNull() ?: 0,
|
||||
lastPaidDate = attrs["lastPaidDate"] ?: "",
|
||||
lastPayAmount = attrs["lastPayAmount"]?.toDoubleOrNull() ?: 0.0,
|
||||
currency = attrs["curCodeDesc"] ?: "MVR"
|
||||
)
|
||||
}.toList().also { Log.d(TAG, "parsed ${it.size} financing deals") }
|
||||
}
|
||||
|
||||
companion object {
|
||||
/** Estimate remaining months until financing is fully paid. */
|
||||
fun remainingMonths(deal: MibFinanceDeal): Int {
|
||||
if (deal.installmentAmount <= 0.0) return 0
|
||||
return ceil(deal.outstandingAmount / deal.installmentAmount).toInt()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,14 @@ class MibLoginFlow(private val prefs: android.content.SharedPreferences) {
|
||||
private val TAG = "MibLoginFlow"
|
||||
private val BASE_URL = "https://faisanet.mib.com.mv/faisamobilex_smvc/"
|
||||
|
||||
/** The active session after a successful login, usable for subsequent WebView requests. */
|
||||
var lastSession: MibSession? = null
|
||||
private set
|
||||
|
||||
/** Profiles returned by the last successful login. */
|
||||
var lastProfiles: List<MibProfile> = emptyList()
|
||||
private set
|
||||
|
||||
private val client = OkHttpClient.Builder()
|
||||
.connectTimeout(30, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
@@ -140,6 +148,8 @@ class MibLoginFlow(private val prefs: android.content.SharedPreferences) {
|
||||
val profiles = parseProfiles(loginResp)
|
||||
Log.d(TAG, "[login] parsed ${profiles.size} profiles")
|
||||
|
||||
lastSession = session2
|
||||
lastProfiles = profiles
|
||||
Log.d(TAG, "[login] step 7: fetch all profiles")
|
||||
return fetchAllProfiles(session2, profiles)
|
||||
}
|
||||
@@ -213,6 +223,19 @@ class MibLoginFlow(private val prefs: android.content.SharedPreferences) {
|
||||
put("xxid", session.xxid)
|
||||
}
|
||||
|
||||
/**
|
||||
* Activates [profile] server-side via P47, setting the session role context so that
|
||||
* subsequent WebView requests run under that profile.
|
||||
*/
|
||||
fun switchProfile(session: MibSession, profile: MibProfile) {
|
||||
Log.d(TAG, "switchProfile: profileId=${profile.profileId} cifType=${profile.cifType}")
|
||||
val payload = baseData(session, "P47").apply {
|
||||
put("profileType", profile.profileType)
|
||||
put("profileId", profile.profileId)
|
||||
}
|
||||
doRequest(session, payload, "n")
|
||||
}
|
||||
|
||||
private fun fetchAllProfiles(session: MibSession, profiles: List<MibProfile>): List<MibAccount> {
|
||||
val allAccounts = mutableListOf<MibAccount>()
|
||||
for (profile in profiles) {
|
||||
|
||||
@@ -31,3 +31,20 @@ data class MibAccount(
|
||||
val mvrBalance: String,
|
||||
val statusDesc: String
|
||||
)
|
||||
|
||||
data class MibFinanceDeal(
|
||||
val dealNo: String,
|
||||
val productDesc: String,
|
||||
val dealStatus: String,
|
||||
val statusDesc: String,
|
||||
val dealAmount: Double,
|
||||
val paidAmount: Double,
|
||||
val outstandingAmount: Double,
|
||||
val dealDate: String,
|
||||
val overdueAmount: Double,
|
||||
val installmentAmount: Double,
|
||||
val noOfInstallments: Int,
|
||||
val lastPaidDate: String,
|
||||
val lastPayAmount: Double,
|
||||
val currency: String
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user