libeufin

Integration and sandbox testing for FinTech APIs and data formats
Log | Files | Refs | Submodules | README | LICENSE

commit c384fd4a41146ca6e5a0a3f4c3eb06b96d9f0dbe
parent 1c58a511f1e13db3b9267706e1937d4757349a1f
Author: ms <ms@taler.net>
Date:   Sat, 13 Nov 2021 10:23:17 +0100

Fixes after wallet harness tests.

- Implement sign-up bonus
- Do communicate debit balances

Diffstat:
Msandbox/src/main/kotlin/tech/libeufin/sandbox/DB.kt | 13+++++++++----
Msandbox/src/main/kotlin/tech/libeufin/sandbox/EbicsProtocolBackend.kt | 30++++++++++--------------------
Msandbox/src/main/kotlin/tech/libeufin/sandbox/Helpers.kt | 31+++++++++++++++++++++++++------
Msandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt | 28++++++++++++++++++----------
Msandbox/src/main/kotlin/tech/libeufin/sandbox/bankAccount.kt | 6------
Msandbox/src/test/kotlin/BalanceTest.kt | 8++++++++
6 files changed, 70 insertions(+), 46 deletions(-)

diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/DB.kt b/sandbox/src/main/kotlin/tech/libeufin/sandbox/DB.kt @@ -370,10 +370,16 @@ object BankAccountsTable : IntIdTable() { val iban = text("iban") val bic = text("bic").default("SANDBOXX") val label = text("label").uniqueIndex("accountLabelIndex") - val isDebit = bool("isDebit").default(false) /** - * Allow to assign "admin" - who doesn't have a customer DB entry - - * as the owner. That allows tests using the --no-auth option to go on. + * This field is the username of the customer that owns the + * bank account. Some actors do not have a customer registered, + * but they can still specify their "username" - merely a label + * that identifies their operations - to this field. + * + * Two examples of such actors are: "admin" and "bank". Note: + * "admin" cannot act as the bank, because it participates in + * tests and therefore should not have its balance affected by + * awarding sign-up bonuses. */ val owner = text("owner") val isPublic = bool("isPublic").default(false) @@ -386,7 +392,6 @@ class BankAccountEntity(id: EntityID<Int>) : IntEntity(id) { var iban by BankAccountsTable.iban var bic by BankAccountsTable.bic var label by BankAccountsTable.label - var isDebit by BankAccountsTable.isDebit var owner by BankAccountsTable.owner var isPublic by BankAccountsTable.isPublic var demoBank by DemobankConfigEntity referencedOn BankAccountsTable.demoBank diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/EbicsProtocolBackend.kt b/sandbox/src/main/kotlin/tech/libeufin/sandbox/EbicsProtocolBackend.kt @@ -243,6 +243,12 @@ private fun getRelatedParty(branch: XmlElementBuilder, payment: RawPayment) { } } +// This should fix #6269. +private fun getCreditDebitInd(balance: BigDecimal): String { + if (balance < BigDecimal.ZERO) return "DBIT" + return "CRDT" +} + fun buildCamtString( type: Int, subscriberIban: String, @@ -342,14 +348,10 @@ fun buildCamtString( } element("Amt") { attribute("Ccy", "EUR") - if (balancePrcd < BigDecimal.ZERO) { - text(balancePrcd.abs().toPlainString()) - } else { - text(balancePrcd.toPlainString()) - } + balancePrcd.abs().toPlainString() } element("CdtDbtInd") { - text("CRDT") + getCreditDebitInd(balancePrcd) } element("Dt/Dt") { // date of this balance @@ -365,22 +367,10 @@ fun buildCamtString( } element("Amt") { attribute("Ccy", "EUR") - // FIXME: the balance computation still not working properly - //text(balanceForAccount(subscriberIban).toString()) - if (balanceClbd < BigDecimal.ZERO) { - text(balanceClbd.abs().toPlainString()) - } else { - text(balanceClbd.toPlainString()) - } + balanceClbd.abs().toPlainString() } element("CdtDbtInd") { - // a temporary value to get the camt to validate. - // Should be fixed along #6269 - if (balanceClbd < BigDecimal.ZERO) { - text("DBIT") - } else { - text("CRDT") - } + getCreditDebitInd(balanceClbd) } element("Dt/Dt") { text(dashedDate) diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/Helpers.kt b/sandbox/src/main/kotlin/tech/libeufin/sandbox/Helpers.kt @@ -133,8 +133,10 @@ fun getCustomer(username: String): DemobankCustomerEntity { * Get person name from a customer's username. */ fun getPersonNameFromCustomer(ownerUsername: String): String { - return if (ownerUsername == "admin") "admin" else { - return transaction { + return when (ownerUsername) { + "admin" -> "admin" // Could be changed to Admin, or some different value. + "bank" -> "The Bank" + else -> transaction { val ownerCustomer = DemobankCustomerEntity.find( DemobankCustomersTable.username eq ownerUsername ).firstOrNull() ?: throw internalServerError( @@ -144,6 +146,15 @@ fun getPersonNameFromCustomer(ownerUsername: String): String { } } } +fun getFirstDemobank(): DemobankConfigEntity { + return transaction { + DemobankConfigEntity.all().firstOrNull() ?: throw SandboxError( + HttpStatusCode.InternalServerError, + "Cannot find one demobank, please create one!" + ) + } +} + fun getDefaultDemobank(): DemobankConfigEntity { return transaction { DemobankConfigEntity.find { @@ -321,17 +332,25 @@ fun getBankAccountFromSubscriber(subscriber: EbicsSubscriberEntity): BankAccount } } +fun BankAccountEntity.bonus(amount: String) { + wireTransfer( + "bank", + this.label, + this.demoBank.name, + "Sign-up bonus", + amount + ) +} + fun ensureDemobank(call: ApplicationCall): DemobankConfigEntity { return ensureDemobank(call.getUriComponent("demobankid")) } private fun ensureDemobank(name: String): DemobankConfigEntity { return transaction { - val res = DemobankConfigEntity.find { + DemobankConfigEntity.find { DemobankConfigsTable.name eq name - }.firstOrNull() - if (res == null) throw internalServerError("Demobank '$name' never created") - res + }.firstOrNull() ?: throw internalServerError("Demobank '$name' never created") } } diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt b/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt @@ -310,6 +310,18 @@ class Serve : CliktCommand("Run sandbox HTTP server") { ) exitProcess(0) } + /** + * Create the bank's bank account, to award the 100 Kudos + * when new customers open bank account. */ + transaction { + BankAccountEntity.new { + iban = getIban() + label = "bank" // used by the wire helper + owner = "bank" // used by the person name finder + // For now, the model assumes always one demobank + demoBank = getFirstDemobank() + } + } serverMain(port) } } @@ -437,7 +449,6 @@ val sandboxApp: Application.() -> Unit = { indentObjectsWith(DefaultIndenter(" ", "\n")) }) registerModule(KotlinModule(nullisSameAsDefault = true)) - //registerModule(JavaTimeModule()) } } install(StatusPages) { @@ -1216,16 +1227,11 @@ val sandboxApp: Application.() -> Unit = { ) throw forbidden( "Customer '$username' cannot access bank account '$accountAccessed'" ) - val creditDebitIndicator = if (bankAccount.isDebit) { - "debit" - } else { - "credit" - } val balance = balanceForAccount(bankAccount) call.respond(object { - val balance = { - val amount = "${demobank.currency}:${balance}" - val credit_debit_indicator = creditDebitIndicator + val balance = object { + val amount = "${demobank.currency}:${balance.abs(). toPlainString()}" + val credit_debit_indicator = if (balance < BigDecimal.ZERO) "debit" else "credit" } val paytoUri = buildIbanPaytoUri( iban = bankAccount.iban, @@ -1314,11 +1320,13 @@ val sandboxApp: Application.() -> Unit = { username = req.username passwordHash = CryptoUtil.hashpw(req.password) } + bankAccount.bonus("${demobank.currency}:100") bankAccount } + val balance = balanceForAccount(bankAccount) call.respond(object { val balance = { - val amount = "${demobank.currency}:0" + val amount = "${demobank.currency}:${balance}" val credit_debit_indicator = "CRDT" } val paytoUri = buildIbanPaytoUri( diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/bankAccount.kt b/sandbox/src/main/kotlin/tech/libeufin/sandbox/bankAccount.kt @@ -54,12 +54,6 @@ fun balanceForAccount(bankAccount: BankAccountEntity): BigDecimal { balance -= amount } } - /** - * FIXME: for negative accounts, temporarily return 0, so as to make - * the current CAMT generator happy. Negative amounts need to have their - * onw sub-tree in the report, see bug: #6962 - */ - if (balance < BigDecimal.ZERO) return BigDecimal.ZERO return balance } diff --git a/sandbox/src/test/kotlin/BalanceTest.kt b/sandbox/src/test/kotlin/BalanceTest.kt @@ -4,6 +4,7 @@ import org.jetbrains.exposed.sql.transactions.transaction import org.junit.Test import tech.libeufin.sandbox.* import tech.libeufin.util.millis +import java.math.BigDecimal import java.time.LocalDateTime class BalanceTest { @@ -86,4 +87,11 @@ class BalanceTest { } } } + @Test + fun balanceAbsTest() { + val minus = BigDecimal.ZERO - BigDecimal.ONE + val plus = BigDecimal.ONE + println(minus.abs().toPlainString()) + println(plus.abs().toPlainString()) + } }