NTP-63647 | Sidharth Bamba | Bug fix for timestamp changes after scratch card (#16462)

This commit is contained in:
Sidharth Bamba
2025-06-30 16:02:26 +05:30
committed by GitHub
parent 8dc7c830e9
commit f01dfa4208
6 changed files with 84 additions and 39 deletions

View File

@@ -636,5 +636,19 @@ val NAVI_PAY_APP_DATABASE_MIGRATION_21_22 =
db.execSQL(
"ALTER TABLE `$NAVI_PAY_DATABASE_VPA_TABLE_NAME` ADD COLUMN `vpaReason` TEXT NOT NULL DEFAULT 'UNKNOWN'"
)
/*
* Migration to fix orderTimestamp format inconsistency causing sorting issues.
*
* Problem: Order history had mixed timestamp formats:
* - Network sync: UTC format (2025-06-18T12:10:19.673Z)
* - Local transactions: IST format (2025-06-18T17:34:34.452+05:30)
*
* Solution: Force re-sync from server to get all data in consistent UTC format.
* This ensures proper chronological sorting in order history.
*/
db.execSQL(
"DELETE FROM $NAVI_PAY_DATABASE_SYNC_TABLE_NAME WHERE syncKey = '$NAVI_PAY_SYNC_TABLE_ORDER_HISTORY_KEY'"
)
}
}

View File

