diff options
5 files changed, 51 insertions, 33 deletions
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/DB.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/DB.kt index 366449bf..2b7475ab 100644 --- a/nexus/src/main/kotlin/tech/libeufin/nexus/DB.kt +++ b/nexus/src/main/kotlin/tech/libeufin/nexus/DB.kt @@ -64,7 +64,7 @@ class TalerRequestedPaymentEntity(id: EntityID<Long>) : LongEntity(id) { * entries from the raw payments table. Fixme: name should end with "-table". */ object TalerIncomingPayments : LongIdTable() { - val payment = reference("payment", RawBankTransactionsTable) + val payment = reference("payment", NexusBankTransactionsTable) val reservePublicKey = text("reservePublicKey") val timestampMs = long("timestampMs") val incomingPaytoUri = text("incomingPaytoUri") @@ -73,7 +73,7 @@ object TalerIncomingPayments : LongIdTable() { class TalerIncomingPaymentEntity(id: EntityID<Long>) : LongEntity(id) { companion object : LongEntityClass<TalerIncomingPaymentEntity>(TalerIncomingPayments) - var payment by RawBankTransactionEntity referencedOn TalerIncomingPayments.payment + var payment by NexusBankTransactionEntity referencedOn TalerIncomingPayments.payment var reservePublicKey by TalerIncomingPayments.reservePublicKey var timestampMs by TalerIncomingPayments.timestampMs var incomingPaytoUri by TalerIncomingPayments.incomingPaytoUri @@ -104,7 +104,7 @@ class NexusBankMessageEntity(id: EntityID<Int>) : IntEntity(id) { * This table contains history "elements" as returned by the bank from a * CAMT message. */ -object RawBankTransactionsTable : LongIdTable() { +object NexusBankTransactionsTable : LongIdTable() { /** * Identifier for the transaction that is unique among all transactions of the account. * The scheme for this identifier is the accounts transaction identification scheme. @@ -138,7 +138,7 @@ object RawBankTransactionsTable : LongIdTable() { /** * Another, later transaction that updates the status of the current transaction. */ - val updatedBy = optReference("updatedBy", RawBankTransactionsTable) + val updatedBy = optReference("updatedBy", NexusBankTransactionsTable) /** * Full details of the transaction in JSON format. @@ -146,16 +146,16 @@ object RawBankTransactionsTable : LongIdTable() { val transactionJson = text("transactionJson") } -class RawBankTransactionEntity(id: EntityID<Long>) : LongEntity(id) { - companion object : LongEntityClass<RawBankTransactionEntity>(RawBankTransactionsTable) - var currency by RawBankTransactionsTable.currency - var amount by RawBankTransactionsTable.amount - var status by RawBankTransactionsTable.status - var creditDebitIndicator by RawBankTransactionsTable.creditDebitIndicator - var bankAccount by NexusBankAccountEntity referencedOn RawBankTransactionsTable.bankAccount - var transactionJson by RawBankTransactionsTable.transactionJson - var accountTransactionId by RawBankTransactionsTable.accountTransactionId - val updatedBy by RawBankTransactionEntity optionalReferencedOn RawBankTransactionsTable.updatedBy +class NexusBankTransactionEntity(id: EntityID<Long>) : LongEntity(id) { + companion object : LongEntityClass<NexusBankTransactionEntity>(NexusBankTransactionsTable) + var currency by NexusBankTransactionsTable.currency + var amount by NexusBankTransactionsTable.amount + var status by NexusBankTransactionsTable.status + var creditDebitIndicator by NexusBankTransactionsTable.creditDebitIndicator + var bankAccount by NexusBankAccountEntity referencedOn NexusBankTransactionsTable.bankAccount + var transactionJson by NexusBankTransactionsTable.transactionJson + var accountTransactionId by NexusBankTransactionsTable.accountTransactionId + val updatedBy by NexusBankTransactionEntity optionalReferencedOn NexusBankTransactionsTable.updatedBy } /** @@ -184,7 +184,7 @@ object PaymentInitiationsTable : LongIdTable() { * Points at the raw transaction witnessing that this * initiated payment was successfully performed. */ - val rawConfirmation = reference("rawConfirmation", RawBankTransactionsTable).nullable() + val confirmationTransaction = reference("rawConfirmation", NexusBankTransactionsTable).nullable() } class PaymentInitiationEntity(id: EntityID<Long>) : LongEntity(id) { @@ -204,7 +204,7 @@ class PaymentInitiationEntity(id: EntityID<Long>) : LongEntity(id) { var paymentInformationId by PaymentInitiationsTable.paymentInformationId var messageId by PaymentInitiationsTable.messageId var instructionId by PaymentInitiationsTable.instructionId - var rawConfirmation by RawBankTransactionEntity optionalReferencedOn PaymentInitiationsTable.rawConfirmation + var confirmationTransaction by NexusBankTransactionEntity optionalReferencedOn PaymentInitiationsTable.confirmationTransaction } /** @@ -343,7 +343,7 @@ fun dbCreateTables(dbName: String) { PaymentInitiationsTable, EbicsSubscribersTable, NexusBankAccountsTable, - RawBankTransactionsTable, + NexusBankTransactionsTable, TalerIncomingPayments, TalerRequestedPayments, NexusBankConnectionsTable, diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/Iso20022.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/Iso20022.kt index 5c880775..ffba9f4b 100644 --- a/nexus/src/main/kotlin/tech/libeufin/nexus/Iso20022.kt +++ b/nexus/src/main/kotlin/tech/libeufin/nexus/Iso20022.kt @@ -194,7 +194,9 @@ data class AmountDetails( @JsonInclude(JsonInclude.Include.NON_NULL) data class References( - val endToEndIdentification: String? + val endToEndIdentification: String? = null, + val paymentInformationIdentification: String? = null, + val messageIdentification: String? = null ) /** @@ -444,9 +446,11 @@ private fun XmlElementDestructor.extractTransactionDetails(): List<TransactionDe } ?: AmountDetails(null, null), references = maybeUniqueChildNamed("Refs") { References( - endToEndIdentification = maybeUniqueChildNamed("EndToEndId") { it.textContent } + endToEndIdentification = maybeUniqueChildNamed("EndToEndId") { it.textContent }, + messageIdentification = maybeUniqueChildNamed("MsgId") { it.textContent }, + paymentInformationIdentification = maybeUniqueChildNamed("PmtInfId") { it.textContent } ) - } ?: References(null), + } ?: References(), unstructuredRemittanceInformation = maybeUniqueChildNamed("RmtInf") { requireUniqueChildNamed("Ustrd") { it.textContent } } ?: "" diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt index 8de9a0d2..f70cae41 100644 --- a/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt +++ b/nexus/src/main/kotlin/tech/libeufin/nexus/Main.kt @@ -662,7 +662,7 @@ fun serverMain(dbName: String) { val ret = Transactions() transaction { authenticateRequest(call.request).id.value - RawBankTransactionEntity.all().map { + NexusBankTransactionEntity.all().map { val tx = jacksonObjectMapper().readValue(it.transactionJson, BankTransaction::class.java) ret.transactions.add(tx) } diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/bankaccount/BankAccount.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/bankaccount/BankAccount.kt index 16a17c34..acd128da 100644 --- a/nexus/src/main/kotlin/tech/libeufin/nexus/bankaccount/BankAccount.kt +++ b/nexus/src/main/kotlin/tech/libeufin/nexus/bankaccount/BankAccount.kt @@ -24,7 +24,6 @@ import io.ktor.client.HttpClient import io.ktor.http.HttpStatusCode import org.jetbrains.exposed.sql.SortOrder import org.jetbrains.exposed.sql.and -import org.jetbrains.exposed.sql.not import org.jetbrains.exposed.sql.transactions.transaction import org.w3c.dom.Document import tech.libeufin.nexus.* @@ -90,12 +89,12 @@ suspend fun submitAllPreparedPayments(httpClient: HttpClient) { /** * Check if the transaction is already found in the database. */ -private fun findDuplicate(bankAccountId: String, acctSvcrRef: String): RawBankTransactionEntity? { +private fun findDuplicate(bankAccountId: String, acctSvcrRef: String): NexusBankTransactionEntity? { // FIXME: make this generic depending on transaction identification scheme val ati = "AcctSvcrRef:$acctSvcrRef" return transaction { - RawBankTransactionEntity.find { - (RawBankTransactionsTable.accountTransactionId eq ati) and (RawBankTransactionsTable.bankAccount eq bankAccountId) + NexusBankTransactionEntity.find { + (NexusBankTransactionsTable.accountTransactionId eq ati) and (NexusBankTransactionsTable.bankAccount eq bankAccountId) }.firstOrNull() } } @@ -126,7 +125,7 @@ fun processCamtMessage( break } - val rawEntity = RawBankTransactionEntity.new { + val rawEntity = NexusBankTransactionEntity.new { bankAccount = acct accountTransactionId = "AcctSvcrRef:$acctSvcrRef" amount = tx.amount @@ -135,7 +134,22 @@ fun processCamtMessage( creditDebitIndicator = tx.creditDebitIndicator.name status = tx.status } + rawEntity.flush() if (tx.creditDebitIndicator == CreditDebitIndicator.DBIT) { + val t0 = tx.details.getOrNull(0) + val msgId = t0?.references?.messageIdentification + val pmtInfId = t0?.references?.paymentInformationIdentification + if (t0 != null && msgId != null && pmtInfId != null) { + val paymentInitiation = PaymentInitiationEntity.find { + (PaymentInitiationsTable.messageId eq msgId) and + (PaymentInitiationsTable.bankAccount eq acct.id) and + (PaymentInitiationsTable.paymentInformationId eq pmtInfId) + + }.firstOrNull() + if (paymentInitiation != null) { + paymentInitiation.confirmationTransaction = rawEntity + } + } // FIXME: find matching PaymentInitiation by PaymentInformationID, message ID or whatever is present } } diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/taler.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/taler.kt index 4741ecbc..2b4dbc2a 100644 --- a/nexus/src/main/kotlin/tech/libeufin/nexus/taler.kt +++ b/nexus/src/main/kotlin/tech/libeufin/nexus/taler.kt @@ -350,7 +350,7 @@ private suspend fun talerAddIncoming(call: ApplicationCall, httpClient: HttpClie } -private fun ingestIncoming(payment: RawBankTransactionEntity, txDtls: TransactionDetails) { +private fun ingestIncoming(payment: NexusBankTransactionEntity, txDtls: TransactionDetails) { val subject = txDtls.unstructuredRemittanceInformation val debtorName = txDtls.relatedParties.debtor?.name if (debtorName == null) { @@ -407,14 +407,14 @@ fun ingestTalerTransactions() { logger.debug("Ingesting transactions for Taler facade ${facade.id.value}") val facadeState = getTalerFacadeState(facade.id.value) var lastId = facadeState.highestSeenMsgID - RawBankTransactionEntity.find { + NexusBankTransactionEntity.find { /** Those with exchange bank account involved */ - RawBankTransactionsTable.bankAccount eq subscriberAccount.id.value and + NexusBankTransactionsTable.bankAccount eq subscriberAccount.id.value and /** Those that are booked */ - (RawBankTransactionsTable.status eq TransactionStatus.BOOK) and + (NexusBankTransactionsTable.status eq TransactionStatus.BOOK) and /** Those that came later than the latest processed payment */ - (RawBankTransactionsTable.id.greater(lastId)) - }.orderBy(Pair(RawBankTransactionsTable.id, SortOrder.ASC)).forEach { + (NexusBankTransactionsTable.id.greater(lastId)) + }.orderBy(Pair(NexusBankTransactionsTable.id, SortOrder.ASC)).forEach { // Incoming payment. val tx = jacksonObjectMapper().readValue(it.transactionJson, BankTransaction::class.java) if (tx.isBatch) { @@ -464,7 +464,7 @@ private suspend fun historyOutgoing(call: ApplicationCall) { startCmpOp }.orderTaler(delta) reqPaymentsWithUnconfirmed.forEach { - if (it.preparedPayment.rawConfirmation != null) { + if (it.preparedPayment.confirmationTransaction != null) { reqPayments.add(it) } } |