Skip to content

Commit

Permalink
feature(bank-sdk): Skonto + RA validation implementation
Browse files Browse the repository at this point in the history
PP-795
  • Loading branch information
ndubkov-distcotech committed Nov 12, 2024
1 parent 109538e commit 115cafe
Show file tree
Hide file tree
Showing 7 changed files with 87 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -82,10 +82,13 @@ import net.gini.android.bank.sdk.capture.digitalinvoice.skonto.colors.section.Di
import net.gini.android.bank.sdk.capture.digitalinvoice.skonto.colors.section.DigitalInvoiceSkontoInfoDialogColors
import net.gini.android.bank.sdk.capture.digitalinvoice.skonto.colors.section.DigitalInvoiceSkontoInvoicePreviewSectionColors
import net.gini.android.bank.sdk.capture.digitalinvoice.skonto.colors.section.DigitalInvoiceSkontoSectionColors
import net.gini.android.bank.sdk.capture.digitalinvoice.skonto.mapper.toErrorMessage
import net.gini.android.bank.sdk.capture.skonto.mapper.toErrorMessage
import net.gini.android.bank.sdk.capture.skonto.model.SkontoData
import net.gini.android.bank.sdk.capture.skonto.model.SkontoEdgeCase
import net.gini.android.bank.sdk.di.koin.giniBankViewModel
import net.gini.android.bank.sdk.util.disallowScreenshots
import net.gini.android.bank.sdk.util.ui.keyboardAsState
import net.gini.android.capture.Amount
import net.gini.android.capture.GiniCapture
import net.gini.android.capture.internal.util.ActivityHelper
Expand Down Expand Up @@ -217,6 +220,11 @@ private fun ScreenContent(
BackHandler { navigateBack() }

val state by viewModel.stateFlow.collectAsState()
val keyboardState by keyboardAsState()

LaunchedEffect(keyboardState) {
viewModel.onKeyboardStateChanged(keyboardState)
}

viewModel.collectSideEffect {
when (it) {
Expand All @@ -240,7 +248,7 @@ private fun ScreenContent(
onInfoDialogDismissed = viewModel::onInfoDialogDismissed,
onInvoiceClicked = viewModel::onInvoiceClicked,
customBottomNavBarAdapter = customBottomNavBarAdapter,
onHelpClicked = viewModel::onHelpClicked
onHelpClicked = viewModel::onHelpClicked,
)
}

Expand Down Expand Up @@ -355,6 +363,7 @@ private fun ScreenReadyState(
onDueDateChanged = onDueDateChanged,
edgeCase = state.edgeCase,
onInfoBannerClicked = onInfoBannerClicked,
skontoAmountValidationError = state.skontoAmountValidationError,
)
}
}
Expand Down Expand Up @@ -521,9 +530,11 @@ private fun SkontoSection(
onInfoBannerClicked: () -> Unit,
edgeCase: SkontoEdgeCase?,
colors: DigitalInvoiceSkontoSectionColors,
skontoAmountValidationError: DigitalInvoiceSkontoScreenState.Ready.SkontoAmountValidationError?,
modifier: Modifier = Modifier,
) {
val dateFormatter = DateTimeFormatter.ofPattern("dd.MM.yyyy")
val resources = LocalContext.current.resources

var isDatePickerVisible by remember { mutableStateOf(false) }
Card(
Expand Down Expand Up @@ -638,6 +649,10 @@ private fun SkontoSection(
)
}
},
isError = skontoAmountValidationError != null,
supportingText = skontoAmountValidationError?.toErrorMessage(
resources = resources,
)
)

val dueDateOnClickSource = remember { MutableInteractionSource() }
Expand Down Expand Up @@ -888,4 +903,5 @@ private val previewState = DigitalInvoiceSkontoScreenState.Ready(
paymentMethod = SkontoData.SkontoPaymentMethod.PayPal,
edgeCase = SkontoEdgeCase.PayByCashOnly,
edgeCaseInfoDialogVisible = false,
skontoAmountValidationError = null
)
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package net.gini.android.bank.sdk.capture.digitalinvoice.skonto

