save trsnaction type to history for reload, raastas and bill pay to autoselct card
Auto Tag on Version Change / check-version (push) Successful in 3s

This commit is contained in:
2026-10-03 01:32:39 +05:00
parent bb76f4e591
commit 5abd981096
3 changed files with 50 additions and 14 deletions
@@ -52,6 +52,7 @@ import sh.sar.basedbank.databinding.ItemPickerSectionHeaderBinding
import sh.sar.basedbank.databinding.ItemTransferTypeBinding import sh.sar.basedbank.databinding.ItemTransferTypeBinding
import sh.sar.basedbank.ui.home.transfer.BmlTransferHandler import sh.sar.basedbank.ui.home.transfer.BmlTransferHandler
import sh.sar.basedbank.ui.home.transfer.BmlVerifiedCards import sh.sar.basedbank.ui.home.transfer.BmlVerifiedCards
import sh.sar.basedbank.ui.home.transfer.CardPayoutService
import sh.sar.basedbank.ui.home.transfer.CardPayoutTransferHandler import sh.sar.basedbank.ui.home.transfer.CardPayoutTransferHandler
import sh.sar.basedbank.ui.home.transfer.CarrierLookup import sh.sar.basedbank.ui.home.transfer.CarrierLookup
import sh.sar.basedbank.ui.home.transfer.FahipayService import sh.sar.basedbank.ui.home.transfer.FahipayService
@@ -407,7 +408,7 @@ class TransferFragment : Fragment() {
return@setFragmentResultListener return@setFragmentResultListener
} }
val label = bundle.getString(ContactPickerSheetFragment.KEY_LABEL) ?: "" val label = bundle.getString(ContactPickerSheetFragment.KEY_LABEL) ?: ""
if (applyFahipayContact(accountNumber, bundle.getString(ContactPickerSheetFragment.KEY_CATEGORY), label)) { if (applyServiceContact(accountNumber, bundle.getString(ContactPickerSheetFragment.KEY_CATEGORY), label)) {
return@setFragmentResultListener return@setFragmentResultListener
} }
val subtitle = bundle.getString(ContactPickerSheetFragment.KEY_SUBTITLE) ?: accountNumber val subtitle = bundle.getString(ContactPickerSheetFragment.KEY_SUBTITLE) ?: accountNumber
@@ -453,7 +454,7 @@ class TransferFragment : Fragment() {
// Pre-select contact if navigated from contacts page or QR scan // Pre-select contact if navigated from contacts page or QR scan
arguments?.getString(ARG_ACCOUNT)?.let { account -> arguments?.getString(ARG_ACCOUNT)?.let { account ->
val name = arguments?.getString(ARG_NAME) ?: account val name = arguments?.getString(ARG_NAME) ?: account
if (applyFahipayContact(account, arguments?.getString(ARG_CONTACT_CATEGORY), name)) return@let if (applyServiceContact(account, arguments?.getString(ARG_CONTACT_CATEGORY), name)) return@let
prefillToDirectly( prefillToDirectly(
accountNumber = account, accountNumber = account,
displayName = name, displayName = name,
@@ -1141,15 +1142,27 @@ class TransferFragment : Fragment() {
} }
/** /**
* A saved Fahipay favourite: its list ([categoryId]) already says which service pays it, so * A saved Fahipay favourite, or a recent paid with a Fahipay or card service: its category
* that service is applied as the only transfer type, with no carrier lookup. That switches * ([categoryId]) already says which service pays it, so that service is applied as the only
* the source to the Fahipay wallet and brings in the service's amount rules, the same as a * transfer type, with no carrier lookup. That switches the source to the Fahipay wallet or
* searched number. Returns false, doing nothing, when [categoryId] isn't a Fahipay list. * the default card and brings in the service's amount rules, the same as a searched number.
* Returns false, doing nothing, when [categoryId] isn't one of those.
*/ */
private fun applyFahipayContact(number: String, categoryId: String?, name: String): Boolean { private fun applyServiceContact(number: String, categoryId: String?, name: String): Boolean {
val service = FahipayService.fromContactCategory(categoryId) ?: return false val ownerName = name.takeIf { it.isNotBlank() && it != number }
val type = FahipayService.fromContactCategory(categoryId)?.let { TransferType.Fahipay(it, ownerName) }
?: CardPayoutService.fromContactCategory(categoryId)?.let { service ->
// The cards that could pay it then may not be payable now
val cards = cardPayoutHandler().payableCards()
if (cards.isEmpty()) {
Toast.makeText(requireContext(), R.string.bml_card_pay_no_verified, Toast.LENGTH_LONG).show()
return true
}
TransferType.Card(service, ownerName, cards)
}
?: return false
clearRecipient() clearRecipient()
offerTransferTypes(number, listOf(TransferType.Fahipay(service, name.takeIf { it.isNotBlank() && it != number }))) offerTransferTypes(number, listOf(type))
return true return true
} }
@@ -33,22 +33,37 @@ enum class CardPayoutService(
override val maxAmount: Int?, override val maxAmount: Int?,
override val decimalsAllowed: Boolean, override val decimalsAllowed: Boolean,
override val gstPercent: Int?, override val gstPercent: Int?,
/**
* Tags the recents paid with this service (`RecentPick.contactCategory`), so picking one
* again pays the same way. Not a real contact list: card payouts have no favourites.
*/
val contactCategory: String,
override val gstAdded: Boolean = false, override val gstAdded: Boolean = false,
) : PayoutService { ) : PayoutService {
DHIRAAGU_RELOAD("Dhiraagu Reload", "Dhiraagu · Reload", R.drawable.dhiraagu_logo, DHIRAAGU_RELOAD("Dhiraagu Reload", "Dhiraagu · Reload", R.drawable.dhiraagu_logo,
minAmount = 20, maxAmount = 1000, decimalsAllowed = false, gstPercent = 8) { minAmount = 20, maxAmount = 1000, decimalsAllowed = false, gstPercent = 8,
contactCategory = "CARD_DHIRAAGU_RELOAD") {
// Dhiraagu rounds the GST to 2 places and credits the rest // Dhiraagu rounds the GST to 2 places and credits the rest
override fun creditedAfterGst(amount: BigDecimal): BigDecimal = override fun creditedAfterGst(amount: BigDecimal): BigDecimal =
amount - DhiraaguPaymentClient.gstOf(amount.setScale(0, RoundingMode.DOWN).toInt()) amount - DhiraaguPaymentClient.gstOf(amount.setScale(0, RoundingMode.DOWN).toInt())
}, },
// Easy Pay sets no limits of its own: any amount with up to 2 decimals, no GST // Easy Pay sets no limits of its own: any amount with up to 2 decimals, no GST
DHIRAAGU_BILL("Dhiraagu Bill Pay", "Dhiraagu · Bill Pay", R.drawable.dhiraagu_logo, DHIRAAGU_BILL("Dhiraagu Bill Pay", "Dhiraagu · Bill Pay", R.drawable.dhiraagu_logo,
minAmount = 1, maxAmount = null, decimalsAllowed = true, gstPercent = null), minAmount = 1, maxAmount = null, decimalsAllowed = true, gstPercent = null,
contactCategory = "CARD_DHIRAAGU_BILL"),
// Ooredoo credits the whole amount and charges the card 8% GST on top // Ooredoo credits the whole amount and charges the card 8% GST on top
OOREDOO_RAASTAS("Raastas", "Ooredoo · Raastas", R.drawable.ooredoo_logo, OOREDOO_RAASTAS("Raastas", "Ooredoo · Raastas", R.drawable.ooredoo_logo,
minAmount = 20, maxAmount = null, decimalsAllowed = false, gstPercent = 8, gstAdded = true), minAmount = 20, maxAmount = null, decimalsAllowed = false, gstPercent = 8,
contactCategory = "CARD_RAASTAS", gstAdded = true),
OOREDOO_BILL("Ooredoo Bill Pay", "Ooredoo · Bill Pay", R.drawable.ooredoo_logo, OOREDOO_BILL("Ooredoo Bill Pay", "Ooredoo · Bill Pay", R.drawable.ooredoo_logo,
minAmount = 10, maxAmount = null, decimalsAllowed = true, gstPercent = null); minAmount = 10, maxAmount = null, decimalsAllowed = true, gstPercent = null,
contactCategory = "CARD_OOREDOO_BILL");
companion object {
/** The service a recent was paid with, from its [contactCategory], or null when it isn't one. */
fun fromContactCategory(categoryId: String?): CardPayoutService? =
entries.firstOrNull { it.contactCategory == categoryId }
}
} }
/** /**
@@ -136,7 +151,8 @@ class CardPayoutTransferHandler(
displayName = displayName, displayName = displayName,
subtitle = "${type.label} · $number", subtitle = "${type.label} · $number",
colorHex = "#E4002B", colorHex = "#E4002B",
imageHash = null imageHash = null,
contactCategory = type.service.contactCategory
) )
fragment.focusAmount() fragment.focusAmount()
} }
+7
View File
@@ -189,6 +189,13 @@ paid ("You pay MVR 21.60 with 8% GST"). The order check in step 2 below compares
**Reference.** None. The field is cleared and disabled, as for the Fahipay services. **Reference.** None. The field is cleared and disabled, as for the Fahipay services.
**Recents.** As with Fahipay services, the recent is saved with the service's category
(`CardPayoutService.contactCategory`: `CARD_DHIRAAGU_RELOAD`, `CARD_DHIRAAGU_BILL`,
`CARD_RAASTAS`, `CARD_OOREDOO_BILL`). Picking it again applies that service with no lookup, so
the default card (or another payable card) is selected rather than the default account
(`TransferFragment.applyServiceContact`). With no payable card left, it toasts and stops. A number
keeps one recent, so paying it another way replaces the category.
**Sending.** The only part that differs from paying a card-only BML merchant link is where the **Sending.** The only part that differs from paying a card-only BML merchant link is where the
BML transaction comes from: BML transaction comes from: