NTP-24902 | Divyesh | arc post bill payment testing fixes (#14713)

This commit is contained in:
Divyesh Shinde
2025-01-29 13:01:46 +05:30
committed by GitHub
parent d44b97034e
commit 48d540e660
9 changed files with 101 additions and 89 deletions

View File

@@ -205,6 +205,9 @@ constructor(
private val _goToNextScreen = MutableSharedFlow<Pair<Direction?, Boolean>>()
val goToNextScreen = _goToNextScreen.asSharedFlow()
private val _navigateToOrderDetailsScreen = MutableSharedFlow<Boolean>()
val navigateToOrderDetailsScreen = _navigateToOrderDetailsScreen.asSharedFlow()
private val _billDetailsEntity = MutableStateFlow(value = payBillScreenSource.billDetailsEntity)
val billDetailsEntity = _billDetailsEntity.asStateFlow()
@@ -747,7 +750,9 @@ constructor(
paymentResponseMetadata.optString("uniqueTransactionReference") ?: ""
val upiRequestId = paymentResponseMetadata.optString("upiRequestId") ?: ""
val debitedFrom = paymentResponseMetadata.optString("debitedFrom") ?: ""
val orderReferenceId = paymentResponseMetadata.optString("tstoreOrderReferenceId") ?: ""
_orderReferenceId.update {
paymentResponseMetadata.optString("tstoreOrderReferenceId") ?: ""
}
val isArcProtected = paymentResponseMetadata.optBoolean("isArcProtected", false)
var planItemEntity: PlanItemEntity? = null
var billerLogoUrl = ""
@@ -803,7 +808,7 @@ constructor(
.toString()
.getDisplayableAmount(),
planName = planItemEntity?.planName ?: "",
orderReferenceId = orderReferenceId,
orderReferenceId = orderReferenceId.value,
transactionDetails =
TransactionDetailsEntity(
paymentTransactionId = paymentTransactionId,
@@ -859,7 +864,7 @@ constructor(
isArcProtected = isArcProtected,
paymentResponseMetadata = paymentResponseMetadata,
billCategoryEntity = billCategoryEntity,
orderReferenceId = orderReferenceId,
orderReferenceId = orderReferenceId.value,
billTransactionItemEntity = billTransactionItemEntity,
myBillEntity = myBillEntity,
status = status,
@@ -877,7 +882,7 @@ constructor(
myBillEntity = myBillEntity,
isSourcePaymentSummary = true,
isRootScreen = isRootScreen,
orderReferenceId = orderReferenceId,
orderReferenceId = orderReferenceId.value,
source = NaviBbpsScreen.NAVI_BBPS_PAY_BILL_SCREEN.name,
initialSource = initialSource,
isRepublicDayCelebrationExperimentEnabled =
@@ -895,7 +900,7 @@ constructor(
myBillEntity = myBillEntity,
isSourcePaymentSummary = true,
isRootScreen = isRootScreen,
orderReferenceId = orderReferenceId,
orderReferenceId = orderReferenceId.value,
source = NaviBbpsScreen.NAVI_BBPS_PAY_BILL_SCREEN.name,
initialSource = initialSource,
),
@@ -904,18 +909,22 @@ constructor(
)
}
} else {
_goToNextScreen.emit(
Pair(
BbpsTransactionDetailsScreenDestination(
billTransactionItemEntity = billTransactionItemEntity,
myBillEntity = myBillEntity,
isSourcePaymentSummary = true,
source = NaviBbpsScreen.NAVI_BBPS_PAY_BILL_SCREEN.name,
initialSource = initialSource,
),
true,
if (orderReferenceId.value.isEmpty()) {
_goToNextScreen.emit(
Pair(
BbpsTransactionDetailsScreenDestination(
billTransactionItemEntity = billTransactionItemEntity,
myBillEntity = myBillEntity,
isSourcePaymentSummary = true,
source = NaviBbpsScreen.NAVI_BBPS_PAY_BILL_SCREEN.name,
initialSource = initialSource,
),
true,
)
)
)
} else {
_navigateToOrderDetailsScreen.emit(true)
}
}
}
}

View File

@@ -73,16 +73,16 @@ import com.navi.bbps.common.ui.KeyValueTextSection
import com.navi.bbps.common.ui.NaviBbpsHeader
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.isCreditCardCategory
import com.navi.bbps.common.utils.clearBackStackUpToAndNavigate
import com.navi.bbps.common.utils.getDisplayableAmount
import com.navi.bbps.customHide
import com.navi.bbps.entry.NaviBbpsActivity
import com.navi.bbps.entry.NaviBbpsRouter
import com.navi.bbps.feature.category.model.view.BillCategoryEntity
import com.navi.bbps.feature.contactlist.model.view.PhoneContactEntity
import com.navi.bbps.feature.customerinput.model.view.BillerAdditionalParamsEntity
import com.navi.bbps.feature.customerinput.model.view.BillerDetailsEntity
import com.navi.bbps.feature.destinations.BillCategoriesScreenV2Destination
import com.navi.bbps.feature.destinations.MyBillHistoryDetailsScreenDestination
import com.navi.bbps.feature.mybills.model.view.MyBillEntity
import com.navi.bbps.feature.paybill.PayBillViewModel
@@ -94,6 +94,7 @@ import com.navi.bbps.feature.paybill.model.view.PayBillSource
import com.navi.bbps.feature.prepaidrecharge.model.view.OperatorItemEntity
import com.navi.common.R as CommonR
import com.navi.common.customview.LoaderRoundedButton
import com.navi.common.extensions.or
import com.navi.common.utils.stringToJsonObject
import com.navi.design.decorator.DashedDivider
import com.navi.design.font.FontWeightEnum
@@ -133,6 +134,7 @@ fun PayBillScreen(
naviBbpsAnalytics: NaviBbpsAnalytics.PayBill = NaviBbpsAnalytics.INSTANCE.PayBill(),
) {
val billDetailsEntity by payBillViewModel.billDetailsEntity.collectAsStateWithLifecycle()
val orderReferenceId by payBillViewModel.orderReferenceId.collectAsStateWithLifecycle()
val paymentsResultLauncher =
rememberLauncherForActivityResult(ActivityResultContracts.StartActivityForResult()) { result
->
@@ -204,21 +206,17 @@ fun PayBillScreen(
}
LaunchedEffect(Unit) {
payBillViewModel.goToNextScreen.collectLatest { nextScreen ->
val direction = nextScreen.first
val clearBackStack = nextScreen.second
if (direction != null) {
if (clearBackStack) {
navigator.clearBackStackUpToAndNavigate(
destination = direction,
popUpTo = BillCategoriesScreenV2Destination,
inclusive = false,
payBillViewModel.navigateToOrderDetailsScreen.collectLatest { navigateToOrderDetailsScreen
->
if (navigateToOrderDetailsScreen) {
val orderDetailsCtaData =
NaviBbpsCommonUtils.getOrderDetailsCtaDataForRedirection(
orderReferenceId = orderReferenceId
)
} else {
navigator.navigate(direction = direction)
}
} else {
navigator.navigateUp()
NaviBbpsRouter.onCtaClick(
naviBbpsActivity = naviBbpsActivity,
ctaData = orderDetailsCtaData,
)
}
}
}

View File

@@ -98,10 +98,10 @@ import com.navi.bbps.common.ui.NaviBbpsHeader
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.clearBackStackUpToAndNavigate
import com.navi.bbps.common.utils.getDisplayableAmount
import com.navi.bbps.customHide
import com.navi.bbps.entry.NaviBbpsActivity
@@ -111,7 +111,6 @@ import com.navi.bbps.feature.contactlist.model.view.PhoneContactEntity
import com.navi.bbps.feature.customerinput.model.view.BillDetailsEntity
import com.navi.bbps.feature.customerinput.model.view.BillerAdditionalParamsEntity
import com.navi.bbps.feature.customerinput.model.view.BillerDetailsEntity
import com.navi.bbps.feature.destinations.BillCategoriesScreenV2Destination
import com.navi.bbps.feature.destinations.MyBillHistoryDetailsScreenDestination
import com.navi.bbps.feature.mybills.model.view.MyBillEntity
import com.navi.bbps.feature.mybills.model.view.UnpaidBillDetails
@@ -213,7 +212,7 @@ fun PayBillScreenV2(
}
}
}
val orderReferenceId by payBillViewModelV2.orderReferenceId.collectAsStateWithLifecycle()
LaunchedEffect(Unit) {
naviBbpsActivity.errorEventHandler.bbpsErrorCtaClickEvent.collectLatest { event ->
// In case of bill fetch error, go back to previous screen
@@ -224,21 +223,17 @@ fun PayBillScreenV2(
}
LaunchedEffect(Unit) {
payBillViewModelV2.goToNextScreen.collectLatest { nextScreen ->
val direction = nextScreen.first
val clearBackStack = nextScreen.second
if (direction != null) {
if (clearBackStack) {
navigator.clearBackStackUpToAndNavigate(
destination = direction,
popUpTo = BillCategoriesScreenV2Destination,
inclusive = false,
payBillViewModelV2.navigateToOrderDetailsScreen.collectLatest { navigateToOrderDetailsScreen
->
if (navigateToOrderDetailsScreen) {
val orderDetailsCtaData =
NaviBbpsCommonUtils.getOrderDetailsCtaDataForRedirection(
orderReferenceId = orderReferenceId
)
} else {
navigator.navigate(direction = direction)
}
} else {
navigator.navigateUp()
NaviBbpsRouter.onCtaClick(
naviBbpsActivity = naviBbpsActivity,
ctaData = orderDetailsCtaData,
)
}
}
}

View File

@@ -22,11 +22,11 @@ object ArcStatusWidgetUtils {
fun prepareArcStatusWidgetProperties(
resourceProvider: ResourceProvider,
isArcProtected: Boolean,
orderStatusOfView: OrderStatusOfView,
categoryId: String,
productType: String,
isArcDelayed: Boolean,
isArcProtected: Boolean,
isArcRewardDisbursed: Boolean,
arcThresholdInDays: String,
orderTimestamp: DateTime,
@@ -36,6 +36,7 @@ object ArcStatusWidgetUtils {
if (!isArcProtected) {
return null
}
if (!isArcDelayed && (productType == OrderProductType.UPI.name)) {
return null
}

View File

@@ -104,7 +104,12 @@ internal fun PaymentStatusSection(
fontWeight = getFontWeight(FontWeightEnum.NAVI_BODY_DEMI_BOLD),
fontSize = 14.sp,
lineHeight = 22.sp,
color = NaviPayColor.bgSuccess,
color =
if (orderEntity?.paymentStatus == OrderPaymentStatus.SUCCESS) {
NaviPayColor.bgSuccess
} else {
NaviPayColor.textTertiary
},
maxLines = 1,
overflow = TextOverflow.Ellipsis,
modifier =
@@ -113,7 +118,15 @@ internal fun PaymentStatusSection(
val strokeWidth = 1.5.dp.toPx()
val verticalCenter = size.height / 2
drawLine(
color = NaviPayColor.bgSuccess,
color =
if (
orderEntity?.paymentStatus ==
OrderPaymentStatus.SUCCESS
) {
NaviPayColor.bgSuccess
} else {
NaviPayColor.textTertiary
},
strokeWidth = strokeWidth,
start = Offset(-4.dp.toPx(), verticalCenter.toFloat()),
end =
@@ -272,12 +285,12 @@ private fun CoinDiscountBanner(
Image(
painter = painterResource(id = CommonR.drawable.ic_np_coin),
contentDescription = EMPTY,
modifier = Modifier.size(14.dp).align(Alignment.CenterVertically),
modifier = Modifier.size(16.dp).align(Alignment.CenterVertically),
)
Spacer(modifier = Modifier.width(2.dp))
NaviText(
text = coinsUsed,
color = NaviPayColor.textWhite,
color = NaviPayColor.textPrimary,
fontSize = 12.sp,
lineHeight = 16.sp,
fontFamily = naviFontFamily,
@@ -297,9 +310,14 @@ private fun CoinDiscountBanner(
fontFamily = naviFontFamily,
lineHeight = 16.sp,
fontWeight = getFontWeight(FontWeightEnum.NAVI_BODY_REGULAR),
color = NaviPayColor.textWhite,
color =
if (paymentStatus == OrderPaymentStatus.SUCCESS) {
NaviPayColor.textWhite
} else {
NaviPayColor.textPrimary
},
)
if (paymentStatus != OrderPaymentStatus.PENDING) {
if (paymentStatus == OrderPaymentStatus.SUCCESS) {
Spacer(modifier = Modifier.width(4.dp))
Image(
painter = painterResource(id = CommonR.drawable.ic_np_coin),

View File

@@ -1004,30 +1004,29 @@ constructor(
if (orderEntity.value?.isArcProtected.orFalse()) {
_arcStatusWidgetProperties.update {
if (orderEntity.value == null) {
null
} else {
orderEntity.value?.let { orderEntity ->
ArcStatusWidgetUtils.prepareArcStatusWidgetProperties(
isArcProtected = orderEntity.isArcProtected,
categoryId =
orderDetailsMetadataProvider.value
.getBbpsMetadata()
?.categoryId
.orEmpty(),
resourceProvider = resourceProvider,
isArcProtected = orderEntity.value!!.isArcProtected,
orderStatusOfView = orderEntity.value!!.orderStatusOfView,
productType = orderEntity.value!!.productType,
isArcDelayed = orderEntity.value!!.isArcDelayed,
isArcRewardDisbursed = orderEntity.value!!.isArcRewardDisbursed,
orderTimestamp = orderEntity.value!!.orderTimestamp,
orderStatusOfView = orderEntity.orderStatusOfView,
productType = orderEntity.productType,
isArcDelayed = orderEntity.isArcDelayed,
isArcRewardDisbursed = orderEntity.isArcRewardDisbursed,
orderTimestamp = orderEntity.orderTimestamp,
arcThresholdInDays = arcNudgeCoinDaysPair.value.second,
orderTerminalTimestampFormatted =
orderEntity.value!!.orderTerminalTimestampFormatted,
orderEntity.orderTerminalTimestampFormatted,
)
}
}
if (orderEntity.value?.isArcRewardDisbursed.orFalse()) {
_arcRewardCoins.update { orderEntity.value?.arcRewardCoins.orEmpty() }
return
}
@@ -1037,6 +1036,7 @@ constructor(
_arcCoinsPromiseValueStateType.update {
ArcCoinsPromiseValueStateType.ExactValue
}
_arcRewardCoins.update { orderEntity.value?.arcRewardCoins.orEmpty() }
_showArcBottomSheetOnWidgetClick.update { true }
return
}

View File

@@ -7,10 +7,10 @@
package com.navi.pay.tstore.list.model.network
import android.os.Parcelable
import com.google.gson.Gson
import com.google.gson.annotations.SerializedName
import com.navi.base.utils.orFalse
import com.navi.common.extensions.or
import com.navi.pay.common.utils.NaviPayCommonUtils.getDateTimeObjectFromEpochString
import com.navi.pay.common.utils.NaviPayCommonUtils.getTagStringWithSeparator
import com.navi.pay.management.common.transaction.util.getMonthTag
@@ -31,6 +31,7 @@ import com.navi.pay.utils.NAVI_PAY_UPI_LITE_LOGO_URL
import com.navi.pay.utils.NAVI_PAY_UPI_LITE_SEND_MONEY_PURPOSE_CODE
import com.navi.rr.utils.ext.toJson
import java.lang.reflect.Type
import kotlinx.parcelize.Parcelize
import org.json.JSONObject
data class OrderItem(
@@ -54,6 +55,7 @@ data class OrderItem(
@SerializedName("isArcDelayed") val isArcDelayed: Boolean?,
@SerializedName("orderTerminalTimestamp") val orderTerminalTimestamp: String?,
@SerializedName("orderDetails") val orderDetails: OrderDetailsResponse?,
@SerializedName("rewardList") val rewardList: List<RewardMetadata>?,
)
data class OrderDetailsResponse(
@@ -61,9 +63,9 @@ data class OrderDetailsResponse(
@SerializedName("refundUtr") val refundUtr: String?,
@SerializedName("coinsUsed") val coinsUsed: String?,
@SerializedName("coinEquivalentCash") val coinEquivalentCash: String?,
@SerializedName("rewardDetails") val rewardDetails: List<RewardMetadata>?,
)
@Parcelize
data class RewardMetadata(
@SerializedName("rewardReferenceId") val rewardReferenceId: String?,
@SerializedName("eventId") val eventId: String?,
@@ -71,7 +73,7 @@ data class RewardMetadata(
@SerializedName("expiryTimestampMs") val expiryTimeStampMs: String?,
@SerializedName("isArcReward") val isArcReward: Boolean?,
@SerializedName("status") val status: String?,
)
) : Parcelable
fun OrderItem.toOrderEntity(
gson: Gson,
@@ -187,7 +189,7 @@ fun OrderItem.toOrderEntity(
coinEquivalentCash = orderDetails?.coinEquivalentCash.orEmpty(),
orderTerminalTimestamp = orderTerminalTimestamp,
isArcDelayed = isArcDelayed.orFalse(),
rewardDetails = orderDetails?.rewardDetails?.let { gson.toJson(it) },
rewardList = rewardList,
),
)
}

View File

@@ -9,6 +9,7 @@ package com.navi.pay.tstore.list.model.view
import android.os.Parcelable
import com.google.gson.annotations.SerializedName
import com.navi.pay.tstore.list.model.network.RewardMetadata
import kotlinx.parcelize.Parcelize
@Parcelize
@@ -20,5 +21,5 @@ data class OrderDetailEntity(
@SerializedName("refundUtr") val refundUtr: String?,
@SerializedName("coinsUsed") val coinsUsed: String?,
@SerializedName("coinEquivalentCash") val coinEquivalentCash: String?,
@SerializedName("rewardDetails") val rewardDetails: String? = null,
@SerializedName("rewardList") val rewardList: List<RewardMetadata>? = null,
) : Parcelable

View File

@@ -33,7 +33,6 @@ import com.navi.pay.tstore.details.ui.upi.NaviPayTransactionDetailsMetadata
import com.navi.pay.tstore.details.util.OrderDetailsMetadataProvider
import com.navi.pay.tstore.list.db.converter.OrderDetailConverter
import com.navi.pay.tstore.list.model.network.OrderType
import com.navi.pay.tstore.list.model.network.RewardMetadata
import com.navi.pay.tstore.list.util.OrderPaymentModeConverter
import com.navi.pay.tstore.list.util.OrderPaymentStatusConverter
import com.navi.pay.tstore.list.util.OrderStatusOfViewConverter
@@ -243,33 +242,22 @@ data class OrderEntity(
@IgnoredOnParcel
@delegate:Ignore
val rewardDetails: List<RewardMetadata> by lazy {
if (!orderDetails.rewardDetails.isNullOrEmpty()) {
nonNullableGson
.fromJson(
JSONObject(orderDetails.rewardDetails).toString(),
Array<RewardMetadata>::class.java,
)
.toList()
} else {
emptyList()
}
val arcRewardCoins by lazy {
orderDetails.rewardList?.find { it.isArcReward == true }?.coins.orEmpty()
}
@IgnoredOnParcel
@delegate:Ignore
val arcRewardCoins by lazy { rewardDetails.find { it.isArcReward == true }?.coins.orEmpty() }
@IgnoredOnParcel
@delegate:Ignore
val isArcRewardDisbursed by lazy {
rewardDetails.any { it.isArcReward == true && it.status == RewardStatus.COMPLETED.name }
orderDetails.rewardList
?.any { it.isArcReward == true && it.status == RewardStatus.COMPLETED.name }
.orFalse()
}
@IgnoredOnParcel
@delegate:Ignore
val arcRewardReferenceId by lazy {
rewardDetails.find { it.isArcReward == true }?.rewardReferenceId.orEmpty()
orderDetails.rewardList?.find { it.isArcReward == true }?.rewardReferenceId.orEmpty()
}
private fun isTransactionViaLite(): Boolean {