import net.gini.android.bank.sdk.capture.digitalinvoice.skonto.args.DigitalInvoiceSkontoArgs
import net.gini.android.bank.sdk.capture.digitalinvoice.skonto.validation.DigitalInvoiceSkontoAmountValidator
import org.koin.androidx.viewmodel.dsl.viewModel
import org.koin.dsl.module

Expand All @@ -12,7 +13,9 @@ val digitalInvoiceSkontoScreenModule = module {
getSkontoEdgeCaseUseCase = get(),
getSkontoRemainingDaysUseCase = get(),
lastAnalyzedDocumentProvider = get(),
skontoInvoicePreviewTextLinesFactory = get()
skontoInvoicePreviewTextLinesFactory = get(),
digitalInvoiceSkontoAmountValidator = get(),
)
}
factory { DigitalInvoiceSkontoAmountValidator() }
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,25 @@ import net.gini.android.capture.Amount
import java.math.BigDecimal
import java.time.LocalDate

internal sealed class DigitalInvoiceSkontoScreenState {
internal sealed interface DigitalInvoiceSkontoScreenState {

data class Ready(
val isSkontoSectionActive: Boolean,
val paymentInDays: Int,
val skontoPercentage: BigDecimal,
val skontoAmount: Amount,
val skontoAmountValidationError: SkontoAmountValidationError?,
val fullAmount: Amount,
val discountDueDate: LocalDate,
val paymentMethod: SkontoData.SkontoPaymentMethod,
val edgeCase: SkontoEdgeCase?,
val edgeCaseInfoDialogVisible: Boolean,
) : DigitalInvoiceSkontoScreenState()
) : DigitalInvoiceSkontoScreenState {

sealed interface SkontoAmountValidationError {
object SkontoAmountMoreThanFullAmount : SkontoAmountValidationError
}
}
}

