Skip to content

Commit

Permalink
refactor(merchant-sdk): Remove redundant fields from PaymentDetails
Browse files Browse the repository at this point in the history
EC-74
  • Loading branch information
danicretu committed Aug 15, 2024
1 parent 70fee14 commit 5f96267
Show file tree
Hide file tree
Showing 4 changed files with 27 additions and 216 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,6 @@ package net.gini.android.merchant.sdk.api.payment.model

import android.os.Parcelable
import kotlinx.parcelize.Parcelize
import net.gini.android.core.api.models.CompoundExtraction
import net.gini.android.core.api.models.ExtractionsContainer
import net.gini.android.core.api.models.SpecificExtraction
import net.gini.android.merchant.sdk.review.error.NoPaymentDataExtracted
import net.gini.android.merchant.sdk.util.toBackendFormat

/**
* Represents the payment details of an invoice as extracted from a document.
Expand All @@ -17,96 +12,11 @@ data class PaymentDetails(
val iban: String,
val amount: String,
val purpose: String,
internal val extractions: ExtractionsContainer? = null
): Parcelable

internal fun ExtractionsContainer.toPaymentDetails(): PaymentDetails {
if (!compoundExtractions.containsKey("payment")) {
throw NoPaymentDataExtracted()
}
return PaymentDetails(
recipient = compoundExtractions.getPaymentExtraction("payment_recipient")?.value
?: "",
iban = compoundExtractions.getPaymentExtraction("iban")?.value ?: "",
amount = compoundExtractions.getPaymentExtraction("amount_to_pay")?.value?.toAmount()
?: "",
purpose = compoundExtractions.getPaymentExtraction("payment_purpose")?.value ?: "",
extractions = this
)
}

internal fun String.toAmount(): String {
val delimiterIndex = this.indexOf(":")
return if (delimiterIndex != -1) {
this.substring(0, delimiterIndex)
} else {
this
}
}

/**
* Checks if the document is payable which looks for iban extraction.
*/
val PaymentDetails.isPayable get() = iban.isNotEmpty() // It appears this is not used anymore - we could remove it at a later stage (would remove it from the documentation as well)

internal fun MutableMap<String, CompoundExtraction>.withFeedback(paymentDetails: PaymentDetails): Map<String, CompoundExtraction> {
this["payment"] = this["payment"].let { payment ->
CompoundExtraction(
payment?.name ?: "payment",
payment?.specificExtractionMaps?.mapIndexed { index, specificExtractions ->
if (index > 0) return@mapIndexed specificExtractions

mutableMapOf<String, SpecificExtraction>().also { extractions ->
extractions.putAll(specificExtractions)
extractions["payment_recipient"] = extractions["payment_recipient"].let { extraction ->
SpecificExtraction(
extraction?.name ?: "payment_recipient",
paymentDetails.recipient,
extraction?.entity ?: "",
extraction?.box,
extraction?.candidate ?: emptyList()
)
}
extractions["iban"] = extractions["iban"].let { extraction ->
SpecificExtraction(
extraction?.name ?: "iban",
paymentDetails.iban,
extraction?.entity ?: "",
extraction?.box,
extraction?.candidate ?: emptyList()
)
}
extractions["amount_to_pay"] = extractions["amount_to_pay"].let { extraction ->
SpecificExtraction(
extraction?.name ?: "amount_to_pay",
"${paymentDetails.amount.toBackendFormat()}:EUR",
extraction?.entity ?: "",
extraction?.box,
extraction?.candidate ?: emptyList()
)
}
extractions["payment_purpose"] = extractions["payment_purpose"].let { extraction ->
SpecificExtraction(
extraction?.name ?: "payment_purpose",
paymentDetails.purpose,
extraction?.entity ?: "",
extraction?.box,
extraction?.candidate ?: emptyList()
)
}
}
} ?: listOf()
)
}
return this
}

internal fun MutableMap<String, CompoundExtraction>.getPaymentExtraction(name: String) = this["payment"]?.specificExtractionMaps?.get(0)?.get(name)

internal fun PaymentDetails.overwriteEmptyFields(value: PaymentDetails): PaymentDetails = this.copy(
recipient = if (recipient.trim().isEmpty()) value.recipient else recipient,
iban = if (iban.trim().isEmpty()) value.iban else iban,
amount = if (amount.trim().isEmpty()) value.amount else amount,
purpose = if (purpose.trim().isEmpty()) value.purpose else purpose,
extractions = extractions ?: value.extractions,
)
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,9 @@ import kotlinx.coroutines.flow.StateFlow
import net.gini.android.core.api.Resource
import net.gini.android.health.api.models.PaymentRequestInput
import net.gini.android.merchant.sdk.GiniMerchant
import net.gini.android.merchant.sdk.api.ResultWrapper
import net.gini.android.merchant.sdk.api.payment.model.PaymentDetails
import net.gini.android.merchant.sdk.api.payment.model.PaymentRequest
import net.gini.android.merchant.sdk.api.payment.model.toPaymentRequest
import net.gini.android.merchant.sdk.api.payment.model.withFeedback
import net.gini.android.merchant.sdk.paymentprovider.PaymentProviderApp
import net.gini.android.merchant.sdk.review.ValidationMessage
import net.gini.android.merchant.sdk.review.validate
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
package net.gini.android.merchant.sdk.review.model

