diff --git a/android/navi-pay/src/main/kotlin/com/navi/pay/common/usecase/ValidateVpaUseCase.kt b/android/navi-pay/src/main/kotlin/com/navi/pay/common/usecase/ValidateVpaUseCase.kt index db4cce65f9..0a20e0d2b0 100644 --- a/android/navi-pay/src/main/kotlin/com/navi/pay/common/usecase/ValidateVpaUseCase.kt +++ b/android/navi-pay/src/main/kotlin/com/navi/pay/common/usecase/ValidateVpaUseCase.kt @@ -19,7 +19,6 @@ import com.navi.pay.common.model.network.ValidateVpaRequest import com.navi.pay.common.model.network.ValidateVpaResponse import com.navi.pay.common.model.view.NaviPayFlowType import com.navi.pay.common.model.view.NaviPaySessionHelper -import com.navi.pay.common.model.view.PspType import com.navi.pay.common.repository.CommonRepository import com.navi.pay.common.setup.NaviPayCustomerStatusHandler import com.navi.pay.common.utils.getMetricInfo @@ -27,7 +26,6 @@ import com.navi.pay.common.validatevpa.model.view.ValidateVpaEntity import com.navi.pay.management.common.utils.NaviPayPspManager import com.navi.pay.management.paytocontacts.model.network.PayToContactRequest import com.navi.pay.network.di.NaviPayGsonBuilder -import com.navi.pay.onboarding.account.common.repository.AccountsRepository import com.navi.pay.onboarding.binding.model.view.NaviPayCustomerOnboardingEntity import com.navi.pay.utils.DEFAULT_RETRY_COUNT import com.navi.pay.utils.RETRY_INTERVAL_IN_SECONDS @@ -48,7 +46,6 @@ constructor( private val naviPaySessionHelper: NaviPaySessionHelper, private val naviPayPspManager: NaviPayPspManager, private val naviPayCustomerStatusHandler: NaviPayCustomerStatusHandler, - private val accountsRepository: AccountsRepository, @NaviPayGsonBuilder private val gson: Gson, ) { val naviPayAnalytics = NaviPayAnalytics.INSTANCE.NaviPayValidateVpaUseCase() @@ -65,25 +62,22 @@ constructor( naviPayAnalytics.onValidateVpaStart( naviPaySessionAttributes = naviPaySessionHelper.getNaviPaySessionAttributes() ) - val isCustomerExists = isCustomerExistsOnAnySupportedPsp(screenName) + val pspTypesWhereCustomerExists = + naviPayPspManager.getSupportedPspListWhereCustomerExists( + naviPayFlowType = NaviPayFlowType.VALIDATE_VPA, + screenName = screenName, + ) + val isCustomerExists = pspTypesWhereCustomerExists.isNotEmpty() if (!skipCustomerOnboardingCheck && !isCustomerExists) { naviPayAnalytics.onValidateVpaAbort(naviPaySessionHelper.getNaviPaySessionAttributes()) return null // early return } var customerOnboardingEntity: NaviPayCustomerOnboardingEntity? = null - - if (isCustomerExists) { - // TODO: Hardcoded PSP to be removed in multibank - customerOnboardingEntity = - naviPayCustomerStatusHandler.getCustomerOnboardingEntity( - pspType = PspType.JUSPAY_AXIS - ) - } else { - evaluateAndBindPspForVpaValidation( - onPspEvaluatedSuccess = { customerOnboardingEntity = it } - ) - } + evaluatePspForVpaValidation( + isCustomerExists = isCustomerExists, + onPspEvaluatedSuccess = { customerOnboardingEntity = it }, + ) if (customerOnboardingEntity == null) { return null @@ -137,20 +131,41 @@ constructor( return validateVpaRepoResultResponse } - private suspend fun evaluateAndBindPspForVpaValidation( - onPspEvaluatedSuccess: (NaviPayCustomerOnboardingEntity?) -> Unit, + private suspend fun evaluatePspForVpaValidation( + isCustomerExists: Boolean, + onPspEvaluatedSuccess: (NaviPayCustomerOnboardingEntity) -> Unit, onPspEvaluatedFailed: () -> Unit = {}, ) { - naviPayPspManager.evaluateAndBindAnySupportedPspForFlow( - naviPayFlowType = NaviPayFlowType.VALIDATE_VPA, - screenName = screenName, - onPspEvaluated = { pspEvaluationResult -> - if (pspEvaluationResult.onboardingDataEntity == null) { - onPspEvaluatedFailed() + if (isCustomerExists) { + val selectedPsp = + naviPayPspManager.getPspWithoutOnboardingForFlow( + naviPayFlowType = NaviPayFlowType.VALIDATE_VPA, + screenName = screenName, + ) + + val customerOnboardingEntity = + selectedPsp?.let { + naviPayCustomerStatusHandler.getCustomerOnboardingEntity(pspType = it) } - onPspEvaluatedSuccess(pspEvaluationResult.onboardingDataEntity) - }, - ) + + if (customerOnboardingEntity != null) { + onPspEvaluatedSuccess(customerOnboardingEntity) + } else { + onPspEvaluatedFailed() + } + } else { + naviPayPspManager.evaluateAndBindAnySupportedPspForFlow( + naviPayFlowType = NaviPayFlowType.VALIDATE_VPA, + screenName = screenName, + onPspEvaluated = { pspEvaluationResult -> + if (pspEvaluationResult.onboardingDataEntity == null) { + onPspEvaluatedFailed() + return@evaluateAndBindAnySupportedPspForFlow + } + onPspEvaluatedSuccess(pspEvaluationResult.onboardingDataEntity) + }, + ) + } } private suspend fun fetchFromNetworkAndSaveToDb( @@ -234,21 +249,6 @@ constructor( return apiResponse } - // returns true if customer has done binding or has at least one account in db - private suspend fun isCustomerExistsOnAnySupportedPsp(screenName: String): Boolean { - val accounts = accountsRepository.getAllAccounts() - if (accounts.isNotEmpty()) { - return true - } - val supportedPspTypes = - naviPayPspManager.getSupportedPspList( - naviPayFlowType = NaviPayFlowType.VALIDATE_VPA, - screenName = screenName, - ) - val customerStatusMap = naviPayCustomerStatusHandler.getCustomerStatusMap() - return supportedPspTypes.any { psp -> customerStatusMap[psp]?.isBound == true } - } - private fun getVpaKeyParam(request: T): String { return when (request) { is ValidateVpaRequest -> request.vpa 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 7a8b9ddf10..ca1c872640 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 @@ -24,6 +24,7 @@ import com.navi.pay.common.utils.NaviPayOnboardingNavigator import com.navi.pay.network.di.NaviPayGsonBuilder import com.navi.pay.onboarding.account.common.model.view.VpaEntity import com.navi.pay.onboarding.account.common.model.view.VpaStatus +import com.navi.pay.onboarding.account.common.repository.AccountsRepository import com.navi.pay.onboarding.activatevpa.model.view.VpaActivationData import com.navi.pay.onboarding.binding.model.view.NaviPayCustomerOnboardingEntity import com.navi.pay.onboarding.common.NaviPayOnboardingActionsType @@ -52,6 +53,7 @@ constructor( private val naviPayOnboardingNavigator: NaviPayOnboardingNavigator, private val naviCacheRepository: NaviCacheRepository, private val resourceProvider: ResourceProvider, + private val accountsRepository: AccountsRepository, @NaviPayGsonBuilder private val gson: Gson, ) { private lateinit var screenName: String @@ -299,8 +301,8 @@ constructor( val pspSelectionConfig = getPspSelectionConfig() val supportedPspList = - getSupportedPspList( - naviPayFlowType = naviPayFlowType, + getSupportedPspListWhereCustomerExists( + naviPayFlowType, pspSelectionConfig = pspSelectionConfig, ) if (supportedPspList.isEmpty()) { @@ -404,14 +406,55 @@ constructor( onPspEvaluated(pspEvaluationResult) } - suspend fun getSupportedPspList( + /** + * Retrieves a list of supported PSP types where a customer exists. + * + * @param naviPayFlowType The flow type for the NaviPay process. + * @param pspSelectionConfig Optional configuration for PSP selection. If null, defaults to the + * standard configuration. + * @param screenName The name of the screen invoking this function. Defaults to the instance's + * screen name. + * @return A list of supported PSP types that have associated accounts or are device bound. + */ + suspend fun getSupportedPspListWhereCustomerExists( naviPayFlowType: NaviPayFlowType, pspSelectionConfig: PspSelectionConfigContent? = null, screenName: String = this.screenName, ): List { this@NaviPayPspManager.screenName = screenName - val flowToRoutingBucketMap = - (pspSelectionConfig ?: getPspSelectionConfig()).flowToRoutingBucketMap + + val supportedPspTypes = + getSupportedPspList( + naviPayFlowType = naviPayFlowType, + pspSelectionConfig = pspSelectionConfig ?: getPspSelectionConfig(), + ) + + val pspTypesWhereCustomerExists = getPspListWhereCustomerExists().toSet() + + return supportedPspTypes.filter { it in pspTypesWhereCustomerExists } + } + + private suspend fun getPspListWhereCustomerExists(): List { + val vpaEntities = accountsRepository.getAllVpaEntities() + + val pspTypesWithAccounts = + vpaEntities + .filter { it.pspType != null && it.status != VpaStatus.PENDING_ADDITION } + .mapNotNull { it.pspType } + .toSet() + + val customerStatusMap = naviPayCustomerStatusHandler.getCustomerStatusMap() + + return PspType.entries.filter { psp -> + pspTypesWithAccounts.contains(psp) || customerStatusMap[psp]?.isBound == true + } + } + + private suspend fun getSupportedPspList( + naviPayFlowType: NaviPayFlowType, + pspSelectionConfig: PspSelectionConfigContent, + ): List { + val flowToRoutingBucketMap = pspSelectionConfig.flowToRoutingBucketMap val pspDistributionMap = getPspDistributionMap( naviPayFlowType = naviPayFlowType, diff --git a/android/navi-pay/src/main/kotlin/com/navi/pay/onboarding/account/common/dao/VpaDao.kt b/android/navi-pay/src/main/kotlin/com/navi/pay/onboarding/account/common/dao/VpaDao.kt index d6f57d3f63..327d25c76f 100644 --- a/android/navi-pay/src/main/kotlin/com/navi/pay/onboarding/account/common/dao/VpaDao.kt +++ b/android/navi-pay/src/main/kotlin/com/navi/pay/onboarding/account/common/dao/VpaDao.kt @@ -48,4 +48,7 @@ interface VpaDao { "SELECT accountId FROM $NAVI_PAY_DATABASE_VPA_TABLE_NAME WHERE bankAccountUniqueId = :buid LIMIT 1" ) suspend fun getAccountIdByBuid(buid: String): String? + + @Query("SELECT * FROM $NAVI_PAY_DATABASE_VPA_TABLE_NAME") + suspend fun getAllVpaEntities(): List } diff --git a/android/navi-pay/src/main/kotlin/com/navi/pay/onboarding/account/common/repository/AccountsRepository.kt b/android/navi-pay/src/main/kotlin/com/navi/pay/onboarding/account/common/repository/AccountsRepository.kt index 5f1db85476..487814ea43 100644 --- a/android/navi-pay/src/main/kotlin/com/navi/pay/onboarding/account/common/repository/AccountsRepository.kt +++ b/android/navi-pay/src/main/kotlin/com/navi/pay/onboarding/account/common/repository/AccountsRepository.kt @@ -107,7 +107,7 @@ constructor( suspend fun insertAllAccountEntity(accountEntities: List) = accountDao.insertAll(accountEntities = accountEntities) - suspend fun getAllAccounts() = accountDao.getAllAccounts() + suspend fun getAllVpaEntities() = vpaDao.getAllVpaEntities() fun getAllAccountByStatusAsFlow(status: AccountStatus) = accountDao.getAllAccountByStatusAsFlow(status = status)