commit 22e474fa22b5dba46f01d141d1da46a427469b72
parent c688de41036ab5e6a7fcf4fcdad278136e2a66d1
Author: MS <ms@taler.net>
Date: Wed, 17 Jun 2020 18:01:17 +0200
Linking a raw payment to a initiated one,
after the raw shows up in one report from the bank.
Diffstat:
3 files changed, 48 insertions(+), 1 deletion(-)
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/DB.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/DB.kt
@@ -190,6 +190,9 @@ object InitiatedPaymentsTable : LongIdTable() {
val debitorBic = text("debitorBic")
val debitorName = text("debitorName").nullable()
val submitted = bool("submitted").default(false)
+ // points at the raw transaction witnessing that this
+ // initiated payment was successfully performed.
+ val rawConfirmation = reference("rawConfirmation", RawBankTransactionsTable).nullable()
}
class InitiatedPaymentEntity(id: EntityID<Long>) : LongEntity(id) {
@@ -207,6 +210,7 @@ class InitiatedPaymentEntity(id: EntityID<Long>) : LongEntity(id) {
var creditorBic by InitiatedPaymentsTable.creditorBic
var creditorName by InitiatedPaymentsTable.creditorName
var submitted by InitiatedPaymentsTable.submitted
+ var rawConfirmation by RawBankTransactionEntity optionalReferencedOn InitiatedPaymentsTable.rawConfirmation
}
/**
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/Helpers.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/Helpers.kt
@@ -110,6 +110,26 @@ private fun findDuplicate(bankAccountId: String, acctSvcrRef: String): RawBankTr
}
}
+// retrieves the initiated payment and marks it as "performed
+// by the bank". This avoids to submit it again. 'subject' is
+// the the A.K.A. unstructured remittance information.
+fun markInitiatedAsConfirmed(subject: String, debtorIban: String, rawUuid: Long) {
+ // not introducing a 'transaction {}' block since
+ // this function should be always be invoked from one.
+ val initiatedPayment = InitiatedPaymentEntity.find {
+ InitiatedPaymentsTable.subject eq subject and
+ (InitiatedPaymentsTable.debitorIban eq debtorIban)
+ }.firstOrNull()
+ if (initiatedPayment == null) {
+ logger.info("Payment '$subject' was never programmatically prepared")
+ return
+ }
+ val rawEntity = RawBankTransactionEntity.findById(rawUuid) ?: throw NexusError(
+ HttpStatusCode.InternalServerError, "Raw payment '$rawUuid' disappeared from database"
+ )
+ initiatedPayment.rawConfirmation = rawEntity
+}
+
fun processCamtMessage(
bankAccountId: String,
camtDoc: Document
@@ -135,7 +155,8 @@ fun processCamtMessage(
// https://bugs.gnunet.org/view.php?id=6381
break
}
- RawBankTransactionEntity.new {
+
+ val rawEntity = RawBankTransactionEntity.new {
bankAccount = acct
accountTransactionId = "AcctSvcrRef:$acctSvcrRef"
amount = tx.amount
@@ -144,6 +165,26 @@ fun processCamtMessage(
creditDebitIndicator = tx.creditDebitIndicator.name
status = tx.status
}
+ if (tx.creditDebitIndicator == CreditDebitIndicator.DBIT) {
+ // assuming batches contain always one element, as aren't fully
+ // implemented now.
+ val uniqueBatchElement = tx.details.get(0)
+ markInitiatedAsConfirmed(
+ // if the user has two initiated payments under the same
+ // IBAN with the same subject, then this logic will cause
+ // problems. But a programmatic user should take care of this.
+ uniqueBatchElement.unstructuredRemittanceInformation,
+ if (uniqueBatchElement.relatedParties.debtorAccount !is AccountIdentificationIban) {
+ throw NexusError(
+ HttpStatusCode.InternalServerError,
+ "Parsed CAMT didn't have IBAN in debtor!"
+ )
+ } else {
+ uniqueBatchElement.relatedParties.debtorAccount.iban
+ },
+ rawEntity.id.value
+ )
+ }
}
}
}
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/taler.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/taler.kt
@@ -379,6 +379,7 @@ private suspend fun talerAddIncoming(call: ApplicationCall, httpClient: HttpClie
// submits ALL the prepared payments from ALL the Taler facades.
// FIXME(dold): This should not be done here.
+// -> why? It crawls the *taler* facade to find payment to submit.
suspend fun submitPreparedPaymentsViaEbics(httpClient: HttpClient) {
data class EbicsSubmission(
val subscriberDetails: EbicsClientSubscriberDetails,
@@ -417,6 +418,7 @@ suspend fun submitPreparedPaymentsViaEbics(httpClient: HttpClient) {
val subscriberDetails = getEbicsSubscriberDetailsInternal(subscriberEntity)
workQueue.add(EbicsSubmission(subscriberDetails, pain001document))
// FIXME: the payment must be flagged AFTER the submission happens.
+ // -> this is an open question: see #6367.
it.submitted = true
}
}