NTP-37025 | Mandate usecase changes (#15017)

This commit is contained in:
Hardik Chaudhary
2025-02-24 16:28:45 +05:30
committed by GitHub
parent 11e4b469bb
commit cd22369cfd
2 changed files with 299 additions and 202 deletions

View File

@@ -0,0 +1,157 @@
/*
*
* * Copyright © 2025 by Navi Technologies Limited
* * All rights reserved. Strictly confidential
*
*/
package com.navi.pay.common.usecase
import com.navi.base.utils.DateUtils
import com.navi.common.network.models.RepoResult
import com.navi.common.network.models.isSuccessWithData
import com.navi.pay.common.model.view.PspType
import com.navi.pay.common.utils.DeviceInfoProvider
import com.navi.pay.common.utils.getMetricInfo
import com.navi.pay.management.common.sendmoney.model.view.PayeeEntity
import com.navi.pay.management.mandate.model.network.CreateMandateRequest
import com.navi.pay.management.mandate.model.network.CreateMandateResponse
import com.navi.pay.management.mandate.repository.MandateRepository
import com.navi.pay.npcicl.CredDataProvider
import com.navi.pay.npcicl.NpciRepository
import com.navi.pay.npcicl.NpciResult
import com.navi.pay.onboarding.account.detail.model.view.LinkedAccountEntity
import com.navi.pay.utils.DATE_TIME_FORMAT_DATE_MONTH_YEAR_WITHOUT_SEPARATOR
import com.navi.pay.utils.DATE_TIME_FORMAT_YEAR_MONTH_DATE_WITH_SLASH_SEPARATOR
import javax.inject.Inject
class CreateMandateUseCase
@Inject
constructor(
private val credDataProvider: CredDataProvider,
private val npciRepository: NpciRepository,
private val deviceInfoProvider: DeviceInfoProvider,
private val mandateRepository: MandateRepository,
) {
suspend fun generateMandateCredBlock(
accountEntity: LinkedAccountEntity,
payeeEntity: PayeeEntity,
upiRequestId: String,
screenName: String,
pspType: PspType,
onNpciResultError: suspend (Boolean) -> Unit,
onNpciResultSuccess: suspend (String, String, LinkedAccountEntity) -> Unit,
) {
val mandateCredData =
credDataProvider.mandateCred(
accountEntity = accountEntity,
note = payeeEntity.note,
mandateName = payeeEntity.mandateName.orEmpty(),
amount = payeeEntity.amount,
payeeVpa = payeeEntity.vpa,
upiRequestId = upiRequestId,
pspType = pspType,
)
val npciResult =
npciRepository.fetchCredentials(
npciCredData = mandateCredData,
metricInfo = getMetricInfo(screenName = screenName, isNae = { false }),
)
when (npciResult) {
is NpciResult.Error -> {
onNpciResultError(npciResult.isUserAborted)
}
is NpciResult.Success -> {
onNpciResultSuccess(upiRequestId, npciResult.data, accountEntity)
}
else -> Unit
}
}
suspend fun createMandatePostCredBlockGeneration(
payeeEntity: PayeeEntity?,
selectedBankAccount: LinkedAccountEntity,
npciResultData: String,
upiRequestId: String,
screenName: String,
onCreateMandateApiSuccess: suspend (RepoResult<CreateMandateResponse>) -> Unit,
onCreateMandateApiFailure: suspend (RepoResult<CreateMandateResponse>) -> Unit,
) {
val createMandateRequest =
CreateMandateRequest(
amount = payeeEntity?.amount.orEmpty(),
amountRule = payeeEntity?.mandateAmountRule.orEmpty(),
bankAccountUniqueId = selectedBankAccount.accountId,
blockFund =
getStringifiedBooleanFromYOrNString(
statusString = payeeEntity?.mandateBlock.orEmpty()
),
credBlock = npciResultData,
currency = payeeEntity?.currency.orEmpty(),
deviceData = deviceInfoProvider.getDeviceData(),
mandateName = payeeEntity?.mandateName.orEmpty(),
mcc = payeeEntity?.mcc.orEmpty(),
merchantCustomerId = deviceInfoProvider.getMerchantCustomerId(),
payeeVpa = payeeEntity?.vpa.orEmpty(),
payerVpa = selectedBankAccount.vpa,
recipientName = payeeEntity?.name.orEmpty(),
recurrencePattern = payeeEntity?.mandateRecurrence.orEmpty(),
recurrenceValue = payeeEntity?.mandateRecurrenceValue,
recurrenceRule = payeeEntity?.mandateRecurrenceType,
refUrl = payeeEntity?.refUrl.orEmpty(),
remarks = payeeEntity?.note.orEmpty(),
shareToPayee =
getStringifiedBooleanFromYOrNString(
statusString = payeeEntity?.mandateShareToPayee.orEmpty(),
default = "true",
),
upiRequestId = upiRequestId,
validityEnd =
DateUtils.convertDateTimeStringFromSourceFormatToDestinationFormat(
dateTime = payeeEntity?.mandateValidityEndDate.orEmpty(),
sourceFormat = DATE_TIME_FORMAT_DATE_MONTH_YEAR_WITHOUT_SEPARATOR,
destinationFormat = DATE_TIME_FORMAT_YEAR_MONTH_DATE_WITH_SLASH_SEPARATOR,
),
validityStart =
DateUtils.convertDateTimeStringFromSourceFormatToDestinationFormat(
dateTime = payeeEntity?.mandateValidityStartDate.orEmpty(),
sourceFormat = DATE_TIME_FORMAT_DATE_MONTH_YEAR_WITHOUT_SEPARATOR,
destinationFormat = DATE_TIME_FORMAT_YEAR_MONTH_DATE_WITH_SLASH_SEPARATOR,
),
refCategory = payeeEntity?.refCategory.orEmpty(),
transactionReference = payeeEntity?.transactionReference.orEmpty(),
purpose = payeeEntity?.purpose.orEmpty(),
initiationMode = payeeEntity?.mode.orEmpty(),
payerRevocable =
getStringifiedBooleanFromYOrNString(
statusString = payeeEntity?.mandateRevocable.orEmpty(),
default = "true",
),
)
val createMandateAPIResponse =
mandateRepository.createMandate(
createMandateRequest = createMandateRequest,
metricInfo = getMetricInfo(screenName = screenName),
)
if (createMandateAPIResponse.isSuccessWithData()) {
onCreateMandateApiSuccess(createMandateAPIResponse)
} else {
onCreateMandateApiFailure(createMandateAPIResponse)
}
}
private fun getStringifiedBooleanFromYOrNString(
statusString: String,
default: String = "false",
): String {
return when (statusString) {
"Y" -> "true"
"N" -> "false"
else -> default
}
}
}

View File

@@ -9,7 +9,6 @@ package com.navi.pay.management.mandate.viewmodel
import androidx.lifecycle.SavedStateHandle
import androidx.lifecycle.viewModelScope
import com.navi.base.utils.DateUtils
import com.navi.base.utils.EMPTY
import com.navi.base.utils.ResourceProvider
import com.navi.common.network.models.RepoResult
@@ -24,6 +23,7 @@ import com.navi.pay.common.model.network.ValidateVpaResponse
import com.navi.pay.common.model.view.NaviPayFlowType
import com.navi.pay.common.model.view.PspType
import com.navi.pay.common.repository.CommonRepository
import com.navi.pay.common.usecase.CreateMandateUseCase
import com.navi.pay.common.usecase.LinkedAccountsUseCase
import com.navi.pay.common.usecase.UpiRequestIdUseCase
import com.navi.pay.common.usecase.ValidateVpaUseCase
@@ -38,7 +38,7 @@ import com.navi.pay.management.common.sendmoney.model.view.PayeeEntity
import com.navi.pay.management.common.sendmoney.util.AccountEligibilityMerchantHelper
import com.navi.pay.management.common.utils.NaviPayPspManager
import com.navi.pay.management.common.utils.PspEvaluationResult
import com.navi.pay.management.mandate.model.network.CreateMandateRequest
import com.navi.pay.management.mandate.model.network.CreateMandateResponse
import com.navi.pay.management.mandate.model.network.MandateDetailRequest
import com.navi.pay.management.mandate.model.network.ReviewMandateRequest
import com.navi.pay.management.mandate.model.network.toMandateEntity
@@ -53,8 +53,6 @@ import com.navi.pay.npcicl.NpciRepository
import com.navi.pay.npcicl.NpciResult
import com.navi.pay.onboarding.account.detail.model.view.LinkedAccountEntity
import com.navi.pay.onboarding.common.NaviPayOnboardingActionsType
import com.navi.pay.utils.DATE_TIME_FORMAT_DATE_MONTH_YEAR_WITHOUT_SEPARATOR
import com.navi.pay.utils.DATE_TIME_FORMAT_YEAR_MONTH_DATE_WITH_SLASH_SEPARATOR
import com.navi.pay.utils.DEFAULT_INITIATION_MODE_QR_MANDATE
import com.navi.pay.utils.NAVI_PAY_PURPLE_CTA_LOADER_LOTTIE
import com.navi.pay.utils.REQUEST_TYPE_MANDATE
@@ -94,6 +92,7 @@ constructor(
private val resourceProvider: ResourceProvider,
private val accountEligibilityMerchantHelper: AccountEligibilityMerchantHelper,
private val naviPayPspManager: NaviPayPspManager,
private val createMandateUseCase: CreateMandateUseCase,
) : NaviPayBaseVM() {
private val naviPayAnalytics: NaviPayAnalytics.NaviPayManageAutoPay =
@@ -497,209 +496,161 @@ constructor(
val payeeEntity = payeeEntity
if (selectedBankAccount != null && payeeEntity != null) {
val upiRequestId = payeeEntity.transactionId ?: upiRequestIdUseCase.execute()
val mandateCredData =
credDataProvider.mandateCred(
accountEntity = selectedBankAccount,
note = payeeEntity.note,
mandateName = payeeEntity.mandateName.orEmpty(),
amount = payeeEntity.amount,
payeeVpa = payeeEntity.vpa,
upiRequestId = upiRequestId,
pspType = pspType,
)
val npciResult =
npciRepository.fetchCredentials(
npciCredData = mandateCredData,
metricInfo = getMetricInfo(screenName = screenName, isNae = { false }),
)
onCreateMandateCLCallback(
npciResult = npciResult,
upiRequestId = upiRequestId,
selectedBankAccount = selectedBankAccount,
createMandateUseCase.generateMandateCredBlock(
accountEntity = selectedBankAccount,
payeeEntity = payeeEntity,
upiRequestId = payeeEntity.transactionId ?: upiRequestIdUseCase.execute(),
screenName = screenName,
pspType = pspType,
onNpciResultError = { isUserAborted ->
updateBottomSheetUIState(showBottomSheet = false)
if (!isUserAborted) {
notifyError(getNoInternetErrorConfig())
}
},
onNpciResultSuccess = { upiRequestId, npciResultData, selectedBankAccount ->
onCreateMandateCLCallback(
upiRequestId = upiRequestId,
npciResultData = npciResultData,
selectedBankAccount = selectedBankAccount,
)
},
)
}
}
private suspend fun onCreateMandateCLCallback(
npciResult: NpciResult,
upiRequestId: String,
npciResultData: String,
selectedBankAccount: LinkedAccountEntity,
) {
updateBottomSheetUIState(showBottomSheet = false)
when (npciResult) {
is NpciResult.Success -> {
updateUIState(
uiState =
MandateDetailUIStateOfPendingCategory.Loading(
titleId = R.string.setting_up_autopay_of_x,
titleArgs = mandateEntity?.amount,
showLoader = true,
)
)
createMandateUseCase.createMandatePostCredBlockGeneration(
payeeEntity = payeeEntity,
selectedBankAccount = selectedBankAccount,
npciResultData = npciResultData,
upiRequestId = upiRequestId,
screenName = screenName,
onCreateMandateApiSuccess = { createMandateAPIResponse ->
handleCreateMandateApiSuccess(createMandateAPIResponse)
},
onCreateMandateApiFailure = { createMandateAPIResponse ->
handleCreateMandateApiFailure(createMandateAPIResponse)
},
)
}
private fun handleCreateMandateApiFailure(
createMandateAPIResponse: RepoResult<CreateMandateResponse>
) {
val error = getError(response = createMandateAPIResponse)
updateUIState(uiState = MandateDetailUIStateOfPendingCategory.MandateDetail)
updateMandateScreenBackNavigationState(
mandateScreenBackNavigation = MandateScreenBackNavigation.RefreshAndMaintainSameTab
)
updateBottomSheetUIState(
bottomSheetUIState =
MandateDetailOfPendingCategoryBottomSheetState.Error(
title = error.title,
description = error.description,
primaryText = error.firstPrimaryButtonConfig?.text,
secondaryText = error.firstSecondaryButtonConfig?.text,
),
showBottomSheet = true,
allowStateChange = false,
)
}
private suspend fun handleCreateMandateApiSuccess(
createMandateAPIResponse: RepoResult<CreateMandateResponse>
) {
val createMandateData = createMandateAPIResponse.data!!
this@MandateDetailOfPendingCategoryViewModel.mandateEntity =
mandateEntity?.copy(
id = createMandateData.mandateReferenceId,
status = createMandateData.mandateDetails.status,
)
val mandateDetailAPIResponse =
commonRepository.getMandateDetail(
mandateDetailRequest =
MandateDetailRequest(
mandateReferenceId = createMandateData.mandateReferenceId,
merchantCustomerId = deviceInfoProvider.getMerchantCustomerId(),
deviceData = deviceInfoProvider.getDeviceData(),
),
metricInfo = getMetricInfo(screenName = screenName, isNae = { false }),
)
if (mandateDetailAPIResponse.isSuccessWithData()) {
this@MandateDetailOfPendingCategoryViewModel.mandateEntity =
mandateDetailAPIResponse.data!!.toMandateEntity()
}
updateUIStateFromCreateMandateState(createMandateAPIResponse = createMandateAPIResponse)
}
private suspend fun updateUIStateFromCreateMandateState(
createMandateAPIResponse: RepoResult<CreateMandateResponse>
) {
when (createMandateAPIResponse.data!!.state) {
MandateResponseState.SUCCESS.name -> {
naviPayAnalytics.onMandateSetupSuccess(mandateEntity)
updateMandateScreenBackNavigationState(
mandateScreenBackNavigation =
MandateScreenBackNavigation.RefreshAndNavigateToActiveTab
)
updateUIState(
uiState =
MandateDetailUIStateOfPendingCategory.Loading(
titleId = R.string.setting_up_autopay_of_x,
titleArgs = mandateEntity?.amount,
showLoader = true,
MandateDetailUIStateOfPendingCategory.Success(
titleId = R.string.navi_pay_autopay_setup_successful,
mandateEntity = mandateEntity,
)
)
val createMandateRequest =
CreateMandateRequest(
amount = payeeEntity?.amount.orEmpty(),
amountRule = payeeEntity?.mandateAmountRule.orEmpty(),
bankAccountUniqueId = selectedBankAccount.accountId,
blockFund =
getStringifiedBooleanFromYOrNString(
statusString = payeeEntity?.mandateBlock.orEmpty()
),
credBlock = npciResult.data,
currency = payeeEntity?.currency.orEmpty(),
deviceData = deviceInfoProvider.getDeviceData(),
mandateName = payeeEntity?.mandateName.orEmpty(),
mcc = payeeEntity?.mcc.orEmpty(),
merchantCustomerId = deviceInfoProvider.getMerchantCustomerId(),
payeeVpa = payeeEntity?.vpa.orEmpty(),
payerVpa = selectedBankAccount.vpa,
recipientName = payeeEntity?.name.orEmpty(),
recurrencePattern = payeeEntity?.mandateRecurrence.orEmpty(),
recurrenceValue = payeeEntity?.mandateRecurrenceValue,
recurrenceRule = payeeEntity?.mandateRecurrenceType,
refUrl = payeeEntity?.refUrl.orEmpty(),
remarks = payeeEntity?.note.orEmpty(),
shareToPayee =
getStringifiedBooleanFromYOrNString(
statusString = payeeEntity?.mandateShareToPayee.orEmpty(),
default = "true",
),
upiRequestId = upiRequestId,
validityEnd =
DateUtils.convertDateTimeStringFromSourceFormatToDestinationFormat(
dateTime = payeeEntity?.mandateValidityEndDate.orEmpty(),
sourceFormat = DATE_TIME_FORMAT_DATE_MONTH_YEAR_WITHOUT_SEPARATOR,
destinationFormat =
DATE_TIME_FORMAT_YEAR_MONTH_DATE_WITH_SLASH_SEPARATOR,
),
validityStart =
DateUtils.convertDateTimeStringFromSourceFormatToDestinationFormat(
dateTime = payeeEntity?.mandateValidityStartDate.orEmpty(),
sourceFormat = DATE_TIME_FORMAT_DATE_MONTH_YEAR_WITHOUT_SEPARATOR,
destinationFormat =
DATE_TIME_FORMAT_YEAR_MONTH_DATE_WITH_SLASH_SEPARATOR,
),
refCategory = payeeEntity?.refCategory.orEmpty(),
transactionReference = payeeEntity?.transactionReference.orEmpty(),
purpose = payeeEntity?.purpose.orEmpty(),
initiationMode = payeeEntity?.mode.orEmpty(),
payerRevocable =
getStringifiedBooleanFromYOrNString(
statusString = payeeEntity?.mandateRevocable.orEmpty(),
default = "true",
),
)
val createMandateAPIResponse =
mandateRepository.createMandate(
createMandateRequest = createMandateRequest,
metricInfo = getMetricInfo(screenName = screenName),
)
if (!createMandateAPIResponse.isSuccessWithData()) {
val error = getError(response = createMandateAPIResponse)
updateUIState(uiState = MandateDetailUIStateOfPendingCategory.MandateDetail)
updateMandateScreenBackNavigationState(
mandateScreenBackNavigation =
MandateScreenBackNavigation.RefreshAndMaintainSameTab
)
updateBottomSheetUIState(
bottomSheetUIState =
MandateDetailOfPendingCategoryBottomSheetState.Error(
title = error.title,
description = error.description,
primaryText = error.firstPrimaryButtonConfig?.text,
secondaryText = error.firstSecondaryButtonConfig?.text,
),
showBottomSheet = true,
allowStateChange = false,
)
return
}
val createMandateData = createMandateAPIResponse.data!!
this@MandateDetailOfPendingCategoryViewModel.mandateEntity =
mandateEntity?.copy(
id = createMandateData.mandateReferenceId,
status = createMandateData.mandateDetails.status,
)
val mandateDetailAPIResponse =
commonRepository.getMandateDetail(
mandateDetailRequest =
MandateDetailRequest(
mandateReferenceId = createMandateData.mandateReferenceId,
merchantCustomerId = deviceInfoProvider.getMerchantCustomerId(),
deviceData = deviceInfoProvider.getDeviceData(),
),
metricInfo = getMetricInfo(screenName = screenName, isNae = { false }),
)
if (mandateDetailAPIResponse.isSuccessWithData()) {
this@MandateDetailOfPendingCategoryViewModel.mandateEntity =
mandateDetailAPIResponse.data!!.toMandateEntity()
}
when (createMandateData.state) {
MandateResponseState.SUCCESS.name -> {
naviPayAnalytics.onMandateSetupSuccess(mandateEntity)
updateMandateScreenBackNavigationState(
mandateScreenBackNavigation =
MandateScreenBackNavigation.RefreshAndNavigateToActiveTab
)
updateUIState(
uiState =
MandateDetailUIStateOfPendingCategory.Success(
titleId = R.string.navi_pay_autopay_setup_successful,
mandateEntity = mandateEntity,
)
)
}
MandateResponseState.FAILURE.name -> {
val error = getError(response = createMandateAPIResponse)
updateMandateScreenBackNavigationState(
mandateScreenBackNavigation =
MandateScreenBackNavigation.RefreshAndMaintainSameTab
)
updateUIState(uiState = MandateDetailUIStateOfPendingCategory.MandateDetail)
updateBottomSheetUIState(
bottomSheetUIState =
MandateDetailOfPendingCategoryBottomSheetState.Error(
title = error.title,
description = error.description,
primaryText = error.firstPrimaryButtonConfig?.text,
secondaryText = error.firstSecondaryButtonConfig?.text,
),
showBottomSheet = true,
allowStateChange = false,
)
}
MandateResponseState.PENDING.name -> {
updateNavigateToNextScreen(
navigateToNextScreen =
NavigateToNextScreenFromMandateDetailOfPendingCategory
.MandateActiveOrCompletedDetailScreen(
mandateEntity =
this@MandateDetailOfPendingCategoryViewModel
.mandateEntity
)
)
}
}
}
is NpciResult.Error -> {
if (!npciResult.isUserAborted) {
notifyError(getNoInternetErrorConfig())
}
MandateResponseState.FAILURE.name -> {
val error = getError(response = createMandateAPIResponse)
updateMandateScreenBackNavigationState(
mandateScreenBackNavigation =
MandateScreenBackNavigation.RefreshAndMaintainSameTab
)
updateUIState(uiState = MandateDetailUIStateOfPendingCategory.MandateDetail)
updateBottomSheetUIState(
bottomSheetUIState =
MandateDetailOfPendingCategoryBottomSheetState.Error(
title = error.title,
description = error.description,
primaryText = error.firstPrimaryButtonConfig?.text,
secondaryText = error.firstSecondaryButtonConfig?.text,
),
showBottomSheet = true,
allowStateChange = false,
)
}
MandateResponseState.PENDING.name -> {
updateNavigateToNextScreen(
navigateToNextScreen =
NavigateToNextScreenFromMandateDetailOfPendingCategory
.MandateActiveOrCompletedDetailScreen(
mandateEntity =
this@MandateDetailOfPendingCategoryViewModel.mandateEntity
)
)
}
else -> Unit
}
}
@@ -993,17 +944,6 @@ constructor(
}
}
private fun getStringifiedBooleanFromYOrNString(
statusString: String,
default: String = "false",
): String {
return when (statusString) {
"Y" -> "true"
"N" -> "false"
else -> default
}
}
fun updateShowSnackBarState(showSnackBar: Boolean) {
_showSnackBar.update { showSnackBar }
}