diff --git a/EpcQrCode/src/commonMain/kotlin/net/codinux/banking/epcqrcode/CreatorParam.kt b/EpcQrCode/src/commonMain/kotlin/net/codinux/banking/epcqrcode/CreatorParam.kt new file mode 100644 index 0000000..3924941 --- /dev/null +++ b/EpcQrCode/src/commonMain/kotlin/net/codinux/banking/epcqrcode/CreatorParam.kt @@ -0,0 +1,20 @@ +package net.codinux.banking.epcqrcode + + +open class CreatorParam( + + var receiverName: String = "", + + var iban: String = "", + + var bic: String? = null, + + var amount: Double? = null, + + var reference: String? = null, + + var noteToUser: String? = null, + + var encoding: EpcQrCodeCharacterSet = EpcQrCodeCharacterSet.UTF_8 + +) \ No newline at end of file diff --git a/EpcQrCode/src/commonMain/kotlin/net/codinux/banking/epcqrcode/EncodeToQrCodeConfig.kt b/EpcQrCode/src/commonMain/kotlin/net/codinux/banking/epcqrcode/EncodeToQrCodeConfig.kt index 627e049..b91467d 100644 --- a/EpcQrCode/src/commonMain/kotlin/net/codinux/banking/epcqrcode/EncodeToQrCodeConfig.kt +++ b/EpcQrCode/src/commonMain/kotlin/net/codinux/banking/epcqrcode/EncodeToQrCodeConfig.kt @@ -5,5 +5,5 @@ open class EncodeToQrCodeConfig( open val width: Int = 500, open val height: Int = 500, open val format: ImageFormat = ImageFormat.PNG, - open val encoding: EpcQrCodeEncoding = EpcQrCodeEncoding.Utf8 + open val encoding: EpcQrCodeCharacterSet = EpcQrCodeCharacterSet.UTF_8 ) \ No newline at end of file diff --git a/EpcQrCode/src/commonMain/kotlin/net/codinux/banking/epcqrcode/EpcQrCode.kt b/EpcQrCode/src/commonMain/kotlin/net/codinux/banking/epcqrcode/EpcQrCode.kt new file mode 100644 index 0000000..5bdd966 --- /dev/null +++ b/EpcQrCode/src/commonMain/kotlin/net/codinux/banking/epcqrcode/EpcQrCode.kt @@ -0,0 +1,102 @@ +package net.codinux.banking.epcqrcode + + +open class EpcQrCode( + + /** + * 3 bytes. + * Always(?) has value "BCD". + */ + open val serviceTag: String, + + /** + * 3 bytes. + * Has either value "001" or "002". + */ + open val version: EpcQrCodeVersion, + + /** + * 1 byte. + * The values 1,2,3,4,5,6,7 and 8 determine the interpretation of data to be used. + * In that order they qualify UTF-8, ISO 8895-1, ISO 8895-2, ISO 8895-4, ISO 8895-5, ISO 8895- 7, ISO 8895-10 and ISO 8895-15 + */ + open val coding: EpcQrCodeCharacterSet, + + /** + * 3 bytes. + * The Function is defined by its key value: SCT - SEPA Credit Transfer + */ + open val function: String, + + /** + * Receiver's BIC. + * Mandatory in Version 001, optional in Version 002. + * Either 8 or 11 bytes. + */ + open val bic: String?, + + /** + * Receiver name. + * Max. 70 characters + */ + open val receiverName: String, + + /** + * Receiver's IBAN. + * Max. 34 bytes. + */ + open val iban: String, + + /** + * Three capital letter currency code. + * Only set if amount is also set. + * The only Currency value available with this version is EUR. + */ + open val currencyCode: String?, + + /** + * Optional amount. + * Max. 12 bytes. + */ + open val amount: Double?, // TODO: use BigDecimal + + /** + * Optional purpose code. + * Max. 4 bytes. + */ + open val purposeCode: String?, + + open val remittanceReference: String?, + + open val remittanceText: String?, + + open val originatorInformation: String? + +) { + + companion object { + + const val ServiceTagDefaultValue = "BCD" + + const val FunctionDefaultValue = "SCT" + + const val CurrencyCodeDefaultValue = "EUR" + + const val PurposeCodeDefaultValue = "CHAR" + + } + + + /** + * [remittanceReference] and [remittanceText] are mutual exclusive, that means one of both has to be set + * but they are never set both at the same time. + * + * remittance returns the one that is set. + */ + open val remittance: String + get() = remittanceReference ?: remittanceText ?: "" // they should never be both null + + override fun toString(): String { + return "$receiverName $amount $currencyCode ${remittance}" + } +} \ No newline at end of file diff --git a/EpcQrCode/src/commonMain/kotlin/net/codinux/banking/epcqrcode/EpcQrCodeCharacterSet.kt b/EpcQrCode/src/commonMain/kotlin/net/codinux/banking/epcqrcode/EpcQrCodeCharacterSet.kt new file mode 100644 index 0000000..23d9f95 --- /dev/null +++ b/EpcQrCode/src/commonMain/kotlin/net/codinux/banking/epcqrcode/EpcQrCodeCharacterSet.kt @@ -0,0 +1,22 @@ +package net.codinux.banking.epcqrcode + + +enum class EpcQrCodeCharacterSet(val code: Int) { + + UTF_8(1), + + ISO_8895_1(2), + + ISO_8895_2(3), + + ISO_8895_4(4), + + ISO_8895_5(5), + + ISO_8895_7(6), + + ISO_8895_10(7), + + ISO_8895_15(8) + +} \ No newline at end of file diff --git a/EpcQrCode/src/commonMain/kotlin/net/codinux/banking/epcqrcode/EpcQrCodeCreator.kt b/EpcQrCode/src/commonMain/kotlin/net/codinux/banking/epcqrcode/EpcQrCodeCreator.kt new file mode 100644 index 0000000..895ed7e --- /dev/null +++ b/EpcQrCode/src/commonMain/kotlin/net/codinux/banking/epcqrcode/EpcQrCodeCreator.kt @@ -0,0 +1,65 @@ +package net.codinux.banking.epcqrcode + + +open class EpcQrCodeCreator { + +// companion object { +// val AmountNumberFormat = Decim +// } + + + open fun generate(param: CreatorParam): EpcQrCode { + return EpcQrCode( + EpcQrCode.ServiceTagDefaultValue, + EpcQrCodeVersion.Version2, + param.encoding, + EpcQrCode.FunctionDefaultValue, + param.bic, + param.receiverName, + param.iban, + EpcQrCode.CurrencyCodeDefaultValue, + param.amount, + EpcQrCode.PurposeCodeDefaultValue, + null, + param.reference, + param.noteToUser + ) + } + + open fun generateAsString(param: CreatorParam): String { + val epcQrCode = generate(param) + + val epcQrCodeBuilder = StringBuilder() + + epcQrCodeBuilder.appendLine(epcQrCode.serviceTag) + epcQrCodeBuilder.appendLine(epcQrCode.version.code) + epcQrCodeBuilder.appendLine(epcQrCode.coding.code) + epcQrCodeBuilder.appendLine(epcQrCode.function) + epcQrCodeBuilder.appendLine(mapNullable(epcQrCode.bic)) + epcQrCodeBuilder.appendLine(epcQrCode.receiverName) + epcQrCodeBuilder.appendLine(epcQrCode.iban) + epcQrCodeBuilder.appendLine(mapNullable(epcQrCode.amount?.let { (epcQrCode.currencyCode ?: EpcQrCode.CurrencyCodeDefaultValue) + convert(it) })) + epcQrCodeBuilder.appendLine(epcQrCode.purposeCode) + epcQrCodeBuilder.appendLine(mapNullable(epcQrCode.remittanceReference)) + + if (epcQrCode.remittanceText != null || epcQrCode.originatorInformation != null) { + epcQrCodeBuilder.appendLine(mapNullable(epcQrCode.remittanceText)) + } + + if (epcQrCode.originatorInformation != null) { + epcQrCodeBuilder.appendLine(epcQrCode.originatorInformation) + } + + return epcQrCodeBuilder.toString() + } + + + protected open fun convert(amount: Double): String { + return amount.toString() // TODO: ensure that it's converted to the correct format + } + + protected open fun mapNullable(value: String?): String { + return value ?: "" + } + +} \ No newline at end of file diff --git a/EpcQrCode/src/commonMain/kotlin/net/codinux/banking/epcqrcode/EpcQrCodeEncoding.kt b/EpcQrCode/src/commonMain/kotlin/net/codinux/banking/epcqrcode/EpcQrCodeEncoding.kt deleted file mode 100644 index 63e8539..0000000 --- a/EpcQrCode/src/commonMain/kotlin/net/codinux/banking/epcqrcode/EpcQrCodeEncoding.kt +++ /dev/null @@ -1,7 +0,0 @@ -package net.codinux.banking.epcqrcode - -enum class EpcQrCodeEncoding { - - Utf8 - -} \ No newline at end of file diff --git a/EpcQrCode/src/commonMain/kotlin/net/codinux/banking/epcqrcode/EpcQrCodeVersion.kt b/EpcQrCode/src/commonMain/kotlin/net/codinux/banking/epcqrcode/EpcQrCodeVersion.kt new file mode 100644 index 0000000..a1b2588 --- /dev/null +++ b/EpcQrCode/src/commonMain/kotlin/net/codinux/banking/epcqrcode/EpcQrCodeVersion.kt @@ -0,0 +1,10 @@ +package net.codinux.banking.epcqrcode + + +enum class EpcQrCodeVersion(val code: String) { + + Version1("001"), // cannot name it '1' + + Version2("002") + +} \ No newline at end of file diff --git a/EpcQrCode/src/jvmMain/kotlin/net/codinux/banking/epcqrcode/QrCodeGenerator.kt b/EpcQrCode/src/jvmMain/kotlin/net/codinux/banking/epcqrcode/QrCodeGenerator.kt index f97c02c..c0cb8cb 100644 --- a/EpcQrCode/src/jvmMain/kotlin/net/codinux/banking/epcqrcode/QrCodeGenerator.kt +++ b/EpcQrCode/src/jvmMain/kotlin/net/codinux/banking/epcqrcode/QrCodeGenerator.kt @@ -12,7 +12,7 @@ class QrCodeGenerator { fun generateQrCode(informationToEncode: String, config: EncodeToQrCodeConfig = EncodeToQrCodeConfig()): ByteArray { val hints = mutableMapOf() - hints[EncodeHintType.CHARACTER_SET] = config.encoding.name + hints[EncodeHintType.CHARACTER_SET] = map(config.encoding) val bitMatrix = QRCodeWriter().encode(informationToEncode, BarcodeFormat.QR_CODE, config.width, config.height, hints) @@ -23,4 +23,12 @@ class QrCodeGenerator { return outputStream.toByteArray() } + + private fun map(encoding: EpcQrCodeCharacterSet): String { + return when (encoding) { + EpcQrCodeCharacterSet.UTF_8 -> "UTF8" + else -> encoding.name.replace("ISO_8859", "ISO8859") + } + } + } \ No newline at end of file diff --git a/EpcQrCodeAndroidApp/src/main/java/net/codinux/banking/epcqrcode/MainActivity.kt b/EpcQrCodeAndroidApp/src/main/java/net/codinux/banking/epcqrcode/MainActivity.kt index 87e2516..7890cff 100644 --- a/EpcQrCodeAndroidApp/src/main/java/net/codinux/banking/epcqrcode/MainActivity.kt +++ b/EpcQrCodeAndroidApp/src/main/java/net/codinux/banking/epcqrcode/MainActivity.kt @@ -17,7 +17,8 @@ class MainActivity : AppCompatActivity() { txtMessage.text = MppTest().showMessage() - val imageBytes = QrCodeGenerator().generateQrCode(MppTest().getTestEpcQrCodeContent()) + val qrCodeContent = EpcQrCodeCreator().generateAsString(CreatorParam("Mahatma Gandhi", "IN00123456789876543210", null, 1234.56, "Struggle for independence")) + val imageBytes = QrCodeGenerator().generateQrCode(qrCodeContent) imgGeneratedQrCode.setImageBitmap(BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.size)) } diff --git a/EpcQrCodeJavaFxApp/src/main/kotlin/net/codinux/banking/epcqrcode/windows/main/MainWindow.kt b/EpcQrCodeJavaFxApp/src/main/kotlin/net/codinux/banking/epcqrcode/windows/main/MainWindow.kt index bb5a522..1b97ea2 100644 --- a/EpcQrCodeJavaFxApp/src/main/kotlin/net/codinux/banking/epcqrcode/windows/main/MainWindow.kt +++ b/EpcQrCodeJavaFxApp/src/main/kotlin/net/codinux/banking/epcqrcode/windows/main/MainWindow.kt @@ -4,8 +4,7 @@ import javafx.beans.property.SimpleObjectProperty import javafx.scene.image.Image import tornadofx.* import java.io.ByteArrayInputStream -import net.codinux.banking.epcqrcode.MppTest -import net.codinux.banking.epcqrcode.QrCodeGenerator +import net.codinux.banking.epcqrcode.* import org.slf4j.LoggerFactory @@ -16,9 +15,11 @@ class MainWindow : View(FX.messages["application.title"]) { } + private val qrCodeContent = EpcQrCodeCreator().generateAsString(CreatorParam("Mahatma Gandhi", "IN00123456789876543210", null, 1234.56, "Struggle for independence")) // TODO: remove again + private val qrCodeGenerator = QrCodeGenerator() - private val qrCode = SimpleObjectProperty(generateQrCode(MppTest().getTestEpcQrCodeContent())) + private val qrCode = SimpleObjectProperty(generateQrCode(qrCodeContent)) override val root = vbox {