@@ -779,6 +779,10 @@ constructor(
orderEntity?.let { currentOrder ->
val updateOrderEntity =
currentOrder.copy(
orderTimestamp =
getDateTimeObjectFromEpochString(
epochMillis = currentOrder.orderTimestamp.millis
),
orderDetails =
currentOrder.orderDetails.let { currentOrderDetails ->
currentOrderDetails.copy(
@@ -792,12 +796,6 @@ constructor(
}
)
},
orderTimestamp =
getDateTimeObjectFromEpochString(
epochMillis = currentOrder.orderTimestamp.millis
),
// updating timestamp here to maintain consistent format in
// local db if the db entry is not updated by api response
)
orderDetailsRepository.updateOrder(orderEntity = updateOrderEntity)
}

View File

@@ -29,6 +29,7 @@ import com.navi.pay.tstore.list.model.view.OrderPaymentMode
import com.navi.pay.tstore.list.model.view.OrderStatusOfView
import com.navi.pay.utils.NAVI_PAY_TRANSACTION_HISTORY_TAG_SEPARATOR
import com.navi.rr.utils.ext.toJson
import org.joda.time.DateTimeZone
internal fun TransactionEntity.toOrderEntity(tstoreOrderId: String): OrderEntity =
OrderEntity(
@@ -49,7 +50,7 @@ internal fun TransactionEntity.toOrderEntity(tstoreOrderId: String): OrderEntity
orderTitle = getOrderTitleToDisplay(),
paymentMode = OrderPaymentMode.UPI,
orderDescription = getOrderDescriptionToDisplay(),
orderTimestamp = transactionTimestamp,
orderTimestamp = transactionTimestamp.withZone(DateTimeZone.UTC),
orderImageUrl =
otherUserInfo.split(NAVI_PAY_TRANSACTION_HISTORY_TAG_SEPARATOR).getOrElse(3) {
""

View File

@@ -23,6 +23,7 @@ import com.navi.payments.shared.core.network.service.PaymentsSharedRetrofitServi
import com.navi.payments.shared.feature.arc.model.network.ArcExactOfferRequest
import com.navi.payments.shared.feature.arc.model.network.ArcExactOfferResponse
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
class OrderDetailsRepository
@Inject
@@ -50,6 +51,10 @@ constructor(
return orderDao.getOrderEntity(orderId)
}
fun getOrderEntityAsFlow(orderId: String): Flow<OrderEntity?> {
return orderDao.getOrderEntityAsFlow(orderId)
}
suspend fun updateNotificationsPermission(
notificationSettings: List<NotificationSettings>
): RepoResult<Unit> {

View File

@@ -191,10 +191,14 @@ import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@@ -252,8 +256,16 @@ constructor(
savedStateHandle.get<String>("orderReferenceId")?.takeIf { it.isNotEmpty() }
?: naviPayActivityDataProvider.getString("orderReferenceId").orEmpty()
private val _orderEntity = MutableStateFlow<OrderEntity?>(null)
val orderEntity = _orderEntity.asStateFlow()
val orderEntity =
orderDetailsRepository
.getOrderEntityAsFlow(orderId = orderReferenceId)
.flowOn(dispatcherProvider.io)
.distinctUntilChanged()
.stateIn(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(),
initialValue = null,
)
private val _linkedAccounts = MutableStateFlow<List<LinkedAccountEntity>>(emptyList())
val linkedAccounts = _linkedAccounts.asStateFlow()
@@ -588,13 +600,25 @@ constructor(
private suspend fun getOrderDetails(): IsError {
val orderDetails = orderDetailsRepository.getOrderEntity(orderId = orderReferenceId)
val orderDetails = orderEntity.first { it != null }
if (orderDetails == null) {
_clearAndNavigateBack.emit(true)
return true
}
updateOrderEntity(orderEntity = orderDetails)
if (orderDetails.paymentStatus.isFailed() || orderDetails.orderStatusOfView.isFailed()) {
val orderErrorEntity =
orderErrorMappingManager.getErrorEntityByCode(
errorCode = orderDetails.orderDetails.errorCode
)
naviPayAnalytics.onOrderErrorDetailsFetchedDevEvent(
errorCode = orderDetails.orderDetails.errorCode.orEmpty(),
orderErrorEntity = orderErrorEntity,
isExperimentEnabled = true,
productType = orderDetails.productType,
)
_orderErrorEntity.update { orderErrorEntity }
}
_orderDetailsMetadataProvider.update {
OrderDetailsMetadataProvider(orderEntity = orderEntity.value)
@@ -1578,11 +1602,15 @@ constructor(
val arcExactOfferResponseData = arcExactOfferResponse.data!!
val updatedOrderEntity =
_orderEntity.value?.copy(
orderEntity.value?.copy(
orderTimestamp =
getDateTimeObjectFromEpochString(
orderEntity.value?.orderTimestamp?.millis ?: 0L
),
orderDetails =
orderEntity.value
?.orderDetails!!
.copy(isArcProtected = arcExactOfferResponseData.isArcProtected.orFalse())
.copy(isArcProtected = arcExactOfferResponseData.isArcProtected.orFalse()),
)
updateOrderEntity(orderEntity = updatedOrderEntity)
@@ -1673,7 +1701,11 @@ constructor(
(orderEntity.value?.paymentStatus != newPaymentStatus)
val updatedOrderEntity =
_orderEntity.value?.copy(
orderEntity.value?.copy(
orderTimestamp =
getDateTimeObjectFromEpochString(
epochMillis = orderEntity.value?.orderTimestamp?.millis ?: 0L
),
orderDetails =
orderEntity.value
?.orderDetails!!
@@ -1682,11 +1714,8 @@ constructor(
paymentStatus = newPaymentStatus,
)
updateOrderEntity(orderEntity = updatedOrderEntity)
if (isStatusChanged) {
orderDetailsRepository.updateOrder(orderEntity = orderEntity.value!!)
getOrderDetails()
updateOrderEntity(orderEntity = updatedOrderEntity!!)
prepareArcStatusWidgetProperties()
if (
newOrderStatusOfView != OrderStatusOfView.Pending ||
@@ -1700,6 +1729,7 @@ constructor(
launch { liteAccountSyncUseCase.execute(screenName = screenName) }
}
}
preparePaymentStatusWidgetProperties()
}
prepareRefundStatusWidgetProperties()
@@ -1948,9 +1978,13 @@ constructor(
updateScratchCardStatus(ScratchCardState.None)
_orderEntity.value?.let { currentOrder ->
orderEntity.value?.let { currentOrder ->
val updatedOrder =
currentOrder.copy(
orderTimestamp =
getDateTimeObjectFromEpochString(
currentOrder.orderTimestamp.millis
),
orderDetails =
currentOrder.orderDetails.let { currentOrderDetails ->
currentOrderDetails.copy(
@@ -1966,17 +2000,9 @@ constructor(
}
)
},
orderTimestamp =
getDateTimeObjectFromEpochString(
epochMillis = currentOrder.orderTimestamp.millis
),
// updating timestamp here to maintain consistent format in
// local db if the db entry is not updated by api response
)
updateOrderEntity(updatedOrder)
orderDetailsRepository.updateOrder(orderEntity = updatedOrder)
}
_orderEntity.value?.let { orderDetailsRepository.updateOrder(it) }
}
is ScratchCardBackResponse.Success -> {
@@ -2005,9 +2031,13 @@ constructor(
}
)
_orderEntity.value?.let { currentOrder ->
orderEntity.value?.let { currentOrder ->
val updatedOrder =
currentOrder.copy(
orderTimestamp =
getDateTimeObjectFromEpochString(
currentOrder.orderTimestamp.millis
),
orderDetails =
currentOrder.orderDetails.let { currentOrderDetails ->
currentOrderDetails.copy(
@@ -2023,17 +2053,9 @@ constructor(
}
)
},
orderTimestamp =
getDateTimeObjectFromEpochString(
epochMillis = currentOrder.orderTimestamp.millis
),
// updating timestamp here to maintain consistent format in
// local db if the db entry is not updated by api response
)
updateOrderEntity(updatedOrder)
orderDetailsRepository.updateOrder(orderEntity = updatedOrder)
}
_orderEntity.value?.let { orderDetailsRepository.updateOrder(it) }
}
else -> {}
@@ -2045,7 +2067,7 @@ constructor(
private suspend fun updateOrderEntity(orderEntity: OrderEntity?) {
if (orderEntity == null) return
_orderEntity.update { orderEntity }
orderDetailsRepository.updateOrder(orderEntity = orderEntity)
if (orderEntity.paymentStatus.isFailed() || orderEntity.orderStatusOfView.isFailed()) {
val orderErrorEntity =

View File

@@ -32,6 +32,11 @@ interface OrderDao {
)
suspend fun getOrderEntity(orderId: String): OrderEntity?
@Query(
"SELECT * FROM $NAVI_PAY_DATABASE_T_STORE_ORDER_HISTORY_TABLE_NAME WHERE orderReferenceId = :orderId"
)
fun getOrderEntityAsFlow(orderId: String): Flow<OrderEntity?>
@Update suspend fun updateOrderEntity(orderEntity: OrderEntity)
@Query(