forked from thijooree/android
add transactions and account history
This commit is contained in:
@@ -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() }
|
||||
}
|
||||
Reference in New Issue
Block a user