From ea816cf668a13334932a027e99a2cd49160cbc5a Mon Sep 17 00:00:00 2001 From: Ralph Soika Date: Mon, 19 Feb 2024 14:16:14 +0100 Subject: [PATCH] sepa format for Bank Polski --- office-alexander-logistics-app/pom.xml | 9 + .../sepa/TestSEPATransform.java | 63 ++++++ .../alexanderlogistics/sepa/XSLTester.java | 92 +++++++++ reports/sepa/result_sepa01.xml | 91 +++++++++ reports/sepa/result_sepa02.xml | 91 +++++++++ reports/sepa/sepa-2.0.5-pl.imixs-report | 188 ++++++++++++++++++ reports/sepa/sepa-2.0.5-pl.xsl | 188 ++++++++++++++++++ 7 files changed, 722 insertions(+) create mode 100644 office-alexander-logistics-app/src/test/java/com/alexanderlogistics/sepa/TestSEPATransform.java create mode 100644 office-alexander-logistics-app/src/test/java/com/alexanderlogistics/sepa/XSLTester.java create mode 100644 reports/sepa/result_sepa01.xml create mode 100644 reports/sepa/result_sepa02.xml create mode 100644 reports/sepa/sepa-2.0.5-pl.imixs-report create mode 100644 reports/sepa/sepa-2.0.5-pl.xsl diff --git a/office-alexander-logistics-app/pom.xml b/office-alexander-logistics-app/pom.xml index 6a2060b..ee03740 100644 --- a/office-alexander-logistics-app/pom.xml +++ b/office-alexander-logistics-app/pom.xml @@ -126,6 +126,15 @@ + + + ${basedir}/../reports + + + ${basedir}/src/test/resources + + + maven-war-plugin diff --git a/office-alexander-logistics-app/src/test/java/com/alexanderlogistics/sepa/TestSEPATransform.java b/office-alexander-logistics-app/src/test/java/com/alexanderlogistics/sepa/TestSEPATransform.java new file mode 100644 index 0000000..d42d42a --- /dev/null +++ b/office-alexander-logistics-app/src/test/java/com/alexanderlogistics/sepa/TestSEPATransform.java @@ -0,0 +1,63 @@ +package com.alexanderlogistics.sepa; + +import java.io.IOException; +import java.util.logging.Logger; + +import org.imixs.workflow.exceptions.ModelException; +import org.imixs.workflow.exceptions.PluginException; +import org.junit.Before; +import org.junit.Test; + +import junit.framework.Assert; + +/** + * Diese Klasse testet die SEPA XSLT Transformation + * + * + * @author rsoika + */ +public class TestSEPATransform { + + final static String ENCODING = "UTF-8"; + + private static Logger logger = Logger.getLogger(TestSEPATransform.class.getName()); + + @Before + public void setup() throws PluginException, ModelException { + logger.info("setup test environment ..."); + + } + + /** + * XSL Transformation for SEPA Standard file + * + * @throws IOException + */ + @Test + public void testDefault() throws IOException { + String MODEL_PATH_XML = "sepa/beispiel-daten.xml"; + String MODEL_PATH_XSL = "sepa/sepa-2.0.5.xsl"; + try { + XSLTester.transform(MODEL_PATH_XML, MODEL_PATH_XSL, "../reports/sepa/result_sepa01.xml"); + } catch (Exception e) { + Assert.fail(); + } + } + + /** + * XSL Transformation for SEPA file for Bank Polski + * + * @throws IOException + */ + @Test + public void testBankPolski() throws IOException { + String MODEL_PATH_XML = "sepa/beispiel-daten.xml"; + String MODEL_PATH_XSL = "sepa/sepa-2.0.5-pl.xsl"; + try { + XSLTester.transform(MODEL_PATH_XML, MODEL_PATH_XSL, "../reports/sepa/result_sepa02.xml"); + } catch (Exception e) { + Assert.fail(); + } + } + +} diff --git a/office-alexander-logistics-app/src/test/java/com/alexanderlogistics/sepa/XSLTester.java b/office-alexander-logistics-app/src/test/java/com/alexanderlogistics/sepa/XSLTester.java new file mode 100644 index 0000000..6950b6c --- /dev/null +++ b/office-alexander-logistics-app/src/test/java/com/alexanderlogistics/sepa/XSLTester.java @@ -0,0 +1,92 @@ +package com.alexanderlogistics.sepa; + +import java.io.BufferedReader; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; + +import javax.xml.transform.TransformerException; + +import org.imixs.workflow.xml.XSLHandler; + +/** + * The XSLTester is used in junit tests to transform XSL/XML files + * + * Do not forget to change your pom.xml and add the following to your build + * section + * + *
+ * {@code		
+ * 
+ *   
+ *     ${basedir}/../reports
+ *   
+ *   
+ *     ${basedir}/src/test/resources
+ *   
+ * 
+ * }
+ * 
+ * + * @author rsoika + */ +public class XSLTester { + + final static String ENCODING = "UTF-8"; + + /** + * XSL Transformation + * + * @throws IOException + * @throws TransformerException + */ + public static void transform(String xmlSourcePath, String xslSourcePath, String outputPath) + throws IOException, TransformerException { + OutputStream outputStream = new FileOutputStream(outputPath); + // Use the class loader to load the XML file as a resource + ClassLoader classLoader = XSLTester.class.getClassLoader(); + InputStream xmlInputStream = classLoader.getResourceAsStream(xmlSourcePath); + InputStream xslInputStream = classLoader.getResourceAsStream(xslSourcePath); + + try { + + if (xmlInputStream == null) { + throw new RuntimeException("XML file not found: " + xmlSourcePath); + } + if (xslInputStream == null) { + throw new RuntimeException("XSL file not found: " + xslSourcePath); + } + + String xmlSource = readXml(xmlInputStream); + String xslSource = readXml(xslInputStream); + XSLHandler.transform(xmlSource, xslSource, ENCODING, outputStream); + + } finally { + if (xmlInputStream != null) + xmlInputStream.close(); + if (xslInputStream != null) + xslInputStream.close(); + if (outputStream != null) + outputStream.close(); + } + } + + /** + * read and return the XML content as a String + * + */ + private static String readXml(InputStream inputStream) { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) { + StringBuilder xmlContent = new StringBuilder(); + String line; + while ((line = reader.readLine()) != null) { + xmlContent.append(line).append("\n"); + } + return xmlContent.toString(); + } catch (IOException e) { + throw new RuntimeException("Error reading XML file", e); + } + } +} diff --git a/reports/sepa/result_sepa01.xml b/reports/sepa/result_sepa01.xml new file mode 100644 index 0000000..0cee055 --- /dev/null +++ b/reports/sepa/result_sepa01.xml @@ -0,0 +1,91 @@ + + + + + a8a5a0fa48bd49d4987dbda597c66055 + 2024-02-19T13:36:17 + 2 + 136.87 + + Muster AG + + + + a8a5a0fa48bd49d4987dbda597c66055-1 + TRF + 2 + 136.87 + + + SEPA + + + 2024-02-19 + + Muster AG + + + + DE07500400000582507042 + + + + + OOBADEFFXXX + + + SLEV + + + NOTPROVIDED + + + 86.87 + + + + XXXADEMM + + + + Supplier 1 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx E + + + + DE74555500000000028273 + + + + Invoice Example-1 + + + + + NOTPROVIDED + + + 50 + + + + XXXADEMM + + + + Supplier 2 Eyy XXXXXXXXX + + + + DE74555500000000055273 + + + + 3453540000 / 202007000175 + + + + + diff --git a/reports/sepa/result_sepa02.xml b/reports/sepa/result_sepa02.xml new file mode 100644 index 0000000..fb95693 --- /dev/null +++ b/reports/sepa/result_sepa02.xml @@ -0,0 +1,91 @@ + + + + + a8a5a0fa48bd49d4987dbda597c66055 + 2024-02-19T13:58:23 + 2 + 136.87 + + Muster AG + + + + a8a5a0fa48bd49d4987dbda597c66055-1 + TRF + 2 + 136.87 + + + SEPA + + + 2024-02-19 + + Muster AG + + + + DE07500400000582507042 + + + + + OOBADEFFXXX + + + SHAR + + + NOTPROVIDED + + + 86.87 + + + + XXXADEMM + + + + Supplier 1 xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx E + + + + DE74555500000000028273 + + + + Invoice Example-1 + + + + + NOTPROVIDED + + + 50 + + + + XXXADEMM + + + + Supplier 2 Eyy XXXXXXXXX + + + + DE74555500000000055273 + + + + 3453540000 / 202007000175 + + + + + diff --git a/reports/sepa/sepa-2.0.5-pl.imixs-report b/reports/sepa/sepa-2.0.5-pl.imixs-report new file mode 100644 index 0000000..045ce81 --- /dev/null +++ b/reports/sepa/sepa-2.0.5-pl.imixs-report @@ -0,0 +1,188 @@ +2024-01-11T14:31:52.923+01:00true2024-02-19T14:07:31.583+01:001a36c52d3-25bc-4c43-8c41-e90e2fd47432-1708348051587a36c52d3-25bc-4c43-8c41-e90e2fd474322$uniqueid$modelversion$workflowgroup$taskid$workflowsummaryinvoice.numberinvoice.dateinvoice.totalinvoice.currencycdtr.namecdtr.ibancdtr.bicdbtr.namedbtr.ibandbtr.bicpayment.typenumsequencenumberUTF-8SEPA export executed by the SepaScheduler. See the XSL definition for details. sepatype:"workitem" AND $taskid:5500 ReportEntity<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<xsl:stylesheet + xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + xmlns:xs="http://www.w3.org/2001/XMLSchema" + version="2.0"> + <xsl:strip-space elements="*" /> + <xsl:output method="xml" indent="yes" encoding="UTF-8" standalone="yes" /> + + <xsl:template match="/"> + <xsl:variable name="now" select="current-dateTime()" /> + + <Document + xmlns="urn:iso:std:iso:20022:tech:xsd:pain.001.001.07" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="urn:iso:std:iso:20022:tech:xsd:pain.001.001.07 pain.001.001.07.xsd"> + <CstmrCdtTrfInitn> + + <!-- generate header info --> + <!-- compute count of invoices --> + <xsl:variable name="count" + select="count(/data/document[starts-with(normalize-space(item[@name = '$modelversion']/value),'rechnungseingang')]/item[@name='$uniqueid']/value)" /> + <!-- compute total amount --> + <xsl:variable name="totalsum" + select="xs:decimal(sum(/data/document[starts-with(normalize-space(item[@name = '$modelversion']/value),'rechnungseingang')]/item[@name='invoice.total']/value))" /> + <!-- round to 2 digits --> + <xsl:variable name="total" + select="xs:decimal(round-half-to-even($totalsum, 2))" /> + + <!-- shortcut for the sepa export document --> + <xsl:variable name="exportWorkitem" + select="/data/document[normalize-space(item[@name = '$workflowgroup']/value) = 'SEPA-Export']" /> + + <GrpHdr> + <MsgId> + <xsl:value-of + select="replace($exportWorkitem/item[@name='$uniqueid']/value, '-', '')" /> + </MsgId> + <CreDtTm> + <xsl:value-of + select="format-dateTime($now, '[Y0001]-[M01]-[D01]T[H01]:[m01]:[s01]')" /> + </CreDtTm> + <NbOfTxs> + <xsl:value-of select="$count" /> + </NbOfTxs> + <CtrlSum> + <!-- round to 2 digits --> + <xsl:value-of select="$total" /> + </CtrlSum> + <InitgPty> + <Nm> + <xsl:value-of + select="$exportWorkitem/item[@name='dbtr.name']/value" /> + </Nm> + </InitgPty> + </GrpHdr> + + <PmtInf> + <PmtInfId> + <xsl:value-of + select="replace($exportWorkitem/item[@name='$uniqueid']/value, '-', '')" /> + <xsl:text>-1</xsl:text> + </PmtInfId> + <PmtMtd>TRF</PmtMtd> + <NbOfTxs> + <xsl:value-of select="$count" /> + </NbOfTxs> + <CtrlSum> + <!-- round to 2 digits --> + <xsl:value-of select="$total" /> + </CtrlSum> + <PmtTpInf> + <SvcLvl> + <Cd>SEPA</Cd> + </SvcLvl> + </PmtTpInf> + <ReqdExctnDt> + <xsl:value-of + select="format-dateTime($now, '[Y0001]-[M01]-[D01]')" /> + </ReqdExctnDt> + <Dbtr> + <Nm> + <xsl:value-of + select="$exportWorkitem/item[@name='dbtr.name']/value" /> + </Nm> + </Dbtr> + <DbtrAcct> + <Id> + <IBAN> + <xsl:value-of + select="replace($exportWorkitem/item[@name='dbtr.iban']/value, ' ', '')" /> + </IBAN> + </Id> + </DbtrAcct> + <DbtrAgt> + <FinInstnId> + <BIC> + <xsl:value-of + select="replace($exportWorkitem/item[@name='dbtr.bic']/value, ' ', '')" /> + </BIC> + </FinInstnId> + </DbtrAgt> + <!-- + SHAR – Charges are shared between debtor and creditor + SLEV – Charges are handled according to service level + --> + <ChrgBr>SHAR</ChrgBr> + <!-- generate CdtTrfTxInf for each invoice --> + <xsl:apply-templates + select="/data/document[starts-with(normalize-space(item[@name = '$modelversion']/value),'rechnungseingang')]" /> + </PmtInf> + </CstmrCdtTrfInitn> + </Document> + </xsl:template> + + + <!-- This template builds sepa header info --> + <xsl:template + match="/data/document[normalize-space(item[@name = '$workflowgroup']/value) = 'SEPA-Export']"> + <!-- not in use --> + </xsl:template> + + + <!-- This template builds sepa payment info for each invoice --> + <xsl:template + match="/data/document[starts-with(normalize-space(item[@name = '$modelversion']/value),'rechnungseingang')]"> + + <!-- round to 2 digits - geht nur mit sum funktion --> + <xsl:variable + name="wert1" + select="xs:decimal(sum(item[@name='invoice.total']/value))" /> + <xsl:variable name="wert2" + select="xs:decimal(round-half-to-even($wert1,2))" /> + <CdtTrfTxInf + xmlns="urn:iso:std:iso:20022:tech:xsd:pain.001.003.03"> + <PmtId> + <EndToEndId>NOTPROVIDED</EndToEndId> + </PmtId> + <Amt> + <InstdAmt> + <xsl:attribute name="Ccy"><xsl:value-of + select="item[@name='invoice.currency']/value" /></xsl:attribute> + <!-- round to 2 digits --> + <xsl:value-of select="$wert2" /> + </InstdAmt> + </Amt> + <CdtrAgt> + <FinInstnId> + <BIC> + <xsl:value-of select="replace(item[@name='cdtr.bic']/value, ' ', '')" /> + </BIC> + </FinInstnId> + </CdtrAgt> + <Cdtr> + <!-- MAX70 --> + <Nm> + <xsl:value-of select="substring(item[@name='cdtr.name']/value, 1, 70)" /> + </Nm> + </Cdtr> + <CdtrAcct> + <Id> + <IBAN> + <xsl:value-of select="replace(item[@name='cdtr.iban']/value, ' ', '')" /> + </IBAN> + </Id> + </CdtrAcct> + <RmtInf> + <!-- Max140Text --> + <Ustrd> + <xsl:choose> + <xsl:when test="string-length(item[@name='numsequencenumber']/value) > 0"> + <!-- neues format buchungsnummer / rechn.nr --> + <xsl:value-of + select="item[@name='numsequencenumber']/value" /><xsl:text> / </xsl:text><xsl:value-of + select="item[@name='invoice.number']/value" /> + </xsl:when> + <xsl:otherwise> + <!-- fallback --> + <xsl:value-of + select="substring(item[@name='$workflowsummary']/value, 1, 140)" /> + </xsl:otherwise> + </xsl:choose> + </Ustrd> + </RmtInf> + </CdtTrfTxInf> + + </xsl:template> + +</xsl:stylesheet>/office-alexander-logistics/reports/sepa/sepa-2.0.5.xsl \ No newline at end of file diff --git a/reports/sepa/sepa-2.0.5-pl.xsl b/reports/sepa/sepa-2.0.5-pl.xsl new file mode 100644 index 0000000..3d1bd17 --- /dev/null +++ b/reports/sepa/sepa-2.0.5-pl.xsl @@ -0,0 +1,188 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + -1 + + TRF + + + + + + + + + + SEPA + + + + + + + + + + + + + + + + + + + + + + + + + + SHAR + + + + + + + + + + + + + + + + + + + + + + + NOTPROVIDED + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + / + + + + + + + + + + + + + \ No newline at end of file