libeufin

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

commit 2ae476cfb5073d61005ce15d0c317e11d26e588d
parent ddff58cf3e94873bc170dbbaff41ffe0fbc78f87
Author: MS <ms@taler.net>
Date:   Thu,  4 Feb 2021 15:18:42 +0100

testing refunds

Diffstat:
Mintegration-tests/tests.py | 47+++++++++++++++++++++++++++++++++++++++++++++++
Mnexus/src/main/kotlin/tech/libeufin/nexus/DB.kt | 12+++---------
Mnexus/src/main/kotlin/tech/libeufin/nexus/Scheduling.kt | 3++-
Mnexus/src/main/kotlin/tech/libeufin/nexus/Taler.kt | 18+++++++-----------
4 files changed, 59 insertions(+), 21 deletions(-)

diff --git a/integration-tests/tests.py b/integration-tests/tests.py @@ -420,6 +420,53 @@ def test_taler_facade_incoming(make_taler_facade): )) assert len(resp.json().get("incoming_transactions")) == 1 + +def test_taler_facade_refund(make_taler_facade): + resp = assertResponse(post( + f"{PERSONA.nexus.base_url}/facades/{PERSONA.nexus.taler_facade_name}/taler-wire-gateway/admin/add-incoming", + json=dict( + amount="EUR:1", + reserve_pub="invalid reserve public key", + debit_account="payto://iban/BUKBGB22/DE00000000000000000000?sender-name=TheName" + ), + auth=PERSONA.nexus.auth + )) + + assertResponse(post( + f"{PERSONA.nexus.base_url}/bank-accounts/{PERSONA.nexus.bank_label}/fetch-transactions", + auth=PERSONA.nexus.auth + )) + + assertResponse(post( + f"{PERSONA.nexus.base_url}/bank-accounts/{PERSONA.nexus.bank_label}/submit-all-payment-initiations", + auth=PERSONA.nexus.auth + )) + + # Fetch again the history, so as to find the freshly made refund. + assertResponse(post( + f"{PERSONA.nexus.base_url}/bank-accounts/{PERSONA.nexus.bank_label}/fetch-transactions", + auth=PERSONA.nexus.auth + )) + + resp = assertResponse( + get( + f"{PERSONA.nexus.base_url}/bank-accounts/{PERSONA.nexus.bank_label}/transactions", + auth=PERSONA.nexus.auth + ) + ) + + # Find the refund now! + print(json.dumps(resp.json(), indent=2)) + transactionsList = resp.json().get("transactions") + assert len(transactionsList) == 2 + for transaction in transactionsList: + movement = transaction.get("batches")[0].get("batchTransactions")[0] + subject = movement.get("details").get("unstructuredRemittanceInformation") + if subject.find("Taler refund") == 0 and movement.get("amount") == "EUR:1": + return + assert False, "Refund transaction not found" + + def test_taler_facade_outgoing(make_taler_facade): assertResponse( post( diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/DB.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/DB.kt @@ -61,8 +61,7 @@ class TalerRequestedPaymentEntity(id: EntityID<Long>) : LongEntity(id) { object TalerInvalidIncomingPaymentsTable : LongIdTable() { val payment = reference("payment", NexusBankTransactionsTable) val timestampMs = long("timestampMs") - val debtorPaytoUri = text("incomingPaytoUri") - val refunded = bool("refunded").default(true) + val refunded = bool("refunded").default(false) } class TalerInvalidIncomingPaymentEntity(id: EntityID<Long>) : LongEntity(id) { @@ -70,7 +69,6 @@ class TalerInvalidIncomingPaymentEntity(id: EntityID<Long>) : LongEntity(id) { var payment by NexusBankTransactionEntity referencedOn TalerInvalidIncomingPaymentsTable.payment var timestampMs by TalerInvalidIncomingPaymentsTable.timestampMs - var debtorPaytoUri by TalerInvalidIncomingPaymentsTable.debtorPaytoUri var refunded by TalerInvalidIncomingPaymentsTable.refunded } @@ -101,10 +99,6 @@ class TalerIncomingPaymentEntity(id: EntityID<Long>) : LongEntity(id) { */ object NexusBankMessagesTable : LongIdTable() { val bankConnection = reference("bankConnection", NexusBankConnectionsTable) - - /** - * Unique identifier for the message within the bank connection - */ val messageId = text("messageId") val code = text("code") val message = blob("message") @@ -454,6 +448,7 @@ fun dbDropTables(dbConnectionString: String) { NexusBankTransactionsTable, TalerIncomingPaymentsTable, TalerRequestedPaymentsTable, + TalerInvalidIncomingPaymentsTable, NexusBankConnectionsTable, NexusBankMessagesTable, FacadesTable, @@ -470,6 +465,7 @@ fun dbCreateTables(dbConnectionString: String) { TransactionManager.manager.defaultIsolationLevel = Connection.TRANSACTION_SERIALIZABLE transaction { SchemaUtils.create( + NexusScheduledTasksTable, NexusUsersTable, PaymentInitiationsTable, NexusEbicsSubscribersTable, @@ -482,9 +478,7 @@ fun dbCreateTables(dbConnectionString: String) { NexusBankConnectionsTable, NexusBankMessagesTable, FacadesTable, - NexusScheduledTasksTable, OfferedBankAccountsTable, - NexusScheduledTasksTable, NexusPermissionsTable, ) } diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/Scheduling.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/Scheduling.kt @@ -138,4 +138,4 @@ fun startOperationScheduler(httpClient: HttpClient) { delay(Duration.ofSeconds(1)) } } -} +} +\ No newline at end of file diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/Taler.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/Taler.kt @@ -389,9 +389,6 @@ private fun ingestIncoming(payment: NexusBankTransactionEntity, txDtls: Transact TalerInvalidIncomingPaymentEntity.new { this.payment = payment timestampMs = System.currentTimeMillis() - debtorPaytoUri = buildIbanPaytoUri( - debtorIban, debtorAgent.bic, debtorName, "DBIT" - ) } // FIXME: send back! return @@ -403,9 +400,6 @@ private fun ingestIncoming(payment: NexusBankTransactionEntity, txDtls: Transact TalerInvalidIncomingPaymentEntity.new { this.payment = payment timestampMs = System.currentTimeMillis() - debtorPaytoUri = buildIbanPaytoUri( - debtorIban, debtorAgent.bic, debtorName, "DBIT" - ) } logger.warn("Invalid public key found") // FIXME: send back! @@ -419,11 +413,10 @@ private fun ingestIncoming(payment: NexusBankTransactionEntity, txDtls: Transact debtorIban, debtorAgent.bic, debtorName, "DBIT" ) } - refundInvalidPayments() return } -fun refundInvalidPayments() { +fun prepareRefunds() { logger.debug("Finding new invalid payments to refund") transaction { TalerInvalidIncomingPaymentEntity.find { @@ -454,13 +447,12 @@ fun refundInvalidPayments() { throw NexusError(HttpStatusCode.InternalServerError, "Name to refund not found") } // FIXME: investigate this amount! - val amount = paymentData.batches[0].batchTransactions[0].details.instructedAmount + val amount = paymentData.batches[0].batchTransactions[0].amount if (amount == null) { logger.error("Could not find the amount to refund for transaction (AcctSvcrRef): ${paymentData.accountServicerRef}, aborting refund") throw NexusError(HttpStatusCode.InternalServerError, "Amount to refund not found") } // FIXME: the amount to refund should be reduced, according to the refund fees. - addPaymentInitiation( Pain001Data( creditorIban = debtorAccount.iban, @@ -472,6 +464,7 @@ fun refundInvalidPayments() { ), it.payment.bankAccount // the Exchange bank account. ) + logger.debug("Refund of transaction (AcctSvcrRef): ${paymentData.accountServicerRef} got prepared") it.refunded = true } } @@ -509,7 +502,10 @@ fun ingestTalerTransactions() { return@forEach } when (tx.creditDebitIndicator) { - CreditDebitIndicator.CRDT -> ingestIncoming(it, txDtls = details) + CreditDebitIndicator.CRDT -> { + ingestIncoming(it, txDtls = details) + prepareRefunds() + } else -> Unit } lastId = it.id.value