diff --git a/History.md b/History.md index 686242c8..a82956ee 100644 --- a/History.md +++ b/History.md @@ -14,6 +14,8 @@ done - 2.1 now default - pushprovider +- new xrechnung profile +- german bank account numbers can no longer be specified (dropped in favor of IBAN and BIC) - integrates validator - validator now additionally supports xrechnung - integrates mustangserver diff --git a/Mustang-CLI/src/main/java/org/mustangproject/commandline/Main.java b/Mustang-CLI/src/main/java/org/mustangproject/commandline/Main.java index e2b24022..f524fb51 100755 --- a/Mustang-CLI/src/main/java/org/mustangproject/commandline/Main.java +++ b/Mustang-CLI/src/main/java/org/mustangproject/commandline/Main.java @@ -112,7 +112,7 @@ public class Main { + "\t\t[--format ]: enable factur-x or ZUGFeRD\r\n" + "\t\t[--version <1|2>]: set ZUGFeRD version\r\n" + "\t\t[--profile <...>]: set ZUGFeRD profile\r\n" + "\t\t\tFor ZUGFeRD v1: ASIC, OMFORT or XTENDED\r\n" - + "\t\t\tFor ZUGFeRD v2: INIMUM, BASIC L, ASIC, IUS, N16931, ETENDED\r\n"); + + "\t\t\tFor ZUGFeRD v2: INIMUM, BASIC L, ASIC, IUS, N16931, EXENDED, Rechnung\r\n"); } /** @@ -459,12 +459,12 @@ public class Main { if (outName == null) { outName = getFilenameFromUser("Ouput PDF", "invoice.ZUGFeRD.pdf", "pdf", false, true); } else { - System.out.println("Ouput PDF set to " + outName); + System.out.println("Output PDF set to " + outName); } if (format == null) { try { - format = getStringFromUser("Format (fx=Factur-X, zf=ZUGFeRD,)", "zf", "fx|zf"); + format = getStringFromUser("Format (fx=Factur-X, zf=ZUGFeRD)", "zf", "fx|zf"); } catch (Exception e) { Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, e); } @@ -474,7 +474,7 @@ public class Main { if (zfVersion == null) { try { - zfVersion = getStringFromUser("Version (1 or 2)", "1", "1|2"); + zfVersion = getStringFromUser("Version (1 or 2)", Integer.toString(ZUGFeRDExporter.DefaultZUGFeRDVersion), "1|2"); } catch (Exception e) { Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, e); } @@ -489,8 +489,8 @@ public class Main { zfProfile = getStringFromUser("Profile b)asic, c)omfort or e)xtended", "e", "B|b|C|c|E|e"); } else { zfProfile = getStringFromUser( - "Profile [M]INIMUM, BASIC [W]L, [B]ASIC,\n" + "[C]IUS, [E]N16931, E[X]TENDED", "E", - "M|m|W|w|B|b|C|c|E|e|X|x|"); + "Profile [M]INIMUM, BASIC [W]L, [B]ASIC,\n" + "[C]IUS, [E]N16931, EX[T]ENDED or [X]RECHNUNG", "E", + "M|m|W|w|B|b|C|c|E|e|T|t|X|x|"); } } catch (Exception e) { Logger.getLogger(Main.class.getName()).log(Level.SEVERE, null, e); @@ -531,8 +531,10 @@ public class Main { zfConformanceLevelProfile = ZUGFeRDConformanceLevel.CIUS; } else if (zfProfile.equals("e")) { zfConformanceLevelProfile = ZUGFeRDConformanceLevel.EN16931; - } else if (zfProfile.equals("x")) { + } else if (zfProfile.equals("t")) { zfConformanceLevelProfile = ZUGFeRDConformanceLevel.EXTENDED; + } else if (zfProfile.equals("x")) { + zfConformanceLevelProfile = ZUGFeRDConformanceLevel.XRECHNUNG; } else { throw new Exception(String.format("Unknown ZUGFeRD profile '%s'", zfProfile)); } diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDConformanceLevel.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDConformanceLevel.java index d59b2f40..b4d9f186 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDConformanceLevel.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDConformanceLevel.java @@ -19,5 +19,5 @@ package org.mustangproject.ZUGFeRD; public enum ZUGFeRDConformanceLevel { - BASIC, COMFORT, EXTENDED, EN16931/*=Comfort*/, MINIMUM, BASICWL /*basic without lines, less than basic*/, CIUS + BASIC, COMFORT, EXTENDED, EN16931/*=Comfort*/, MINIMUM, BASICWL /*basic without lines, less than basic*/, CIUS, XRECHNUNG } diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java index 3e59bbe1..d0712407 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java @@ -287,26 +287,6 @@ public class ZUGFeRDImporter { } - /** - * @return the sender's bank's BLZ code - * @deprecated use BIC and IBAN instead of BLZ and KTO - */ - @Deprecated - public String getBLZ() { - return extractString("//PayeeSpecifiedCreditorFinancialInstitution/GermanBankleitzahlID"); - } - - - /** - * @return the sender's account number - * @deprecated use BIC and IBAN instead of BLZ and KTO - */ - @Deprecated - public String getKTO() { - return extractString("//PayeePartyCreditorFinancialAccount/ProprietaryID"); - } - - /** * @return the sender's bank's BIC code */ diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterCustomXMLTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterCustomXMLTest.java index ff87ab09..d44fd848 100644 --- a/library/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterCustomXMLTest.java +++ b/library/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterCustomXMLTest.java @@ -275,10 +275,8 @@ public class MustangReaderWriterCustomXMLTest extends TestCase { // Reading ZUGFeRD assertEquals(zi.getAmount(), "571.04"); - assertEquals(zi.getBLZ(), "41441604"); assertEquals(zi.getBIC(), "COBADEFFXXX"); assertEquals(zi.getIBAN(), "DE88 2008 0000 0970 3757 00"); - assertEquals(zi.getKTO(), "44421800"); assertEquals(zi.getHolder(), "Bei Spiel GmbH"); assertEquals(zi.getForeignReference(), "RE-20171118/506"); } @@ -448,7 +446,7 @@ public class MustangReaderWriterCustomXMLTest extends TestCase { zea1.close(); String pdfContent = baos.toString("UTF-8"); assertFalse(pdfContent.indexOf("(via mustangproject.org") == -1); - assertFalse(pdfContent.indexOf("BASIC") == -1); + assertFalse(pdfContent.indexOf("BASIC") == -1); } catch (IOException e) { e.printStackTrace(); @@ -460,9 +458,7 @@ public class MustangReaderWriterCustomXMLTest extends TestCase { // Reading ZUGFeRD assertEquals(zi.getAmount(), "571.04"); assertEquals(zi.getBIC(), "COBADEFFXXX"); - assertEquals(zi.getBLZ(), "41441604"); assertEquals(zi.getIBAN(), "DE88 2008 0000 0970 3757 00"); - assertEquals(zi.getKTO(), "44421800"); assertEquals(zi.getHolder(), "Bei Spiel GmbH"); assertEquals(zi.getForeignReference(), "RE-20170509/505"); } diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterEdgeTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterEdgeTest.java index 3f1ebfc3..e4ea9b17 100644 --- a/library/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterEdgeTest.java +++ b/library/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterEdgeTest.java @@ -181,9 +181,7 @@ public class MustangReaderWriterEdgeTest extends MustangReaderTestCase { // Reading ZUGFeRD assertEquals(zi.getAmount(), "571.04"); assertEquals(zi.getBIC(), getTradeSettlementPayment()[0].getOwnBIC()); - assertEquals(zi.getBLZ(), getTradeSettlementPayment()[0].getOwnBLZ()); assertEquals(zi.getIBAN(), getTradeSettlementPayment()[0].getOwnIBAN()); - assertEquals(zi.getKTO(), getTradeSettlementPayment()[0].getOwnKto()); assertEquals(zi.getHolder(), getOwnOrganisationName()); assertEquals(zi.getDueDate(), "20170530"); assertEquals(zi.getForeignReference(), getNumber()); @@ -223,11 +221,9 @@ public class MustangReaderWriterEdgeTest extends MustangReaderTestCase { ZUGFeRDImporter zi = new ZUGFeRDImporter(TARGET_PDF); // Reading ZUGFeRD - assertEquals(zi.getAmount(), "571.04"); - assertEquals(zi.getBIC(), getTradeSettlementPayment()[0].getOwnBIC()); - assertEquals(zi.getBLZ(), getTradeSettlementPayment()[0].getOwnBLZ()); - assertEquals(zi.getIBAN(), getTradeSettlementPayment()[0].getOwnIBAN()); - assertEquals(zi.getKTO(), getTradeSettlementPayment()[0].getOwnKto()); + assertEquals("571.04", zi.getAmount()); + assertEquals(getTradeSettlementPayment()[0].getOwnBIC(), zi.getBIC()); + assertEquals(getTradeSettlementPayment()[0].getOwnIBAN(), zi.getIBAN()); assertEquals(zi.getHolder(), getOwnOrganisationName()); assertEquals(zi.getForeignReference(), getNumber()); try { diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterTest.java index 0efc5a93..33ded416 100644 --- a/library/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterTest.java +++ b/library/src/test/java/org/mustangproject/ZUGFeRD/MustangReaderWriterTest.java @@ -196,10 +196,8 @@ public class MustangReaderWriterTest extends MustangReaderTestCase { // Reading ZUGFeRD assertEquals(zi.getAmount(), "571.04"); - assertEquals(zi.getBLZ(), getTradeSettlementPayment()[0].getOwnBLZ()); assertEquals(zi.getBIC(), getTradeSettlementPayment()[0].getOwnBIC()); assertEquals(zi.getIBAN(),getTradeSettlementPayment()[0].getOwnIBAN()); - assertEquals(zi.getKTO(), getTradeSettlementPayment()[0].getOwnKto()); assertEquals(zi.getHolder(), getOwnOrganisationName()); assertEquals(zi.getForeignReference(), "RE-20170509/505"); assertEquals(zi.getBankName(), "Commerzbank"); @@ -388,7 +386,6 @@ public class MustangReaderWriterTest extends MustangReaderTestCase { assertEquals(zi.getBIC(), getTradeSettlementPayment()[0].getOwnBIC()); assertEquals(zi.getReference(), getReferenceNumber()); assertEquals(zi.getIBAN(), getTradeSettlementPayment()[0].getOwnIBAN()); - assertEquals(zi.getKTO(), getTradeSettlementPayment()[0].getOwnKto()); assertEquals(zi.getHolder(), getOwnOrganisationName()); assertEquals(zi.getForeignReference(), getNumber()); } @@ -457,7 +454,6 @@ public class MustangReaderWriterTest extends MustangReaderTestCase { assertEquals(zi.getAmount(), "571.04"); assertEquals(zi.getBIC(), getTradeSettlementPayment()[0].getOwnBIC()); assertEquals(zi.getIBAN(), getTradeSettlementPayment()[0].getOwnIBAN()); - assertEquals(zi.getKTO(), getTradeSettlementPayment()[0].getOwnKto()); assertEquals(zi.getHolder(), getOwnOrganisationName()); assertEquals(zi.getForeignReference(), getNumber()); } diff --git a/validator/src/main/java/org/mustangproject/validator/PDFValidator.java b/validator/src/main/java/org/mustangproject/validator/PDFValidator.java index 565efd48..3a276c10 100644 --- a/validator/src/main/java/org/mustangproject/validator/PDFValidator.java +++ b/validator/src/main/java/org/mustangproject/validator/PDFValidator.java @@ -179,7 +179,7 @@ public class PDFValidator extends Validator { boolean conformanceLevelValid=false; for (int i = 0; i < nodes.getLength(); i++) { - String[] valueArray = { "BASIC WL", "BASIC", "MINIMUM", "EN 16931", "COMFORT", "CIUS", "EXTENDED" }; + String[] valueArray = { "BASIC WL", "BASIC", "MINIMUM", "EN 16931", "COMFORT", "CIUS", "EXTENDED", "XRECHNUNG" }; if (stringArrayContains(valueArray, nodes.item(i).getTextContent())) { conformanceLevelValid=true; } diff --git a/validator/src/main/java/org/mustangproject/validator/XMLValidator.java b/validator/src/main/java/org/mustangproject/validator/XMLValidator.java index 35e0dc98..550a9476 100644 --- a/validator/src/main/java/org/mustangproject/validator/XMLValidator.java +++ b/validator/src/main/java/org/mustangproject/validator/XMLValidator.java @@ -7,6 +7,7 @@ import java.nio.file.Paths; import java.util.Calendar; import java.util.List; +import javax.print.attribute.standard.Severity; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.*; @@ -105,7 +106,7 @@ public class XMLValidator extends Validator { // it takes 30-40min, try { - + ESeverity XrechnungSeverity=ESeverity.notice; /*** * private static final String VALID_SCHEMATRON = "test-sch/valid01.sch"; * private static final String VALID_XMLINSTANCE = "test-xml/valid01.xml"; @@ -153,9 +154,10 @@ public class XMLValidator extends Validator { boolean isBasic = false; boolean isBasicWithoutLines = false; boolean isEN16931 = false; - boolean isExtended = false; - String xsltFilename = null; - // urn:ferd:CrossIndustryDocument:invoice:1p0:extended, + boolean isExtended = false; + boolean isXRechnung = false; + String xsltFilename = null; + // urn:ferd:CrossIndustryDocument:invoice:1p0:extended, // urn:ferd:CrossIndustryDocument:invoice:1p0:comfort, // urn:ferd:CrossIndustryDocument:invoice:1p0:basic, @@ -173,8 +175,10 @@ public class XMLValidator extends Validator { isEN16931 = matchesURI(context.getProfile(), "urn:cen.eu:en16931:2017:compliant:factur-x.eu:1p0:en16931") || matchesURI(context.getProfile(), "urn:cen.eu:en16931:2017"); - isExtended = context.getProfile().contains("extended"); - if (isExtended) { + isExtended = context.getProfile().contains("extended"); + isXRechnung = context.getProfile().contains("xrechnung"); + + if ((isExtended)||(isXRechnung)) { isEN16931 = false;// the uri for extended is urn:cen.eu:en16931:2017#conformant#urn:zugferd.de:2p0:extended and thus contains en16931... } if (isMiniumum) { @@ -194,10 +198,15 @@ public class XMLValidator extends Validator { validateSchema(zfXML.getBytes(StandardCharsets.UTF_8), "zf2/EN16931/FACTUR-X_EN16931.xsd", 18, EPart.fx); xsltFilename = "/xslt/ZF_211/FACTUR-X_EN16931.xslt"; } else if (isExtended) { - LOGGER.debug("is EXTENDED"); - validateSchema(zfXML.getBytes(StandardCharsets.UTF_8), "zf2/EXTENDED/FACTUR-X_EXTENDED.xsd", 18, EPart.fx); - xsltFilename = "/xslt/ZF_211/FACTUR-X_EXTENDED.xslt"; - } /* + LOGGER.debug("is EXTENDED"); + validateSchema(zfXML.getBytes(StandardCharsets.UTF_8), "zf2/EXTENDED/FACTUR-X_EXTENDED.xsd", 18, EPart.fx); + xsltFilename = "/xslt/ZF_211/FACTUR-X_EXTENDED.xslt"; + } else if (isXRechnung) { + LOGGER.debug("is XRechnung"); + validateSchema(zfXML.getBytes(StandardCharsets.UTF_8), "zf2/EXTENDED/FACTUR-X_EXTENDED.xsd", 18, EPart.fx); + xsltFilename = "/xslt/ZF_211/FACTUR-X_EN16931.xslt"; + XrechnungSeverity=ESeverity.error; + } /* * ISchematronResource aResSCH = SchematronResourceXSLT.fromFile(new File( * "/Users/jstaerk/workspace/ZUV/src/main/resources/ZUGFeRDSchematronStylesheet.xsl" * )); @@ -255,7 +264,7 @@ public class XMLValidator extends Validator { //additionally validate against CEN validateSchematron(zfXML, "/xslt/cii16931schematron/EN16931-CII-validation.xslt", 24, ESeverity.error); - validateXR(zfXML); + validateXR(zfXML, XrechnungSeverity); } @@ -280,9 +289,9 @@ public class XMLValidator extends Validator { } - public void validateXR(String xml) throws IrrecoverableValidationError { + public void validateXR(String xml, ESeverity errorImpact) throws IrrecoverableValidationError { - validateSchematron(xml, "/xslt/XR/XRechnung-CII-validation.xslt",27, ESeverity.notice); + validateSchematron(xml, "/xslt/XR/XRechnung-CII-validation.xslt",27, errorImpact); } diff --git a/validator/src/main/resources/xrechnung.invalid.pdf b/validator/src/main/resources/xrechnung.invalid.pdf new file mode 100644 index 00000000..23df88a9 Binary files /dev/null and b/validator/src/main/resources/xrechnung.invalid.pdf differ diff --git a/validator/src/main/resources/xrechnung.pdf b/validator/src/main/resources/xrechnung.pdf new file mode 100644 index 00000000..095f2019 Binary files /dev/null and b/validator/src/main/resources/xrechnung.pdf differ