internal sealed interface DigitalInvoiceSkontoSideEffect {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.launch
import net.gini.android.bank.sdk.capture.digitalinvoice.skonto.args.DigitalInvoiceSkontoArgs
import net.gini.android.bank.sdk.capture.digitalinvoice.skonto.args.DigitalInvoiceSkontoResultArgs
import net.gini.android.bank.sdk.capture.digitalinvoice.skonto.validation.DigitalInvoiceSkontoAmountValidator
import net.gini.android.bank.sdk.capture.skonto.factory.lines.SkontoInvoicePreviewTextLinesFactory
import net.gini.android.bank.sdk.capture.skonto.model.SkontoData
import net.gini.android.bank.sdk.capture.skonto.usecase.GetSkontoDiscountPercentageUseCase
Expand All @@ -23,6 +24,7 @@ internal class DigitalInvoiceSkontoViewModel(
private val getSkontoEdgeCaseUseCase: GetSkontoEdgeCaseUseCase,
private val getSkontoRemainingDaysUseCase: GetSkontoRemainingDaysUseCase,
private val skontoInvoicePreviewTextLinesFactory: SkontoInvoicePreviewTextLinesFactory,
private val digitalInvoiceSkontoAmountValidator: DigitalInvoiceSkontoAmountValidator,
) : ViewModel() {

val stateFlow: MutableStateFlow<DigitalInvoiceSkontoScreenState> =
Expand Down Expand Up @@ -70,16 +72,26 @@ internal class DigitalInvoiceSkontoViewModel(
paymentMethod = paymentMethod,
edgeCase = edgeCase,
edgeCaseInfoDialogVisible = edgeCase != null,
skontoAmountValidationError = null,
)
}

fun onSkontoAmountFieldChanged(newValue: BigDecimal) = viewModelScope.launch {
val currentState =
stateFlow.value as? DigitalInvoiceSkontoScreenState.Ready ?: return@launch

if (newValue > currentState.fullAmount.value) {
val skontoAmountValidationError = digitalInvoiceSkontoAmountValidator(
newValue,
currentState.fullAmount.value
)

if (skontoAmountValidationError != null) {
stateFlow.emit(
currentState.copy(skontoAmount = currentState.skontoAmount)
currentState.copy(
skontoAmount = currentState.skontoAmount,
skontoAmountValidationError = DigitalInvoiceSkontoScreenState.Ready
.SkontoAmountValidationError.SkontoAmountMoreThanFullAmount
)
)
return@launch
}
Expand All @@ -95,10 +107,12 @@ internal class DigitalInvoiceSkontoViewModel(
currentState.copy(
skontoAmount = newSkontoAmount,
skontoPercentage = discount,
skontoAmountValidationError = null,
)
)
}


fun onSkontoDueDateChanged(newDate: LocalDate) = viewModelScope.launch {
val currentState =
stateFlow.value as? DigitalInvoiceSkontoScreenState.Ready ?: return@launch
Expand All @@ -115,6 +129,17 @@ internal class DigitalInvoiceSkontoViewModel(
)
}

fun onKeyboardStateChanged(isVisible: Boolean) = viewModelScope.launch {
if (isVisible) return@launch
val currentState =
stateFlow.value as? DigitalInvoiceSkontoScreenState.Ready ?: return@launch
stateFlow.emit(
currentState.copy(
skontoAmountValidationError = null
)
)
}

fun onInfoBannerClicked() = viewModelScope.launch {
val currentState =
stateFlow.value as? DigitalInvoiceSkontoScreenState.Ready ?: return@launch
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package net.gini.android.bank.sdk.capture.digitalinvoice.skonto.mapper

import android.content.res.Resources
import net.gini.android.bank.sdk.R
import net.gini.android.bank.sdk.capture.digitalinvoice.skonto.DigitalInvoiceSkontoScreenState

internal fun DigitalInvoiceSkontoScreenState.Ready.SkontoAmountValidationError.toErrorMessage(
resources: Resources,
): String = when (this) {
is DigitalInvoiceSkontoScreenState.Ready.SkontoAmountValidationError.SkontoAmountMoreThanFullAmount ->
resources.getString(
R.string.gbs_skonto_section_discount_field_amount_validation_error_skonto_amount_more_than_full_amount
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package net.gini.android.bank.sdk.capture.digitalinvoice.skonto.validation

import net.gini.android.bank.sdk.capture.digitalinvoice.skonto.DigitalInvoiceSkontoScreenState
import java.math.BigDecimal

internal class DigitalInvoiceSkontoAmountValidator {

operator fun invoke(newSkontoAmount: BigDecimal, fullAmount: BigDecimal)
: DigitalInvoiceSkontoScreenState.Ready.SkontoAmountValidationError? = when {
newSkontoAmount > fullAmount ->
DigitalInvoiceSkontoScreenState.Ready.SkontoAmountValidationError.SkontoAmountMoreThanFullAmount

else -> null
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import java.text.DecimalFormat
import java.text.NumberFormat

class DecimalFormatter(
val numberFormat: NumberFormat = NumberFormat.getCurrencyInstance().apply {
private val numberFormat: NumberFormat = NumberFormat.getCurrencyInstance().apply {
(this as? DecimalFormat)?.apply {
decimalFormatSymbols = decimalFormatSymbols.apply {
currencySymbol = ""
Expand All @@ -14,14 +14,12 @@ class DecimalFormatter(
}
) {

fun parseAmount(amount: BigDecimal) = numberFormat.format(amount).trim()
fun parseAmount(amount: BigDecimal) = numberFormat.format(amount).trim()
.filter { it != '.' && it != ',' }
.take(MAX_PARSE_LENGTH)
.trimStart('0')

fun textToDigits(text: String): String = text.trim()
.filter { it != '.' && it != ',' }
.take(MAX_FORMAT_LENGTH)
.trimStart('0')

fun parseDigits(digits: String): BigDecimal =
Expand All @@ -34,10 +32,4 @@ class DecimalFormatter(
// Format to a currency string
return numberFormat.format(decimal).trim()
}

companion object {
private const val MAX_PARSE_LENGTH = 7
private const val MAX_FORMAT_LENGTH = 8

}
}

0 comments on commit 115cafe

Please sign in to comment.