NTP-36791 | Divyesh | fastag chip enhancement (#15043)

This commit is contained in:
Divyesh Shinde
2025-02-25 21:00:23 +05:30
committed by GitHub
parent 4085cd8d6a
commit 90fcfa89fd
6 changed files with 146 additions and 47 deletions

View File

@@ -37,6 +37,7 @@ data class NaviBbpsDefaultConfig(
@SerializedName("postPaymentPendingMessage")
val postPaymentPendingMessage: PostPaymentPendingMessage = PostPaymentPendingMessage(),
@SerializedName("arcConfig") val arcConfig: ArcConfig = ArcConfig(),
@SerializedName("chipsConfigData") val chipsConfigData: ChipsConfigData = ChipsConfigData(),
)
data class ConfigMessage(
@@ -158,3 +159,11 @@ data class ArcConfig(
@SerializedName("mainTextBill") val mainTextBill: String = "If bill is pending after",
@SerializedName("subText") val subText: String = "you will get extra",
)
data class ChipsConfigData(
@SerializedName("genericMinAmount") val genericMinAmount: Int = 200,
@SerializedName("genericMaxAmount") val genericMaxAmount: Int = 1000,
@SerializedName("minimumRequiredDifference") val minimumRequiredDifference: Int = 500,
@SerializedName("secondChipFormulaExpression") val secondChipFormulaExpression: String = "",
@SerializedName("thirdChipFormulaExpression") val thirdChipFormulaExpression: String = "",
)

View File

@@ -56,10 +56,10 @@ constructor(
epochLastPaidOn = it.lastPaidOn.orEmpty(),
actualLastPaidAmount = it.lastPaidAmount.orEmpty(),
formattedLastPaidAmount = lastPaidAmount,
primaryCustomerParamValue = it.primaryCustomerParam,
primaryCustomerParamValue = it.primaryCustomerParam.orEmpty(),
categoryId = it.categoryId,
categoryName = it.categoryName,
customerParams = it.customerParams,
customerParams = it.customerParams ?: emptyMap(),
isBillPaid = it.isBillPaid ?: false,
nextActionCtaText =
it.nextActionCtaText.orEmpty().ifBlank {

View File

@@ -28,8 +28,8 @@ data class SavedBillItem(
@SerializedName("isConsentRequired") val isConsentRequired: Boolean?,
@SerializedName("lastPaidOn") val lastPaidOn: String?,
@SerializedName("lastPaidAmount") val lastPaidAmount: String?,
@SerializedName("primaryCustomerParam") val primaryCustomerParam: String,
@SerializedName("customerParams") val customerParams: Map<String, String>,
@SerializedName("primaryCustomerParam") val primaryCustomerParam: String?,
@SerializedName("customerParams") val customerParams: Map<String, String>?,
@SerializedName("categoryId") val categoryId: String,
@SerializedName("categoryName") val categoryName: String,
@SerializedName("nextActionCtaText") val nextActionCtaText: String?,

View File

@@ -16,6 +16,7 @@ import com.navi.base.utils.EMPTY
import com.navi.base.utils.NaviNetworkConnectivity
import com.navi.base.utils.ResourceProvider
import com.navi.base.utils.ZERO_STRING
import com.navi.base.utils.isNotNull
import com.navi.base.utils.orFalse
import com.navi.base.utils.orZero
import com.navi.bbps.R
@@ -35,6 +36,7 @@ import com.navi.bbps.common.DISPLAYABLE_MOBILE_NUMBER_KEY
import com.navi.bbps.common.NaviBbpsAnalytics
import com.navi.bbps.common.NaviBbpsScreen
import com.navi.bbps.common.model.NaviBbpsVmData
import com.navi.bbps.common.model.config.ChipsConfigData
import com.navi.bbps.common.model.config.NaviBbpsDefaultConfig
import com.navi.bbps.common.model.view.NaviBbpsSessionHelper
import com.navi.bbps.common.repository.BbpsCommonRepository
@@ -45,6 +47,7 @@ import com.navi.bbps.common.usecase.RewardNudgeUseCase
import com.navi.bbps.common.utils.NaviBbpsCommonUtils.evaluateMvelExpression
import com.navi.bbps.common.utils.NaviBbpsCommonUtils.getBbpsMetricInfo
import com.navi.bbps.common.utils.NaviBbpsCommonUtils.getValidatedAmountNumber
import com.navi.bbps.common.utils.NaviBbpsCommonUtils.isCategoryOfTypeAmountChipsRequired
import com.navi.bbps.common.utils.NaviBbpsDateUtils
import com.navi.bbps.common.utils.getDefaultConfig
import com.navi.bbps.common.utils.getDisplayableAmount
@@ -142,6 +145,8 @@ constructor(
companion object {
const val TAG_BILL_FETCH_ERROR = "TAG_BILL_FETCH_ERROR"
private const val CC_MIN_DUE_AMOUNT_KEY = "MinimumDueAmount"
private const val BILLER_MIN_ACCEPTED_AMOUNT = "Biller_Min_Accepted_Amount"
private const val BILLER_MAX_ACCEPTED_AMOUNT = "Biller_Max_Accepted_Amount"
}
val naviBbpsAnalytics: NaviBbpsAnalytics.PayBill = NaviBbpsAnalytics.INSTANCE.PayBill()
@@ -252,6 +257,8 @@ constructor(
private val _isArcProtected = MutableStateFlow<Boolean>(false)
val isArcProtected = _isArcProtected.asStateFlow()
private val amountChips = MutableStateFlow(emptyList<String>())
var arcNudgeResponse: ArcNudgeResponse? = null
@Inject lateinit var paymentNavigator: PaymentNavigator
@@ -468,9 +475,133 @@ constructor(
}
}
}
updateAmountChips(chipsConfigData = naviBbpsDefaultConfig.value.chipsConfigData)
}
}
private fun updateAmountChips(chipsConfigData: ChipsConfigData) {
if (
!isCategoryOfTypeAmountChipsRequired(
categoryId = billCategoryEntity?.categoryId.orEmpty()
)
) {
return
}
var minChipAmount = chipsConfigData.genericMinAmount
var maxChipAmount = chipsConfigData.genericMaxAmount
when (paymentAmountExactness.value) {
PaymentAmountExactness.EXACT_AND_ABOVE -> {
initialPaymentAmount.value.toDoubleOrNull()?.let {
minChipAmount =
minChipAmount.coerceAtLeast(initialPaymentAmount.value.toDouble().toInt())
}
}
PaymentAmountExactness.EXACT_AND_BELOW -> {
initialPaymentAmount.value.toDoubleOrNull()?.let {
maxChipAmount =
maxChipAmount.coerceAtMost(initialPaymentAmount.value.toDouble().toInt())
}
}
else -> {}
}
val billerLevelMinAmountEntity =
billerAdditionalParams.value.find { it.paramName == BILLER_MIN_ACCEPTED_AMOUNT }
val billerLevelMaxAmountEntity =
billerAdditionalParams.value.find { it.paramName == BILLER_MAX_ACCEPTED_AMOUNT }
billerLevelMinAmountEntity?.value?.toIntOrNull()?.let {
minChipAmount = minChipAmount.coerceAtLeast(billerLevelMinAmountEntity.value.toInt())
}
billerLevelMaxAmountEntity?.value?.toIntOrNull()?.let {
maxChipAmount = maxChipAmount.coerceAtMost(billerLevelMaxAmountEntity.value.toInt())
}
viewModelScope.launch(dispatcherProvider.io) {
val secondChipAmount =
calculateChipAmountFromFormula(
minChipAmount = minChipAmount.toInt(),
maxChipAmount = maxChipAmount.toInt(),
chipFormulaExpression = chipsConfigData.secondChipFormulaExpression,
)
if (secondChipAmount == ZERO_STRING) {
return@launch
}
val thirdChipAmount =
calculateChipAmountFromFormula(
minChipAmount = minChipAmount.toInt(),
maxChipAmount = maxChipAmount.toInt(),
chipFormulaExpression = chipsConfigData.thirdChipFormulaExpression,
)
if (thirdChipAmount == ZERO_STRING) {
return@launch
}
val shouldShowChip =
maxChipAmount - minChipAmount >= chipsConfigData.minimumRequiredDifference
if (!shouldShowChip) {
return@launch
}
amountChips.update {
listOf(
minChipAmount.toString(),
secondChipAmount,
thirdChipAmount,
maxChipAmount.toString(),
)
}
transformAmountChipsToAmountChipEntity(amountChips = amountChips.value)
if (initialPaymentAmount.value == ZERO_STRING) {
updatePaymentAmount(newAmountValue = amountChipEntityList.value.first().amount)
updateAmountChipEntity(amount = amountChipEntityList.value.first().amount)
}
}
}
private suspend fun calculateChipAmountFromFormula(
minChipAmount: Int,
maxChipAmount: Int,
chipFormulaExpression: String,
): String {
return evaluateMvelExpression(
key = chipFormulaExpression,
data = mapOf("minChipAmount" to minChipAmount, "maxChipAmount" to maxChipAmount),
defaultValue = ZERO_STRING,
)
}
private fun transformAmountChipsToAmountChipEntity(amountChips: List<String>) {
_amountChipEntityList.update {
amountChips.map { amount -> AmountChipEntity(amount = amount, isSelected = false) }
}
}
open fun updateAmountChipEntity(amount: String) {
amountChipEntityList.value.isNotNull().let {
updateAmountChipEntityList(
amountChipList =
amountChipEntityList.value.map { amountChipEntity ->
amountChipEntity.copy(isSelected = amountChipEntity.amount == amount)
}
)
}
}
private fun updateAmountChipEntityList(amountChipList: List<AmountChipEntity>) {
_amountChipEntityList.update { amountChipList }
}
private fun updateCreditCardPaymentOptions(billDetailsEntity: BillDetailsEntity) {
val creditCardPaymentOptions = mutableListOf<CreditCardPaymentOption>()

View File

@@ -15,7 +15,6 @@ import com.navi.base.utils.EMPTY
import com.navi.base.utils.NaviNetworkConnectivity
import com.navi.base.utils.ResourceProvider
import com.navi.base.utils.ZERO_STRING
import com.navi.base.utils.isNotNull
import com.navi.base.utils.isNotNullAndNotEmpty
import com.navi.base.utils.orZero
import com.navi.bbps.R
@@ -39,7 +38,6 @@ import com.navi.bbps.common.utils.getDisplayableAmount
import com.navi.bbps.feature.category.BillCategoriesRepository
import com.navi.bbps.feature.mybills.MyBillsRepository
import com.navi.bbps.feature.paybill.model.network.PaymentAmountExactness
import com.navi.bbps.feature.paybill.model.view.AmountChipEntity
import com.navi.bbps.feature.paybill.model.view.CoinUtilisationPropertiesV2
import com.navi.bbps.feature.paybill.model.view.PayBillBottomSheetType
import com.navi.bbps.feature.paybill.model.view.PayBillSource
@@ -49,7 +47,6 @@ import com.navi.payment.nativepayment.utils.NaviPaymentRewardsEventBus
import com.navi.payment.tstore.repository.TStoreOrderHandler
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
import kotlin.collections.map
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableSharedFlow
@@ -131,15 +128,8 @@ constructor(
private val _isLottieAnimationShown = MutableStateFlow(false)
val isLottieAnimationShown = _isLottieAnimationShown.asStateFlow()
private val amountChips = MutableStateFlow(listOf("100", "200", "500", "1000"))
init {
viewModelScope.launch(dispatcherProvider.io) {
// Concurrent calls section
launch { updateAmountChips(chips = naviBbpsDefaultConfig.value.amountChips) }
launch { pmsDiscountListener() }
}
viewModelScope.launch(dispatcherProvider.io) { launch { pmsDiscountListener() } }
}
override fun updatePaymentAmount(newAmountValue: String) {
@@ -257,17 +247,6 @@ constructor(
}
}
private fun updateAmountChips(chips: List<String>) {
amountChips.update { chips }
transformAmountChipsToAmountChipEntity(amountChips = chips)
}
private fun transformAmountChipsToAmountChipEntity(amountChips: List<String>) {
_amountChipEntityList.update {
amountChips.map { amount -> AmountChipEntity(amount = amount, isSelected = false) }
}
}
fun enteredAmountInputChanged(
newInput: String,
isAmountChangedByChipSelection: Boolean = false,
@@ -291,21 +270,6 @@ constructor(
}
}
private fun updateAmountChipEntity(amount: String) {
amountChipEntityList.value.isNotNull().let {
updateAmountChipEntityList(
amountChipList =
amountChipEntityList.value.map { amountChipEntity ->
amountChipEntity.copy(isSelected = amountChipEntity.amount == amount)
}
)
}
}
private fun updateAmountChipEntityList(amountChipList: List<AmountChipEntity>) {
_amountChipEntityList.update { amountChipList }
}
fun onAppliedDiscountClicked() {
val discountAmount = coinUtilisationPropertiesV2.value?.discountAmount.orEmpty()
if (discountAmount.isNotEmpty()) {

View File

@@ -100,7 +100,6 @@ import com.navi.bbps.common.ui.NaviBbpsLottieAnimation
import com.navi.bbps.common.ui.NaviBbpsModalBottomSheetLayout
import com.navi.bbps.common.ui.SetStatusBarColor
import com.navi.bbps.common.utils.NaviBbpsCommonUtils
import com.navi.bbps.common.utils.NaviBbpsCommonUtils.isCategoryOfTypeAmountChipsRequired
import com.navi.bbps.common.utils.NaviBbpsCommonUtils.isCreditCardCategory
import com.navi.bbps.common.utils.NaviBbpsCommonUtils.isRechargeCategory
import com.navi.bbps.common.utils.NaviBbpsCommonUtils.isUrlPathValidForSavedBills
@@ -685,11 +684,7 @@ fun PayBillScreenV2(
payBillViewModelV2::
handleDiscountRemovalOnAmountFieldClick,
)
if (
isCategoryOfTypeAmountChipsRequired(
billCategoryEntity.categoryId
)
) {
if (amountChipEntityList.isNotEmpty()) {
Column {
AmountChipItems(
modifier = Modifier.fillMaxWidth(),