add transactions and account history

This commit is contained in:
2026-05-15 09:21:09 +05:00
parent deedd16ba2
commit 6779b6f3b7
21 changed files with 1629 additions and 5 deletions
@@ -0,0 +1,87 @@
package sh.sar.basedbank.api.mib
import okhttp3.FormBody
import okhttp3.OkHttpClient
import okhttp3.Request
import org.json.JSONObject
import java.util.concurrent.TimeUnit
class MibHistoryClient {
private val BASE_WV_URL = "https://faisamobilex-wv.mib.com.mv"
private val client = OkHttpClient.Builder()
.connectTimeout(20, TimeUnit.SECONDS)
.readTimeout(20, TimeUnit.SECONDS)
.build()
private fun cookieHeader(session: MibSession) =
"mbmodel=IOS-1.0; xxid=${session.xxid}; IBSID=${session.xxid}; " +
"mbnonce=${session.nonceGenerator}; time-tracker=597"
/**
* Fetches transaction history for a single MIB account.
* @param start 1-based index; use 1 for first page, 21 for second, etc. (pageSize=20)
* @return Pair of (transactions, totalCount)
*/
fun fetchHistory(
session: MibSession,
accountNo: String,
accountDisplayName: String,
start: Int = 1,
pageSize: Int = 20
): Pair<List<Transaction>, Int> {
val body = FormBody.Builder()
.add("accountNo", accountNo)
.add("trxNo", "")
.add("trxType", "0")
.add("sortTrx", "date")
.add("sortDir", "desc")
.add("fromDate", "")
.add("toDate", "")
.add("start", start.toString())
.add("end", (start + pageSize - 1).toString())
.add("includeCount", "1")
.build()
val request = Request.Builder()
.url("$BASE_WV_URL/ajaxAccounts/trxHistory")
.post(body)
.header("Cookie", cookieHeader(session))
.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", "XMLHttpRequest")
.header("Accept", "*/*")
.header("Origin", BASE_WV_URL)
.header("Referer", "$BASE_WV_URL//accountDetails?trxh=1&dashurl=1&accountNo=$accountNo")
.build()
return client.newCall(request).execute().use { response ->
val bodyStr = response.body?.string() ?: return Pair(emptyList(), 0)
val json = try { JSONObject(bodyStr) } catch (_: Exception) { return Pair(emptyList(), 0) }
if (!json.optBoolean("success")) return Pair(emptyList(), 0)
val total = json.optString("total_count", "0").toIntOrNull() ?: 0
val data = json.optJSONArray("data") ?: return Pair(emptyList(), total)
val transactions = (0 until data.length()).map { i ->
val item = data.getJSONObject(i)
Transaction(
id = item.optString("trxNumber"),
date = item.optString("trxDate"),
description = item.optString("descr1").trim(),
amount = item.optString("baseAmount", "0").toDoubleOrNull() ?: 0.0,
currency = item.optString("curCodeDesc"),
counterpartyName = item.optString("benefName").takeIf {
it.isNotBlank() && it != "null"
},
reference = item.optString("trxNumber2").takeIf { it.isNotBlank() },
accountNumber = accountNo,
accountDisplayName = accountDisplayName,
source = "MIB"
)
}
Pair(transactions, total)
}
}
}
@@ -72,6 +72,19 @@ data class MibIpsAccountInfo(
val bankId: String
)
data class Transaction(
val id: String,
val date: String, // "YYYY-MM-DD HH:mm:ss" for MIB, ISO8601 for BML
val description: String,
val amount: Double, // negative = debit, positive = credit
val currency: String,
val counterpartyName: String?,
val reference: String?,
val accountNumber: String,
val accountDisplayName: String,
val source: String // "MIB", "BML", "BML_CARD"
)
data class MibFinanceDeal(
val dealNo: String,
val productDesc: String,
@@ -0,0 +1,47 @@
package sh.sar.basedbank.api.mib
import android.content.Context
import org.json.JSONArray
import org.json.JSONObject
import java.io.File
object TransactionCache {
fun save(context: Context, key: String, transactions: List<Transaction>) {
try {
val arr = JSONArray()
for (t in transactions) arr.put(JSONObject().apply {
put("id", t.id)
put("date", t.date)
put("description", t.description)
put("amount", t.amount)
put("currency", t.currency)
put("counterpartyName", t.counterpartyName ?: "")
put("reference", t.reference ?: "")
put("accountNumber", t.accountNumber)
put("accountDisplayName", t.accountDisplayName)
put("source", t.source)
})
File(context.cacheDir, "tx_$key.json").writeText(arr.toString())
} catch (_: Exception) {}
}
fun load(context: Context, key: String): List<Transaction> = try {
val arr = JSONArray(File(context.cacheDir, "tx_$key.json").readText())
(0 until arr.length()).map { i ->
val o = arr.getJSONObject(i)
Transaction(
id = o.optString("id"),
date = o.optString("date"),
description = o.optString("description"),
amount = o.optDouble("amount", 0.0),
currency = o.optString("currency"),
counterpartyName = o.optString("counterpartyName").takeIf { it.isNotBlank() },
reference = o.optString("reference").takeIf { it.isNotBlank() },
accountNumber = o.optString("accountNumber"),
accountDisplayName = o.optString("accountDisplayName"),
source = o.optString("source")
)
}
} catch (_: Exception) { emptyList() }
}