commit 029d0258b5ea5cce71f544b1e874975115e4218f
parent 0a44db6147a3041de0039c48b85f865b8b1b26e2
Author: Marcello Stanisci <stanisci.m@gmail.com>
Date: Tue, 18 Feb 2020 21:02:14 +0100
PAIN001 table.
Diffstat:
5 files changed, 202 insertions(+), 174 deletions(-)
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/DB.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/DB.kt
@@ -0,0 +1,128 @@
+package tech.libeufin.nexus
+
+import org.jetbrains.exposed.dao.*
+import org.jetbrains.exposed.sql.*
+import org.jetbrains.exposed.sql.transactions.TransactionManager
+import org.jetbrains.exposed.sql.transactions.transaction
+import tech.libeufin.nexus.EbicsSubscribersTable.entityId
+import tech.libeufin.nexus.EbicsSubscribersTable.primaryKey
+import tech.libeufin.util.IntIdTableWithAmount
+import java.sql.Connection
+
+const val ID_MAX_LENGTH = 50
+
+
+//object EbicsRawBankTransactionsTable : IdTable<Long>() {
+// override val id = EbicsSubscribersTable.long("id").entityId().primaryKey()
+//
+// val nexusSubscriber = reference("subscriber", EbicsSubscribersTable)
+//
+// /**
+// * How did we learn about this transaction? C52 / C53 / C54
+// */
+// val sourceType = text("sourceType")
+//
+// val sourceFileName = text("sourceFileName")
+//
+//
+//
+// /**
+// * "Subject" of the SEPA transaction
+// */
+// val unstructuredRemittanceInformation = text("unstructuredRemittanceInformation")
+//
+// /**
+// * Is it a credit or debit transaction?
+// */
+// val transactionType = text("transactionType")
+//
+// val currency = text("currency")
+//
+// val amount = text("amount")
+//
+// val creditorIban = text("creditorIban")
+//
+// val debitorIban = text("creditorIban")
+//}
+//
+//
+///**
+// * This table gets populated by the HTD request.
+// *
+// * It stores which subscriber has access to which bank accounts via EBICS.
+// *
+// * When making a payment, we need to refer to one of these accounts
+// */
+//object EbicsBankAccountsTable {
+//
+//}
+
+object Pain001Table : IntIdTableWithAmount() {
+ val msgId = integer("msgId").uniqueIndex()
+ val paymentId = integer("paymentId").uniqueIndex() // id for this system
+ val date = date("fileDate")
+ val sum = amount("sum")
+ val debtorAccount = text("debtorAccount")
+ val endToEndId = integer("EndToEndId").uniqueIndex() // id for this and the creditor system
+ val subject = text("subject")
+ val creditorIban = text("creditorIban")
+ val creditorBic = text("creditorBic")
+ val creditorName = text("creditorName")
+ val submitted = bool("submitted") // indicates whether the PAIN message was sent to the bank.
+}
+
+object EbicsAccountsInfoTable : IdTable<String>() {
+ override val id = varchar("id", ID_MAX_LENGTH).entityId().primaryKey()
+ val subscriber = reference("subscriber", EbicsSubscribersTable)
+ val accountHolder = text("accountHolder").nullable()
+ val iban = text("iban")
+ val bankCode = text("bankCode")
+}
+
+class EbicsAccountInfoEntity(id: EntityID<String>) : Entity<String>(id) {
+ companion object : EntityClass<String, EbicsAccountInfoEntity>(EbicsAccountsInfoTable)
+ var subscriber by EbicsSubscriberEntity referencedOn EbicsAccountsInfoTable.subscriber
+ var accountHolder by EbicsAccountsInfoTable.accountHolder
+ var iban by EbicsAccountsInfoTable.iban
+ var bankCode by EbicsAccountsInfoTable.bankCode
+}
+
+object EbicsSubscribersTable : IdTable<String>() {
+ override val id = varchar("id", ID_MAX_LENGTH).entityId().primaryKey()
+ val ebicsURL = text("ebicsURL")
+ val hostID = text("hostID")
+ val partnerID = text("partnerID")
+ val userID = text("userID")
+ val systemID = text("systemID").nullable()
+ val signaturePrivateKey = blob("signaturePrivateKey")
+ val encryptionPrivateKey = blob("encryptionPrivateKey")
+ val authenticationPrivateKey = blob("authenticationPrivateKey")
+ val bankEncryptionPublicKey = blob("bankEncryptionPublicKey").nullable()
+ val bankAuthenticationPublicKey = blob("bankAuthenticationPublicKey").nullable()
+}
+
+class EbicsSubscriberEntity(id: EntityID<String>) : Entity<String>(id) {
+ companion object : EntityClass<String, EbicsSubscriberEntity>(EbicsSubscribersTable)
+ var ebicsURL by EbicsSubscribersTable.ebicsURL
+ var hostID by EbicsSubscribersTable.hostID
+ var partnerID by EbicsSubscribersTable.partnerID
+ var userID by EbicsSubscribersTable.userID
+ var systemID by EbicsSubscribersTable.systemID
+ var signaturePrivateKey by EbicsSubscribersTable.signaturePrivateKey
+ var encryptionPrivateKey by EbicsSubscribersTable.encryptionPrivateKey
+ var authenticationPrivateKey by EbicsSubscribersTable.authenticationPrivateKey
+ var bankEncryptionPublicKey by EbicsSubscribersTable.bankEncryptionPublicKey
+ var bankAuthenticationPublicKey by EbicsSubscribersTable.bankAuthenticationPublicKey
+}
+
+fun dbCreateTables() {
+ Database.connect("jdbc:sqlite:libeufin-nexus.sqlite3", "org.sqlite.JDBC")
+ TransactionManager.manager.defaultIsolationLevel = Connection.TRANSACTION_SERIALIZABLE
+ transaction {
+ addLogger(StdOutSqlLogger)
+ SchemaUtils.create(
+ EbicsSubscribersTable,
+ EbicsAccountsInfoTable
+ )
+ }
+}
+\ No newline at end of file
diff --git a/nexus/src/main/kotlin/tech/libeufin/nexus/Db.kt b/nexus/src/main/kotlin/tech/libeufin/nexus/Db.kt
@@ -1,113 +0,0 @@
-package tech.libeufin.nexus
-
-import org.jetbrains.exposed.dao.*
-import org.jetbrains.exposed.sql.*
-import org.jetbrains.exposed.sql.transactions.TransactionManager
-import org.jetbrains.exposed.sql.transactions.transaction
-import tech.libeufin.nexus.EbicsSubscribersTable.entityId
-import tech.libeufin.nexus.EbicsSubscribersTable.primaryKey
-import java.sql.Connection
-
-const val ID_MAX_LENGTH = 50
-
-
-//object EbicsRawBankTransactionsTable : IdTable<Long>() {
-// override val id = EbicsSubscribersTable.long("id").entityId().primaryKey()
-//
-// val nexusSubscriber = reference("subscriber", EbicsSubscribersTable)
-//
-// /**
-// * How did we learn about this transaction? C52 / C53 / C54
-// */
-// val sourceType = text("sourceType")
-//
-// val sourceFileName = text("sourceFileName")
-//
-//
-//
-// /**
-// * "Subject" of the SEPA transaction
-// */
-// val unstructuredRemittanceInformation = text("unstructuredRemittanceInformation")
-//
-// /**
-// * Is it a credit or debit transaction?
-// */
-// val transactionType = text("transactionType")
-//
-// val currency = text("currency")
-//
-// val amount = text("amount")
-//
-// val creditorIban = text("creditorIban")
-//
-// val debitorIban = text("creditorIban")
-//}
-//
-//
-///**
-// * This table gets populated by the HTD request.
-// *
-// * It stores which subscriber has access to which bank accounts via EBICS.
-// *
-// * When making a payment, we need to refer to one of these accounts
-// */
-//object EbicsBankAccountsTable {
-//
-//}
-
-object EbicsAccountsInfoTable : IdTable<String>() {
- override val id = varchar("id", ID_MAX_LENGTH).entityId().primaryKey()
- val subscriber = reference("subscriber", EbicsSubscribersTable)
- val accountHolder = text("accountHolder").nullable()
- val iban = text("iban")
- val bankCode = text("bankCode")
-}
-
-class EbicsAccountInfoEntity(id: EntityID<String>) : Entity<String>(id) {
- companion object : EntityClass<String, EbicsAccountInfoEntity>(EbicsAccountsInfoTable)
- var subscriber by EbicsSubscriberEntity referencedOn EbicsAccountsInfoTable.subscriber
- var accountHolder by EbicsAccountsInfoTable.accountHolder
- var iban by EbicsAccountsInfoTable.iban
- var bankCode by EbicsAccountsInfoTable.bankCode
-}
-
-object EbicsSubscribersTable : IdTable<String>() {
- override val id = varchar("id", ID_MAX_LENGTH).entityId().primaryKey()
- val ebicsURL = text("ebicsURL")
- val hostID = text("hostID")
- val partnerID = text("partnerID")
- val userID = text("userID")
- val systemID = text("systemID").nullable()
- val signaturePrivateKey = blob("signaturePrivateKey")
- val encryptionPrivateKey = blob("encryptionPrivateKey")
- val authenticationPrivateKey = blob("authenticationPrivateKey")
- val bankEncryptionPublicKey = blob("bankEncryptionPublicKey").nullable()
- val bankAuthenticationPublicKey = blob("bankAuthenticationPublicKey").nullable()
-}
-
-class EbicsSubscriberEntity(id: EntityID<String>) : Entity<String>(id) {
- companion object : EntityClass<String, EbicsSubscriberEntity>(EbicsSubscribersTable)
- var ebicsURL by EbicsSubscribersTable.ebicsURL
- var hostID by EbicsSubscribersTable.hostID
- var partnerID by EbicsSubscribersTable.partnerID
- var userID by EbicsSubscribersTable.userID
- var systemID by EbicsSubscribersTable.systemID
- var signaturePrivateKey by EbicsSubscribersTable.signaturePrivateKey
- var encryptionPrivateKey by EbicsSubscribersTable.encryptionPrivateKey
- var authenticationPrivateKey by EbicsSubscribersTable.authenticationPrivateKey
- var bankEncryptionPublicKey by EbicsSubscribersTable.bankEncryptionPublicKey
- var bankAuthenticationPublicKey by EbicsSubscribersTable.bankAuthenticationPublicKey
-}
-
-fun dbCreateTables() {
- Database.connect("jdbc:sqlite:libeufin-nexus.sqlite3", "org.sqlite.JDBC")
- TransactionManager.manager.defaultIsolationLevel = Connection.TRANSACTION_SERIALIZABLE
- transaction {
- addLogger(StdOutSqlLogger)
- SchemaUtils.create(
- EbicsSubscribersTable,
- EbicsAccountsInfoTable
- )
- }
-}
-\ No newline at end of file
diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/DB.kt b/sandbox/src/main/kotlin/tech/libeufin/sandbox/DB.kt
@@ -24,12 +24,15 @@ import org.jetbrains.exposed.dao.*
import org.jetbrains.exposed.sql.*
import org.jetbrains.exposed.sql.transactions.TransactionManager
import org.jetbrains.exposed.sql.transactions.transaction
+import tech.libeufin.util.IntIdTableWithAmount
import java.lang.ArithmeticException
import java.math.BigDecimal
import java.math.MathContext
import java.math.RoundingMode
import java.sql.Blob
import java.sql.Connection
+import tech.libeufin.util.IntIdTableWithAmount
+
const val CUSTOMER_NAME_MAX_LENGTH = 20
@@ -39,8 +42,6 @@ const val EBICS_PARTNER_ID_MAX_LENGTH = 10
const val EBICS_SYSTEM_ID_MAX_LENGTH = 10
const val MAX_ID_LENGTH = 21 // enough to contain IBANs
const val MAX_SUBJECT_LENGTH = 140 // okay?
-const val NUMBER_MAX_DIGITS = 20
-const val SCALE_TWO = 2
/**
* All the states to give a subscriber.
@@ -95,62 +96,6 @@ enum class KeyState {
RELEASED
}
-/**
- * Any number can become a Amount IF it does NOT need to be rounded to comply to the scale == 2.
- */
-typealias Amount = BigDecimal
-
-open class IntIdTableWithAmount : IntIdTable() {
-
- class AmountColumnType : ColumnType() {
- override fun sqlType(): String = "DECIMAL(${NUMBER_MAX_DIGITS}, ${SCALE_TWO})"
-
- override fun valueFromDB(value: Any): Any {
-
- val valueFromDB = super.valueFromDB(value)
-
- try {
- return when (valueFromDB) {
- is BigDecimal -> valueFromDB.setScale(SCALE_TWO, RoundingMode.UNNECESSARY)
- is Double -> BigDecimal.valueOf(valueFromDB).setScale(SCALE_TWO, RoundingMode.UNNECESSARY)
- is Float -> BigDecimal(java.lang.Float.toString(valueFromDB)).setScale(
- SCALE_TWO,
- RoundingMode.UNNECESSARY
- )
- is Int -> BigDecimal(valueFromDB)
- is Long -> BigDecimal.valueOf(valueFromDB)
- else -> valueFromDB
- }
- } catch (e: Exception) {
- e.printStackTrace()
- throw BadAmount(value)
- }
- }
-
- override fun valueToDB(value: Any?): Any? {
- try {
- (value as BigDecimal).setScale(SCALE_TWO, RoundingMode.UNNECESSARY)
- } catch (e: Exception) {
- e.printStackTrace()
- throw BadAmount(value)
- }
-
- if (value.compareTo(BigDecimal.ZERO) == 0) {
- LOGGER.error("Cannot have transactions of ZERO amount")
- throw BadAmount(value)
- }
- return super.valueToDB(value)
- }
- }
-
- /**
- * Make sure the number entered by upper layers does not need any rounding
- * to conform to scale == 2
- */
- fun amount(name: String): Column<Amount> {
- return registerColumn(name, AmountColumnType())
- }
-}
object BankTransactionsTable : IntIdTableWithAmount() {
diff --git a/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt b/sandbox/src/main/kotlin/tech/libeufin/sandbox/Main.kt
@@ -48,6 +48,7 @@ import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.slf4j.event.Level
import org.w3c.dom.Document
+import tech.libeufin.util.Amount
import tech.libeufin.util.CryptoUtil
import java.lang.ArithmeticException
import java.math.BigDecimal
@@ -58,7 +59,6 @@ import javax.xml.bind.JAXBContext
class CustomerNotFound(id: String?) : Exception("Customer ${id} not found")
class BadInputData(inputData: String?) : Exception("Customer provided invalid input data: ${inputData}")
-class BadAmount(badValue: Any?) : Exception("Value '${badValue}' is not a valid amount")
class UnacceptableFractional(badNumber: BigDecimal) : Exception(
"Unacceptable fractional part ${badNumber}"
)
@@ -149,7 +149,7 @@ fun sampleData() {
nextOrderID = 1
bankCustomer = customerEntity
}
- for (i in listOf<Amount>(Amount("-0.44"), Amount("6.02"))) {
+ for (i in listOf(Amount("-0.44"), Amount("6.02"))) {
BankTransactionEntity.new {
counterpart = "IBAN"
amount = i
diff --git a/util/src/main/kotlin/DBTypes.kt b/util/src/main/kotlin/DBTypes.kt
@@ -0,0 +1,67 @@
+package tech.libeufin.util
+
+import org.jetbrains.exposed.dao.IntIdTable
+import org.jetbrains.exposed.sql.Column
+import org.jetbrains.exposed.sql.ColumnType
+import java.math.BigDecimal
+import java.math.RoundingMode
+
+const val SCALE_TWO = 2
+const val NUMBER_MAX_DIGITS = 20
+class BadAmount(badValue: Any?) : Exception("Value '${badValue}' is not a valid amount")
+
+/**
+ * Any number can become a Amount IF it does NOT need to be rounded to comply to the scale == 2.
+ */
+typealias Amount = BigDecimal
+
+open class IntIdTableWithAmount : IntIdTable() {
+
+ class AmountColumnType : ColumnType() {
+ override fun sqlType(): String = "DECIMAL(${NUMBER_MAX_DIGITS}, ${SCALE_TWO})"
+
+ override fun valueFromDB(value: Any): Any {
+
+ val valueFromDB = super.valueFromDB(value)
+
+ try {
+ return when (valueFromDB) {
+ is BigDecimal -> valueFromDB.setScale(SCALE_TWO, RoundingMode.UNNECESSARY)
+ is Double -> BigDecimal.valueOf(valueFromDB).setScale(SCALE_TWO, RoundingMode.UNNECESSARY)
+ is Float -> BigDecimal(java.lang.Float.toString(valueFromDB)).setScale(
+ SCALE_TWO,
+ RoundingMode.UNNECESSARY
+ )
+ is Int -> BigDecimal(valueFromDB)
+ is Long -> BigDecimal.valueOf(valueFromDB)
+ else -> valueFromDB
+ }
+ } catch (e: Exception) {
+ e.printStackTrace()
+ throw BadAmount(value)
+ }
+ }
+
+ override fun valueToDB(value: Any?): Any? {
+ try {
+ (value as BigDecimal).setScale(SCALE_TWO, RoundingMode.UNNECESSARY)
+ } catch (e: Exception) {
+ e.printStackTrace()
+ throw BadAmount(value)
+ }
+
+ if (value.compareTo(BigDecimal.ZERO) == 0) {
+ throw BadAmount(value)
+ }
+ return super.valueToDB(value)
+ }
+ }
+
+ /**
+ * Make sure the number entered by upper layers does not need any rounding
+ * to conform to scale == 2
+ */
+ fun amount(name: String): Column<Amount> {
+ return registerColumn(name, AmountColumnType())
+ }
+}
+\ No newline at end of file