import net.gini.android.core.api.models.CompoundExtraction
import net.gini.android.core.api.models.ExtractionsContainer
import net.gini.android.core.api.models.SpecificExtraction
import com.google.common.truth.Truth.assertThat
import net.gini.android.merchant.sdk.api.payment.model.PaymentDetails
import net.gini.android.merchant.sdk.api.payment.model.getPaymentExtraction
import net.gini.android.merchant.sdk.api.payment.model.toPaymentDetails
import net.gini.android.merchant.sdk.api.payment.model.withFeedback
import org.junit.Assert.assertEquals
import net.gini.android.merchant.sdk.api.payment.model.overwriteEmptyFields
import org.junit.Before
import org.junit.Test
import java.util.*
import java.util.Locale

/**
* Created by Alpár Szotyori on 01.02.22.
Expand All @@ -25,141 +20,50 @@ class PaymentDetailsTest {
}

@Test
fun `Updates payment extractions with payment detail values for feedback`() {
fun `Overwrites empty fields`() {
// Given
val compoundExtractions = mutableMapOf("payment" to CompoundExtraction(
"payment",
listOf(mapOf(
"payment_recipient" to SpecificExtraction(
"payment_recipient",
"John Doe",
"", null, emptyList()
),
"iban" to SpecificExtraction(
"iban",
"DE123456789",
"", null, emptyList()
),
"amount_to_pay" to SpecificExtraction(
"amount_to_pay",
"1.11:EUR",
"", null, emptyList()
),
"payment_purpose" to SpecificExtraction(
"payment_purpose",
"Testing",
"", null, emptyList()
)
))
))

val paymentDetails = PaymentDetails(
recipient = "Jack Vance",
iban = "DE987654321",
amount = "9.99:EUR",
purpose = "Still testing"
recipient = "",
iban = "iban",
amount = "30",
purpose = "payment"
)

// When
compoundExtractions.withFeedback(paymentDetails)

// Then
assertEquals(paymentDetails.recipient, compoundExtractions.getPaymentExtraction("payment_recipient")?.value)
assertEquals(paymentDetails.iban, compoundExtractions.getPaymentExtraction("iban")?.value)
assertEquals(paymentDetails.amount, compoundExtractions.getPaymentExtraction("amount_to_pay")?.value)
assertEquals(paymentDetails.purpose, compoundExtractions.getPaymentExtraction("payment_purpose")?.value)
}

@Test
fun `Adds missing payment extraction when updating payment detail values for feedback`() {
// Given
val compoundExtractions = mutableMapOf("payment" to CompoundExtraction(
"payment",
listOf(mapOf(
"iban" to SpecificExtraction(
"iban",
"DE123456789",
"", null, emptyList()
),
"amount_to_pay" to SpecificExtraction(
"amount_to_pay",
"1.11:EUR",
"", null, emptyList()
),
"payment_purpose" to SpecificExtraction(
"payment_purpose",
"Testing",
"", null, emptyList()
)
))
))

val paymentDetails = PaymentDetails(
recipient = "Jack Vance",
iban = "DE987654321",
amount = "9.99:EUR",
purpose = "Still testing"
val nonEmptyPaymentFields = PaymentDetails(
recipient = "recipient",
iban = "iban",
amount = "30",
purpose = "payment"
)

// When
compoundExtractions.withFeedback(paymentDetails)
val newPaymentDetails = paymentDetails.overwriteEmptyFields(nonEmptyPaymentFields)

// Then
assertEquals(paymentDetails.recipient, compoundExtractions.getPaymentExtraction("payment_recipient")?.value)
assertEquals(paymentDetails.iban, compoundExtractions.getPaymentExtraction("iban")?.value)
assertEquals(paymentDetails.amount, compoundExtractions.getPaymentExtraction("amount_to_pay")?.value)
assertEquals(paymentDetails.purpose, compoundExtractions.getPaymentExtraction("payment_purpose")?.value)
assertThat(newPaymentDetails.recipient).isEqualTo("recipient")
}

@Test
fun `Converts amount_to_pay to backend format when updating payment detail values for feedback`() {
fun `Keeps original value if field not empty`() {
// Given
val compoundExtractions = mutableMapOf("payment" to CompoundExtraction(
"payment",
listOf(mapOf(
"amount_to_pay" to SpecificExtraction(
"amount_to_pay",
"1.11:EUR",
"", null, emptyList()
)
))
))

val paymentDetails = PaymentDetails(
recipient = "Jack Vance",
iban = "DE987654321",
amount = "9.99",
purpose = "Still testing"
recipient = "",
iban = "iban",
amount = "30",
purpose = "payment"
)

// When
compoundExtractions.withFeedback(paymentDetails)

// Then
assertEquals("9.99:EUR", compoundExtractions.getPaymentExtraction("amount_to_pay")?.value)
}

@Test
fun `Converts amount_to_pay extraction value to number`() {
// Given
val extractionsContainer = ExtractionsContainer(
emptyMap(),
mutableMapOf("payment" to CompoundExtraction(
"payment",
listOf(mapOf(
"amount_to_pay" to SpecificExtraction(
"amount_to_pay",
"1.11:EUR",
"", null, emptyList()
)
))
))
val nonEmptyPaymentFields = PaymentDetails(
recipient = "recipient",
iban = "iban2",
amount = "30",
purpose = "payment"
)

// When
val paymentDetails = extractionsContainer.toPaymentDetails()
val newPaymentDetails = paymentDetails.overwriteEmptyFields(nonEmptyPaymentFields)

// Then
assertEquals("1.11", paymentDetails.amount)
assertThat(newPaymentDetails.iban).isEqualTo("iban")
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ class GiniPaymentTest {
iban = "iban",
amount = "20",
purpose = "purpose",
extractions = null
)

@Before
Expand Down

0 comments on commit 5f96267

Please sign in to comment.