From 15e64fccb59e45bd31b96cb4f1ec04b4c0d6d624 Mon Sep 17 00:00:00 2001 From: vedant aggarwal Date: Tue, 18 Feb 2025 13:59:17 +0530 Subject: [PATCH] NTP-14194 | Vedant Aggarwal | Supported PSP changes (#14979) --- .../model/config/NaviPayPspSelectionConfig.kt | 19 +--- .../setup/NaviPayCustomerStatusHandler.kt | 98 +++++++++++-------- ...teCustomerStatusOnAccountRemovalUseCase.kt | 1 + .../common/utils/NaviPayPspManager.kt | 67 ++++++++----- 4 files changed, 101 insertions(+), 84 deletions(-) diff --git a/android/navi-pay/src/main/kotlin/com/navi/pay/common/model/config/NaviPayPspSelectionConfig.kt b/android/navi-pay/src/main/kotlin/com/navi/pay/common/model/config/NaviPayPspSelectionConfig.kt index 17a2b2c95c..36896acbec 100644 --- a/android/navi-pay/src/main/kotlin/com/navi/pay/common/model/config/NaviPayPspSelectionConfig.kt +++ b/android/navi-pay/src/main/kotlin/com/navi/pay/common/model/config/NaviPayPspSelectionConfig.kt @@ -9,7 +9,6 @@ package com.navi.pay.common.model.config import com.google.gson.annotations.SerializedName import com.navi.pay.common.model.view.NaviPayFlowType -import com.navi.pay.common.model.view.PspType data class NaviPayPspSelectionConfig( @SerializedName("config") val config: PspSelectionConfigContent = PspSelectionConfigContent(), @@ -17,14 +16,6 @@ data class NaviPayPspSelectionConfig( ) data class PspSelectionConfigContent( - @SerializedName("flowToMandatoryBucketMap") - val flowToMandatoryBucketMap: Map = - mapOf( - NaviPayFlowType.LITE_AUTO_TOP_UP to "mandate_1", - NaviPayFlowType.UPI_INTERNATIONAL to "mandate_2", - NaviPayFlowType.RCC_BILL_PAYMENTS to "mandate_3", - NaviPayFlowType.EMI_CONVERSION to "mandate_4", - ), @SerializedName("flowToRoutingBucketMap") val flowToRoutingBucketMap: Map = mapOf( @@ -34,13 +25,5 @@ data class PspSelectionConfigContent( NaviPayFlowType.CHECK_BALANCE to "bucket_4", NaviPayFlowType.PIN_MANAGEMENT to "bucket_4", NaviPayFlowType.QR_HANDLING to "bucket_5", - ), - @SerializedName("mandatoryBucketToPspListMap") - val mandatoryBucketToPspListMap: Map> = - mapOf( - "mandate_1" to listOf(PspType.JUSPAY), - "mandate_2" to listOf(PspType.JUSPAY), - "mandate_3" to listOf(PspType.JUSPAY), - "mandate_4" to listOf(PspType.JUSPAY), - ), + ) ) diff --git a/android/navi-pay/src/main/kotlin/com/navi/pay/common/setup/NaviPayCustomerStatusHandler.kt b/android/navi-pay/src/main/kotlin/com/navi/pay/common/setup/NaviPayCustomerStatusHandler.kt index f16c70a2d3..8033f1ec19 100644 --- a/android/navi-pay/src/main/kotlin/com/navi/pay/common/setup/NaviPayCustomerStatusHandler.kt +++ b/android/navi-pay/src/main/kotlin/com/navi/pay/common/setup/NaviPayCustomerStatusHandler.kt @@ -14,6 +14,8 @@ import com.navi.pay.common.setup.model.NaviPayCustomerStatus import com.navi.pay.common.utils.toggleNaviPayIntentActivityEnableState import com.navi.pay.onboarding.binding.repository.NaviPayOnboardingRepository import javax.inject.Inject +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext class NaviPayCustomerStatusHandler @Inject @@ -23,51 +25,61 @@ constructor( ) { suspend fun getAllCustomerOnboardingData() = - naviPayOnboardingRepository.getAllCustomerOnboardingData() + withContext(Dispatchers.IO) { naviPayOnboardingRepository.getAllCustomerOnboardingData() } suspend fun getCustomerStatus(pspType: PspType): NaviPayCustomerStatus { - val customerOnboardingEntity = - naviPayOnboardingRepository.getCustomerOnboardingEntity(pspType = pspType) - return customerOnboardingEntity?.customerStatus ?: NaviPayCustomerStatus.NOT_SET + return withContext(Dispatchers.IO) { + val customerOnboardingEntity = + naviPayOnboardingRepository.getCustomerOnboardingEntity(pspType = pspType) + customerOnboardingEntity?.customerStatus ?: NaviPayCustomerStatus.NOT_SET + } } suspend fun isUserOnboarded(pspType: PspType): Boolean { - val customerOnboardingEntity = - naviPayOnboardingRepository.getCustomerOnboardingEntity(pspType = pspType) - return customerOnboardingEntity?.customerStatus == NaviPayCustomerStatus.LINKED_VPA + return withContext(Dispatchers.IO) { + val customerOnboardingEntity = + naviPayOnboardingRepository.getCustomerOnboardingEntity(pspType = pspType) + customerOnboardingEntity?.customerStatus == NaviPayCustomerStatus.LINKED_VPA + } } suspend fun isUserOnboardedForAnyPsp(): Boolean { - val customerEntityList = naviPayOnboardingRepository.getAllCustomerOnboardingData() - - return customerEntityList.any { onboardingDataEntity -> - onboardingDataEntity.customerStatus == NaviPayCustomerStatus.LINKED_VPA + return withContext(Dispatchers.IO) { + val customerEntityList = naviPayOnboardingRepository.getAllCustomerOnboardingData() + customerEntityList.any { onboardingDataEntity -> + onboardingDataEntity.customerStatus == NaviPayCustomerStatus.LINKED_VPA + } } } suspend fun isUserDeviceBoundForAnyPsp(): Boolean { - val customerEntityList = naviPayOnboardingRepository.getAllCustomerOnboardingData() - - return customerEntityList.any { onboardingDataEntity -> - onboardingDataEntity.customerStatus.isBound + return withContext(Dispatchers.IO) { + val customerEntityList = naviPayOnboardingRepository.getAllCustomerOnboardingData() + customerEntityList.any { onboardingDataEntity -> + onboardingDataEntity.customerStatus.isBound + } } } suspend fun getCustomerStatusMap(): Map { - val customerEntityList = naviPayOnboardingRepository.getAllCustomerOnboardingData() - return customerEntityList.associate { it.pspType to it.customerStatus } + return withContext(Dispatchers.IO) { + val customerEntityList = naviPayOnboardingRepository.getAllCustomerOnboardingData() + customerEntityList.associate { it.pspType to it.customerStatus } + } } suspend fun updateCustomerStatusAndHandleNaviPayIntentActivityState( pspType: PspType, customerStatus: NaviPayCustomerStatus, ) { - naviPayOnboardingRepository.upsertCustomerOnboardingDataEntity( - pspType = pspType, - customerStatus = customerStatus, - ) - naviPaySessionHelper.setCustomerStatus(customerStatus = customerStatus.name) - checkAndUpdateNaviPayIntentActivity() + withContext(Dispatchers.IO) { + naviPayOnboardingRepository.upsertCustomerOnboardingDataEntity( + pspType = pspType, + customerStatus = customerStatus, + ) + naviPaySessionHelper.setCustomerStatus(customerStatus = customerStatus.name) + checkAndUpdateNaviPayIntentActivity() + } } suspend fun upsertCustomerOnboardingDataEntity( @@ -76,28 +88,34 @@ constructor( merchantCustomerId: String? = null, deviceFingerPrint: String? = null, ) { - naviPayOnboardingRepository.upsertCustomerOnboardingDataEntity( - pspType = pspType, - customerStatus = customerStatus, - merchantCustomerId = merchantCustomerId, - deviceFingerPrint = deviceFingerPrint, - ) - checkAndUpdateNaviPayIntentActivity() + withContext(Dispatchers.IO) { + naviPayOnboardingRepository.upsertCustomerOnboardingDataEntity( + pspType = pspType, + customerStatus = customerStatus, + merchantCustomerId = merchantCustomerId, + deviceFingerPrint = deviceFingerPrint, + ) + checkAndUpdateNaviPayIntentActivity() + } } private suspend fun checkAndUpdateNaviPayIntentActivity() { - if (isUserOnboardedForAnyPsp()) { - toggleNaviPayIntentActivityEnableState(shouldEnable = true) - } else if ( - FirebaseRemoteConfigHelper.getBoolean( - key = FirebaseRemoteConfigHelper.NAVI_PAY_INTENT_ACTIVITY_CHECK_ENABLED, - defaultValue = true, - ) - ) { - toggleNaviPayIntentActivityEnableState(shouldEnable = false) + withContext(Dispatchers.IO) { + if (isUserOnboardedForAnyPsp()) { + toggleNaviPayIntentActivityEnableState(shouldEnable = true) + } else if ( + FirebaseRemoteConfigHelper.getBoolean( + key = FirebaseRemoteConfigHelper.NAVI_PAY_INTENT_ACTIVITY_CHECK_ENABLED, + defaultValue = true, + ) + ) { + toggleNaviPayIntentActivityEnableState(shouldEnable = false) + } } } suspend fun getCustomerOnboardingEntity(pspType: PspType) = - naviPayOnboardingRepository.getCustomerOnboardingEntity(pspType) + withContext(Dispatchers.IO) { + naviPayOnboardingRepository.getCustomerOnboardingEntity(pspType) + } } diff --git a/android/navi-pay/src/main/kotlin/com/navi/pay/common/usecase/UpdateCustomerStatusOnAccountRemovalUseCase.kt b/android/navi-pay/src/main/kotlin/com/navi/pay/common/usecase/UpdateCustomerStatusOnAccountRemovalUseCase.kt index ba933dc5fe..f6b00c1a89 100644 --- a/android/navi-pay/src/main/kotlin/com/navi/pay/common/usecase/UpdateCustomerStatusOnAccountRemovalUseCase.kt +++ b/android/navi-pay/src/main/kotlin/com/navi/pay/common/usecase/UpdateCustomerStatusOnAccountRemovalUseCase.kt @@ -72,6 +72,7 @@ constructor( pspType: PspType, ): Boolean = linkedAccountEntity.vpaEntityList.any { vpaEntity -> + // TODO: Multibank - Add VPA status check in M1 Account Management PspType.fromVpa(vpaEntity.vpa) == pspType } } diff --git a/android/navi-pay/src/main/kotlin/com/navi/pay/management/common/utils/NaviPayPspManager.kt b/android/navi-pay/src/main/kotlin/com/navi/pay/management/common/utils/NaviPayPspManager.kt index 16436d66f2..9c9369c8b1 100644 --- a/android/navi-pay/src/main/kotlin/com/navi/pay/management/common/utils/NaviPayPspManager.kt +++ b/android/navi-pay/src/main/kotlin/com/navi/pay/management/common/utils/NaviPayPspManager.kt @@ -456,20 +456,8 @@ constructor( } ?: PspEvaluationResult() } - private fun getSupportedPspList( - naviPayFlowType: NaviPayFlowType, - pspSelectionConfig: PspSelectionConfigContent, - ): List { - val mandatoryBucket = pspSelectionConfig.flowToMandatoryBucketMap[naviPayFlowType] - val mandatoryPspList = - mandatoryBucket?.let { pspSelectionConfig.mandatoryBucketToPspListMap[it] } - ?: PspType.entries - return mandatoryPspList - } - private suspend fun getBoundPspList(supportedPspList: List): List { val pspCustomerStatusMap = naviPayCustomerStatusHandler.getCustomerStatusMap() - if (supportedPspList.isEmpty()) { return emptyList() } @@ -487,6 +475,21 @@ constructor( } } + private suspend fun getSupportedPspList( + naviPayFlowType: NaviPayFlowType, + pspSelectionConfig: PspSelectionConfigContent, + ): List { + val pspDistributionMap = + getPspDistributionMap( + naviPayFlowType = naviPayFlowType, + pspSelectionConfig = pspSelectionConfig, + ) ?: return PspType.entries + return pspDistributionMap + .filter { (pspType, weight) -> weight > 0 && PspType.entries.contains(pspType) } + .keys + .toList() + } + /** * Determines the PSP based on routing logic and weighted distribution. If only one PSP exists, * it is directly selected. Otherwise, weights are used for random selection. @@ -505,22 +508,14 @@ constructor( if (pspList.size == 1) return pspList[0] - val routingBucketsJson = - naviCacheRepository.get(key = NAVI_PAY_PSP_ROUTING_BUCKETS_KEY)?.value - // TODO: Multibank - return null after Olympus is live - if (routingBucketsJson.isNullOrBlank()) return PspType.JUSPAY - - val type = object : TypeToken>>() {}.type - val routingBucketsMap: Map> = - gson.fromJson(routingBucketsJson, type) - - val routingBucket = - pspSelectionConfig.flowToRoutingBucketMap[naviPayFlowType] ?: return pspList[0] - - val originalDistribution = routingBucketsMap[routingBucket] ?: return pspList[0] + val pspDistributionMap = + getPspDistributionMap( + naviPayFlowType = naviPayFlowType, + pspSelectionConfig = pspSelectionConfig, + ) ?: return PspType.entries[0] val filteredDistribution = - originalDistribution + pspDistributionMap .filterKeys { pspType -> pspList.any { it == pspType } } .toMutableMap() @@ -543,6 +538,26 @@ constructor( return null } + private suspend fun getPspDistributionMap( + naviPayFlowType: NaviPayFlowType, + pspSelectionConfig: PspSelectionConfigContent, + ): Map? { + val routingBucketsJson = + naviCacheRepository.get(key = NAVI_PAY_PSP_ROUTING_BUCKETS_KEY)?.value + if (routingBucketsJson.isNullOrBlank()) return null + + val type = object : TypeToken>>() {}.type + val routingBucketsMap: Map> = + gson.fromJson(routingBucketsJson, type) + + val routingBucket = + pspSelectionConfig.flowToRoutingBucketMap[naviPayFlowType] ?: return null + + return routingBucketsMap[routingBucket] + ?.mapNotNull { (pspName, weight) -> PspType.fromName(pspName)?.let { it to weight } } + ?.toMap() + } + private suspend fun getPspSelectionConfig(): PspSelectionConfigContent { val naviPayDefaultAccountSelectionConfig = withContext(Dispatchers.IO) {