From 66bb3c4341ea1e9ca13daa287571962a88b4ccc4 Mon Sep 17 00:00:00 2001 From: Kemal Taskin Date: Wed, 6 Nov 2024 11:06:23 +0100 Subject: [PATCH 01/15] Improve toFOP method: Parameterize the input stream and the EStandard input --- .../mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java index b2e47e3c..64e14fc3 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDVisualizer.java @@ -249,6 +249,12 @@ public class ZUGFeRDVisualizer { EStandard theStandard = findOutStandardFromRootNode(fis); fis = new FileInputStream(xmlFilename);//rewind :-( + return toFOP(fis, theStandard); + } + + protected String toFOP(InputStream is, EStandard theStandard) + throws FileNotFoundException, TransformerException { + try { if (mXsltPDFTemplate == null) { mXsltPDFTemplate = mFactory.newTemplates( @@ -263,11 +269,11 @@ public class ZUGFeRDVisualizer { //zf2 or fx if (theStandard == EStandard.facturx) { - applyZF2XSLT(fis, iaos); + applyZF2XSLT(is, iaos); } else if (theStandard == EStandard.ubl) { - applyUBL2XSLT(fis, iaos); + applyUBL2XSLT(is, iaos); } else if (theStandard == EStandard.ubl_creditnote) { - applyUBLCreditNote2XSLT(fis, iaos); + applyUBLCreditNote2XSLT(is, iaos); } From d75a43d4e144c58853e5117f27ec799d856ab103 Mon Sep 17 00:00:00 2001 From: melo0187 <2528018+melo0187@users.noreply.github.com> Date: Wed, 6 Nov 2024 11:52:52 +0100 Subject: [PATCH 02/15] Add test verifying #546 has been fixed --- .../validator/XMLValidatorTest.java | 30 ++++ .../CII_XRechnung_with_Peppol_violation.xml | 144 ++++++++++++++++++ 2 files changed, 174 insertions(+) create mode 100644 validator/src/test/resources/CII_XRechnung_with_Peppol_violation.xml diff --git a/validator/src/test/java/org/mustangproject/validator/XMLValidatorTest.java b/validator/src/test/java/org/mustangproject/validator/XMLValidatorTest.java index 8b6022f5..0aeaca89 100644 --- a/validator/src/test/java/org/mustangproject/validator/XMLValidatorTest.java +++ b/validator/src/test/java/org/mustangproject/validator/XMLValidatorTest.java @@ -204,6 +204,36 @@ public class XMLValidatorTest extends ResourceCase { } + public void testXRCIIPeppolFailureValidation() { + final ValidationContext ctx = new ValidationContext(null); + final XMLValidator xv = new XMLValidator(ctx); + final XPathEngine xpath = new JAXPXPathEngine(); + + // GIVEN XRechnung CII with Peppol rule violation + File file = getResourceAsFile("CII_XRechnung_with_Peppol_violation.xml"); + + boolean noExceptions = true; + try { + xv.setFilename(file.getAbsolutePath()); + + // WHEN validated + xv.validate(); + + Source source = Input.fromString("" + xv.getXMLResult() + "").build(); + + // THEN validation returns only warning message + boolean onlyWarnings = Boolean.parseBoolean(xpath.evaluate("not(//messages/*[not(self::warning)])", source)); + assertTrue(onlyWarnings); + + // THEN validation returns summary status valid + String status = xpath.evaluate("/validation/summary/@status", source); + assertEquals("valid", status); + } catch (IrrecoverableValidationError e) { + noExceptions = false; + } + assertTrue(noExceptions); + } + public void testXRValidation() { final ValidationContext ctx = new ValidationContext(null); final XMLValidator xv = new XMLValidator(ctx); diff --git a/validator/src/test/resources/CII_XRechnung_with_Peppol_violation.xml b/validator/src/test/resources/CII_XRechnung_with_Peppol_violation.xml new file mode 100644 index 00000000..8e023db5 --- /dev/null +++ b/validator/src/test/resources/CII_XRechnung_with_Peppol_violation.xml @@ -0,0 +1,144 @@ + + + + + urn:fdc:peppol.eu:2017:poacc:billing:01:1.0 + + + urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0 + + + + RE0021 + 380 + + 20241002 + + + Rechnung + AFM + + + Unsere Lieferungen/Leistungen stellen wir Ihnen wie folgt in Rechnung. + AAI + + + Vielen Dank für die gute Zusammenarbeit. + SUR + + + + + + 1 + + + 1 + + + + 140.0000 + 1.0000 + + + + 1.0000 + + + + VAT + S + 19.00 + + + 140.00 + + + + + 992-90009-96 + + 231132 + Max Muster + + Max Muster + + 0192435345 + + + muster@example.com + + + + 12345 + Straße + Stadt + DE + + + muster@example.com + + + DE99999/99999 + + + DE325845615 + + + + KUnde + + 12345 + Straße + Stadt + DE + + + + + + + 20241002 + + + + + RE0021 + EUR + + 1 + Überweisung + + DE50110101002129646573 + Max Muster + + + BEVODEBBXXX + + + + 26.60 + VAT + 140.00 + S + 19.00 + + + Zahlbar sofort, rein netto + + 20241002 + + + + 140.00 + 0.00 + 0.00 + 140.00 + 26.60 + 166.60 + 0.00 + 166.60 + + + + From 747b8ca6ba88ff0f87f6179a0e0989369937efc9 Mon Sep 17 00:00:00 2001 From: jstaerk Date: Mon, 11 Nov 2024 16:19:38 +0100 Subject: [PATCH 03/15] activated the test --- .../org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java index db7256cf..5cf44d86 100644 --- a/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java +++ b/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java @@ -416,7 +416,7 @@ this would test if for all elements/attributes /* Seller contact point +41 345 654455 - seller@contact.de);* + seller@contact.de);*/ } catch (XPathExpressionException | ParseException e) { hasExceptions = true; } catch (JsonProcessingException e) { @@ -428,6 +428,6 @@ this would test if for all elements/attributes assertEquals(new BigDecimal("205.00"), tc.getGrandTotal()); } -*/ + } From a7c9e221cb54d019998fd30192ef1d845345932f Mon Sep 17 00:00:00 2001 From: Bharti Date: Wed, 13 Nov 2024 10:44:28 +0100 Subject: [PATCH 04/15] UBL stuff --- .../java/org/mustangproject/TradeParty.java | 13 + .../ZUGFeRD/ZUGFeRDInvoiceImporter.java | 6 +- .../ZUGFeRD/ZF2ImporterTest.java | 431 ------------------ .../ZUGFeRD/ZF2ZInvoiceImporterTest.java | 8 +- 4 files changed, 22 insertions(+), 436 deletions(-) delete mode 100644 library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ImporterTest.java diff --git a/library/src/main/java/org/mustangproject/TradeParty.java b/library/src/main/java/org/mustangproject/TradeParty.java index a5408146..5f14b322 100644 --- a/library/src/main/java/org/mustangproject/TradeParty.java +++ b/library/src/main/java/org/mustangproject/TradeParty.java @@ -90,6 +90,19 @@ public class TradeParty implements IZUGFeRDExportableTradeParty { } } } + if (currentTopElementName.equals("PartyTaxScheme")) { + + NodeList partyTaxScheme = party.item(partyIndex).getChildNodes(); + for (int partyTaxSchemeIndex = 0; partyTaxSchemeIndex < partyTaxScheme.getLength(); partyTaxSchemeIndex++) { + if (partyTaxScheme.item(partyTaxSchemeIndex).getLocalName() != null) { + + if (partyTaxScheme.item(partyTaxSchemeIndex).getLocalName().equals("CompanyID")) { + setTaxID(partyTaxScheme.item(partyTaxSchemeIndex).getTextContent()); + } + + } + } + } // UBL only: formally it can have a name as well but BT27 party name *should* be stored in // so overwrite if one exists diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java index 901f1b96..5c9ee429 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java @@ -440,7 +440,8 @@ public class ZUGFeRDInvoiceImporter { } - String currency = extractString("//*[local-name()=\"ApplicableHeaderTradeSettlement\"]/*[local-name()=\"InvoiceCurrencyCode\"]|*[local-name()=\"DocumentCurrencyCode\"]"); + + String currency = extractString("//*[local-name()=\"ApplicableHeaderTradeSettlement\"]/*[local-name()=\"InvoiceCurrencyCode\"]|//*[local-name()=\"DocumentCurrencyCode\"]") ; zpp.setCurrency(currency); xpr = xpath.compile("//*[local-name()=\"ApplicableHeaderTradeSettlement\"]|//*[local-name()=\"ApplicableSupplyChainTradeSettlement\"]"); @@ -578,6 +579,9 @@ public class ZUGFeRDInvoiceImporter { if (buyerOrderIssuerAssignedID != null) { zpp.setBuyerOrderReferencedDocumentID(buyerOrderIssuerAssignedID); } + else { + zpp.setBuyerOrderReferencedDocumentID(extractString("//*[local-name()=\"OrderReference\"]/*[local-name()=\"ID\"]")); + } if (sellerOrderIssuerAssignedID != null) { zpp.setSellerOrderReferencedDocumentID(sellerOrderIssuerAssignedID); } diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ImporterTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ImporterTest.java deleted file mode 100644 index 08fddcad..00000000 --- a/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ImporterTest.java +++ /dev/null @@ -1,431 +0,0 @@ - -/** - * ********************************************************************* - *

- * Copyright 2019 Jochen Staerk - *

- * Use is subject to license terms. - *

- * Licensed under the Apache License, Version 2.0 (the "License"); you may not - * use this file except in compliance with the License. You may obtain a copy - * of the License at http://www.apache.org/licenses/LICENSE-2.0. - *

- * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - *

- * See the License for the specific language governing permissions and - * limitations under the License. - *

- * ********************************************************************** - */ -package org.mustangproject.ZUGFeRD; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import org.mustangproject.*; - -import javax.xml.xpath.XPathExpressionException; -import java.io.*; -import java.math.BigDecimal; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Paths; -import java.text.ParseException; -import java.text.SimpleDateFormat; -import java.util.Arrays; -import java.util.Date; - - -/*** - * Classname ZF2ZInvoiceImporterTest is alphabetical behind the tests which will create the file - * used for this import, testout-ZF2New.pdf - */ -public class ZF2ZInvoiceImporterTest extends ResourceCase { - - - public void testInvoiceImport() { - - ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter("./target/testout-ZF2new.pdf"); - - boolean hasExceptions = false; - Invoice invoice = null; - try { - invoice = zii.extractInvoice(); - } catch (XPathExpressionException | ParseException e) { - hasExceptions = true; - } - assertFalse(hasExceptions); - // Reading ZUGFeRD - assertEquals("Bei Spiel GmbH", invoice.getOwnOrganisationName()); - assertEquals(3, invoice.getZFItems().length); - assertEquals("400.0000", invoice.getZFItems()[1].getQuantity().toString()); - - assertEquals("AB321", invoice.getReferenceNumber()); - assertEquals("160.0000", invoice.getZFItems()[0].getPrice().toString()); - assertEquals("Heiße Luft pro Liter", invoice.getZFItems()[2].getProduct().getName()); - assertEquals("LTR", invoice.getZFItems()[2].getProduct().getUnit()); - assertEquals("7.00", invoice.getZFItems()[0].getProduct().getVATPercent().toString()); - assertEquals("RE-20170509/505", invoice.getNumber()); - - SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); - assertEquals("2017-05-09", sdf.format(invoice.getIssueDate())); - assertEquals("2017-05-07", sdf.format(invoice.getDeliveryDate())); - assertEquals("2017-05-30", sdf.format(invoice.getDueDate())); - - assertEquals("Bahnstr. 42", invoice.getRecipient().getStreet()); - assertEquals("Hinterhaus", invoice.getRecipient().getAdditionalAddress()); - assertEquals("Zweiter Stock", invoice.getRecipient().getAdditionalAddressExtension()); - assertEquals("88802", invoice.getRecipient().getZIP()); - assertEquals("DE", invoice.getRecipient().getCountry()); - assertEquals("Spielkreis", invoice.getRecipient().getLocation()); - - assertEquals("Ecke 12", invoice.getSender().getStreet()); - assertEquals("12345", invoice.getSender().getZIP()); - assertEquals("DE", invoice.getSender().getCountry()); - assertEquals("Stadthausen", invoice.getSender().getLocation()); - - TransactionCalculator tc = new TransactionCalculator(invoice); - assertEquals(new BigDecimal("571.04"), tc.getGrandTotal()); - - - // name street location zip country, contact name phone email, total amount - - } - - public void testInvoiceImportUBL() { - - - boolean hasExceptions = false; - - ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter(); - File expectedResult = getResourceAsFile("testout-ZF2new.ubl.xml"); - - Invoice invoice = null; - try { - String xml = new String(Files.readAllBytes(expectedResult.toPath()), StandardCharsets.UTF_8).replace("\r", "").replace("\n", ""); - - zii.fromXML(xml); - - invoice = zii.extractInvoice(); - } catch (XPathExpressionException | ParseException | IOException e) { - hasExceptions = true; - } - assertFalse(hasExceptions); - // Reading ZUGFeRD - assertEquals("Bei Spiel GmbH", invoice.getOwnOrganisationName()); - assertEquals(3, invoice.getZFItems().length); - assertEquals("400", invoice.getZFItems()[1].getQuantity().toString()); - - assertEquals("AB321", invoice.getReferenceNumber()); - assertEquals("160", invoice.getZFItems()[0].getPrice().toString()); - assertEquals("Heiße Luft pro Liter", invoice.getZFItems()[2].getProduct().getName()); - assertEquals("LTR", invoice.getZFItems()[2].getProduct().getUnit()); - assertEquals("7", invoice.getZFItems()[0].getProduct().getVATPercent().toString()); - assertEquals("RE-20170509/505", invoice.getNumber()); - - SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); - assertEquals("2017-05-09", sdf.format(invoice.getIssueDate())); - assertEquals("2017-05-07", sdf.format(invoice.getDeliveryDate())); - assertEquals("2017-05-30", sdf.format(invoice.getDueDate())); - - assertEquals("Bahnstr. 42", invoice.getRecipient().getStreet()); - assertEquals("Hinterhaus", invoice.getRecipient().getAdditionalAddress()); - assertEquals("Zweiter Stock", invoice.getRecipient().getAdditionalAddressExtension()); - assertEquals("88802", invoice.getRecipient().getZIP()); - assertEquals("DE", invoice.getRecipient().getCountry()); - assertEquals("Spielkreis", invoice.getRecipient().getLocation()); - - assertEquals("Ecke 12", invoice.getSender().getStreet()); - assertEquals("12345", invoice.getSender().getZIP()); - assertEquals("DE", invoice.getSender().getCountry()); - assertEquals("Stadthausen", invoice.getSender().getLocation()); - - assertTrue(invoice.getPayee() != null); - assertEquals("VR Factoring GmbH", invoice.getPayee().getName()); - - TransactionCalculator tc = new TransactionCalculator(invoice); - assertEquals(new BigDecimal("571.04"), tc.getGrandTotal()); - - - // name street location zip country, contact name phone email, total amount - - } - - public void testEdgeInvoiceImport() { - - ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter("./target/testout-ZF2PushEdge.pdf"); - - boolean hasExceptions = false; - Invoice invoice = null; - try { - invoice = zii.extractInvoice(); - } catch (XPathExpressionException | ParseException e) { - hasExceptions = true; - } - assertFalse(hasExceptions); - // Reading ZUGFeRD - assertEquals("4711", invoice.getZFItems()[0].getProduct().getSellerAssignedID()); - assertEquals("9384", invoice.getSellerOrderReferencedDocumentID()); - assertEquals("sender@test.org", invoice.getSender().getEmail()); - assertEquals("recipient@test.org", invoice.getRecipient().getEmail()); - assertEquals("28934", invoice.getBuyerOrderReferencedDocumentID()); - - } - - - public void testZF1Import() { - - ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter("./target/testout-MustangGnuaccountingBeispielRE-20171118_506zf1.pdf"); - - boolean hasExceptions = false; - Invoice invoice = null; - try { - invoice = zii.extractInvoice(); - } catch (XPathExpressionException | ParseException e) { - hasExceptions = true; - } - assertFalse(hasExceptions); - // Reading ZUGFeRD - assertEquals("Bei Spiel GmbH", invoice.getOwnOrganisationName()); - assertEquals(3, invoice.getZFItems().length); - assertEquals("400.0000", invoice.getZFItems()[1].getQuantity().toString()); - - assertEquals("160.0000", invoice.getZFItems()[0].getPrice().toString()); - assertEquals("Hot air „heiße Luft“ (litres)", invoice.getZFItems()[2].getProduct().getName()); - assertEquals("LTR", invoice.getZFItems()[2].getProduct().getUnit()); - assertEquals("7.00", invoice.getZFItems()[0].getProduct().getVATPercent().toString()); - assertEquals("RE-20190610/507", invoice.getNumber()); - - SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); - assertEquals("2019-06-10", sdf.format(invoice.getIssueDate())); - assertEquals("2019-07-01", sdf.format(invoice.getDueDate())); - - assertEquals("street", invoice.getRecipient().getStreet()); - assertEquals("zip", invoice.getRecipient().getZIP()); - assertEquals("DE", invoice.getRecipient().getCountry()); - assertEquals("city", invoice.getRecipient().getLocation()); - - assertEquals("street", invoice.getSender().getStreet()); - assertEquals("zip", invoice.getSender().getZIP()); - assertEquals("DE", invoice.getSender().getCountry()); - assertEquals("city", invoice.getSender().getLocation()); - - TransactionCalculator tc = new TransactionCalculator(invoice); - assertEquals(new BigDecimal("571.04"), tc.getGrandTotal()); - - - // name street location zip country, contact name phone email, total amount - - - } - - public void testItemAllowancesChargesImport() { - - ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter("./target/testout-ZF2PushItemChargesAllowances.pdf"); - - boolean hasExceptions = false; - Invoice invoice = null; - try { - invoice = zii.extractInvoice(); - } catch (XPathExpressionException | ParseException e) { - hasExceptions = true; - } - assertFalse(hasExceptions); - TransactionCalculator tc = new TransactionCalculator(invoice); - assertEquals(new BigDecimal("18.33"), tc.getGrandTotal()); - } - - public void testBasisQuantityImport() { - - ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter("./target/testout-ZF2newEdge.pdf"); - - boolean hasExceptions = false; - Invoice invoice = null; - try { - invoice = zii.extractInvoice(); - } catch (XPathExpressionException | ParseException e) { - hasExceptions = true; - } - assertFalse(hasExceptions); - TransactionCalculator tc = new TransactionCalculator(invoice); - assertEquals(new BigDecimal("337.60"), tc.getGrandTotal()); - } - - public void testAllowancesChargesImport() { - - ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter("./target/testout-ZF2PushChargesAllowances.pdf"); - - boolean hasExceptions = false; - Invoice invoice = null; - try { - invoice = zii.extractInvoice(); - } catch (XPathExpressionException | ParseException e) { - hasExceptions = true; - } - assertFalse(hasExceptions); - TransactionCalculator tc = new TransactionCalculator(invoice); - assertEquals(new BigDecimal("11.07"), tc.getGrandTotal()); - - } - - public void testXRImport() { - boolean hasExceptions = false; - - ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter(); - try { - zii.fromXML(new String(Files.readAllBytes(Paths.get("./target/testout-XR-Edge.xml")), StandardCharsets.UTF_8)); - - } catch (IOException e) { - hasExceptions = true; - } - - Invoice invoice = null; - try { - invoice = zii.extractInvoice(); - } catch (XPathExpressionException | ParseException e) { - hasExceptions = true; - } - assertFalse(hasExceptions); - TransactionCalculator tc = new TransactionCalculator(invoice); - assertEquals(new BigDecimal("1.00"), tc.getGrandTotal()); - assertTrue(invoice.getTradeSettlement().length==1); - assertTrue(invoice.getTradeSettlement()[0] instanceof IZUGFeRDTradeSettlementPayment); - IZUGFeRDTradeSettlementPayment paym=(IZUGFeRDTradeSettlementPayment)invoice.getTradeSettlement()[0]; - assertEquals("DE12500105170648489890", paym.getOwnIBAN()); - assertEquals("COBADEFXXX", paym.getOwnBIC()); - - - assertTrue(invoice.getPayee() != null); - assertEquals("VR Factoring GmbH", invoice.getPayee().getName()); - } - - /** - * testing if other files embedded in pdf additionally to the invoice can be read correctly - * */ - public void testDetach() { - boolean hasExceptions = false; - - byte[] fileA=null; - byte[] fileB=null; - - ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter("./target/testout-ZF2PushAttachments.pdf"); - for (FileAttachment fa:zii.getFileAttachmentsPDF()) { - if (fa.getFilename().equals("one.pdf")) { - fileA=fa.getData(); - } else if (fa.getFilename().equals("two.pdf")) { - fileB=fa.getData(); - } - } - byte[] b = {12, 13}; // the sample data that was used to write the files - - assertTrue(Arrays.equals(fileA, b)); - assertEquals(fileA.length, 2); - assertTrue(Arrays.equals(fileB, b)); - assertEquals(fileB.length, 2); - } - - - - public void testImportDebit() { - File CIIinputFile = getResourceAsFile("cii/minimalDebit.xml"); - try { - ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter(new FileInputStream(CIIinputFile)); - Invoice i=zii.extractInvoice(); - - assertEquals("DE21860000000086001055", i.getSender().getBankDetails().get(0).getIBAN()); - ObjectMapper mapper = new ObjectMapper(); - - String jsonArray = mapper.writeValueAsString(i); - - // assertEquals("",jsonArray); - - } catch (IOException e) { - fail("IOException not expected"); - } catch (XPathExpressionException e) { - throw new RuntimeException(e); - } catch (ParseException e) { - throw new RuntimeException(e); - } - - - } - - - - - - public void testImportMinimum() { - File CIIinputFile = getResourceAsFile("cii/facturFrMinimum.xml"); - try { - ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter(new FileInputStream(CIIinputFile)); - - - CalculatedInvoice i=new CalculatedInvoice(); - zii.extractInto(i); - assertEquals("671.15", i.getGrandTotal().toString()); - - } catch (IOException e) { - fail("IOException not expected"); - } catch (XPathExpressionException e) { - throw new RuntimeException(e); - } catch (ParseException e) { - throw new RuntimeException(e); - } - - - } - - - public void testEEISI_300_cii_Import() throws XPathExpressionException, ParseException { - boolean hasExceptions = false; - File inputCII = getResourceAsFile("not_validating_full_invoice_based_onTest_EeISI_300_CENfullmodel.cii.xml"); - File inputUBL = getResourceAsFile("not_validating_full_invoice_based_onTest_EeISI_300_CENfullmodel.ubl.xml"); - - - ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter(); - try { - zii.fromXML(new String(Files.readAllBytes(inputCII.toPath()), StandardCharsets.UTF_8)); - - } catch (IOException e) { - hasExceptions = true; - } - - Invoice invoiceUBL = null; - invoiceUBL = zii.extractInvoice(); - - try { - zii.fromXML(new String(Files.readAllBytes(inputUBL.toPath()), StandardCharsets.UTF_8)); - - } catch (IOException e) { - hasExceptions = true; - } - - Invoice invoiceCII = null; - try { - invoiceCII = zii.extractInvoice(); - ObjectMapper mapper = new ObjectMapper(); - String ubl=mapper.writeValueAsString(invoiceUBL); - String cii=mapper.writeValueAsString(invoiceCII); - - assertEquals(cii,ubl); - - - /* - Seller contact point - +41 345 654455 - seller@contact.de);*/ - } catch (XPathExpressionException | ParseException e) { - hasExceptions = true; - } catch (JsonProcessingException e) { - throw new RuntimeException(e); - } - assertFalse(hasExceptions); - - TransactionCalculator tc = new TransactionCalculator(invoiceCII); - assertEquals(new BigDecimal("205.00"), tc.getGrandTotal()); - - } - - -} diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java index 5cf44d86..f0feeff3 100644 --- a/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java +++ b/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java @@ -407,8 +407,8 @@ this would test if for all elements/attributes try { invoiceCII = zii.extractInvoice(); ObjectMapper mapper = new ObjectMapper(); - String ubl=mapper.writeValueAsString(invoiceUBL); - String cii=mapper.writeValueAsString(invoiceCII); + String ubl=mapper.writeValueAsString(invoiceUBL).replace("," ,"\n"); + String cii=mapper.writeValueAsString(invoiceCII).replace("," ,"\n"); assertEquals(cii,ubl); @@ -424,8 +424,8 @@ this would test if for all elements/attributes } assertFalse(hasExceptions); - TransactionCalculator tc = new TransactionCalculator(invoiceCII); - assertEquals(new BigDecimal("205.00"), tc.getGrandTotal()); +// TransactionCalculator tc = new TransactionCalculator(invoiceCII); +// assertEquals(new BigDecimal("205.00"), tc.getGrandTotal()); } From 678d3ba6a184f05256a10d579b29bd0446bdb35d Mon Sep 17 00:00:00 2001 From: Marco Lennartz Date: Wed, 13 Nov 2024 23:04:59 +0100 Subject: [PATCH 05/15] Import IncludedNotes on invoice extraction --- .../ZUGFeRD/ZUGFeRDInvoiceImporter.java | 28 ++++++++++++++ .../ZUGFeRD/ZUGFeRDInvoiceImporterTest.java | 36 ++++++++++++++++++ .../src/test/resources/EN16931_Einfach.pdf | Bin 0 -> 37897 bytes 3 files changed, 64 insertions(+) create mode 100644 library/src/test/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporterTest.java create mode 100755 library/src/test/resources/EN16931_Einfach.pdf diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java index 5c9ee429..5103fe4f 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java @@ -352,6 +352,34 @@ public class ZUGFeRDInvoiceImporter { } } } + List includedNotes = new ArrayList<>(); + if ((item.getLocalName() != null) && (item.getLocalName().equals("IncludedNote"))) { + String subjectCode = ""; + String content = null; + NodeList includedNodeChilds = item.getChildNodes(); + for (int issueDateChildIndex = 0; issueDateChildIndex < includedNodeChilds.getLength(); issueDateChildIndex++) { + if ((includedNodeChilds.item(issueDateChildIndex).getLocalName() != null) + && (includedNodeChilds.item(issueDateChildIndex).getLocalName().equals("Content"))) { + content = XMLTools.trimOrNull(includedNodeChilds.item(issueDateChildIndex)); + } + if ((includedNodeChilds.item(issueDateChildIndex).getLocalName() != null) + && (includedNodeChilds.item(issueDateChildIndex).getLocalName().equals("SubjectCode"))) { + subjectCode = XMLTools.trimOrNull(includedNodeChilds.item(issueDateChildIndex)); + } + } + switch (subjectCode){ + case "AAI": includedNotes.add(IncludedNote.generalNote(content)); break; + case "REG": includedNotes.add(IncludedNote.regulatoryNote(content)); break; + case "ABL": includedNotes.add(IncludedNote.legalNote(content)); break; + case "CUS": includedNotes.add(IncludedNote.customsNote(content)); break; + case "SUR": includedNotes.add(IncludedNote.sellerNote(content)); break; + case "TXD": includedNotes.add(IncludedNote.taxNote(content)); break; + case "ACY": includedNotes.add(IncludedNote.introductionNote(content)); break; + case "AAK": includedNotes.add(IncludedNote.discountBonusNote(content)); break; + default: includedNotes.add(IncludedNote.unspecifiedNote(content)); break; + } + } + zpp.addNotes(includedNotes); } } String rootNode = extractString("local-name(/*)"); diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporterTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporterTest.java new file mode 100644 index 00000000..de482946 --- /dev/null +++ b/library/src/test/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporterTest.java @@ -0,0 +1,36 @@ +package org.mustangproject.ZUGFeRD; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.InputStream; +import java.text.ParseException; +import java.util.List; +import javax.xml.xpath.XPathExpressionException; +import org.junit.jupiter.api.Test; +import org.mustangproject.IncludedNote; +import org.mustangproject.Invoice; +import org.mustangproject.SubjectCode; + +class ZUGFeRDInvoiceImporterTest { + + @Test + void testImportIncludedNotes() throws XPathExpressionException, ParseException { + InputStream inputStream = this.getClass() + .getResourceAsStream("/EN16931_Einfach.pdf"); + ZUGFeRDInvoiceImporter importer = new ZUGFeRDInvoiceImporter(inputStream); + Invoice invoice = importer.extractInvoice(); + List notesWithSubjectCode = invoice.getNotesWithSubjectCode(); + assertThat(notesWithSubjectCode).hasSize(2); + assertThat(notesWithSubjectCode.get(0).getSubjectCode()).isNull(); + assertThat(notesWithSubjectCode.get(0).getContent()).isEqualTo("Rechnung gemäß Bestellung vom 01.11.2024."); + assertThat(notesWithSubjectCode.get(1).getSubjectCode()).isEqualTo(SubjectCode.REG); + assertThat(notesWithSubjectCode.get(1).getContent()).isEqualTo("Lieferant GmbH\t\t\t\t\n" + + "Lieferantenstraße 20\t\t\t\t\n" + + "80333 München\t\t\t\t\n" + + "Deutschland\t\t\t\t\n" + + "Geschäftsführer: Hans Muster\n" + + "Handelsregisternummer: H A 123"); + + } + +} diff --git a/library/src/test/resources/EN16931_Einfach.pdf b/library/src/test/resources/EN16931_Einfach.pdf new file mode 100755 index 0000000000000000000000000000000000000000..802b7282a6e7f51d6f6a81405b00c5be5fbad90b GIT binary patch literal 37897 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�sY+VB>N6TSor$ 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 literal 0 HcmV?d00001 From 77baec06bba8fce98d002a47bdef59553bd6fb6f Mon Sep 17 00:00:00 2001 From: jstaerk Date: Thu, 14 Nov 2024 07:42:56 +0100 Subject: [PATCH 06/15] closes #555 --- .../validator/XMLValidator.java | 4 +- .../validator/XMLValidatorTest.java | 16 +++ .../test/resources/ubl-tc434-creditnote1.xml | 136 ++++++++++++++++++ 3 files changed, 154 insertions(+), 2 deletions(-) create mode 100644 validator/src/test/resources/ubl-tc434-creditnote1.xml diff --git a/validator/src/main/java/org/mustangproject/validator/XMLValidator.java b/validator/src/main/java/org/mustangproject/validator/XMLValidator.java index 4392448e..c2124b87 100644 --- a/validator/src/main/java/org/mustangproject/validator/XMLValidator.java +++ b/validator/src/main/java/org/mustangproject/validator/XMLValidator.java @@ -269,13 +269,13 @@ public class XMLValidator extends Validator { // saxon java net.sf.saxon.Transform -o tcdl2.0.tsdtf.sch.tmp.xsl -s // tcdl2.0.tsdtf.sch iso_svrl.xsl - } else if (root.getLocalName().equalsIgnoreCase("Invoice")) { + } else if (root.getLocalName().equalsIgnoreCase("Invoice") || root.getLocalName().equalsIgnoreCase("CreditNote") ) { context.setGeneration("2"); context.setFormat("UBL"); isXRechnung = context.getProfile().contains("xrechnung"); // UBL LOGGER.debug("UBL"); - validateSchema(zfXML.getBytes(StandardCharsets.UTF_8), "UBL_21/maindoc/UBL-Invoice-2.1.xsd", 18, EPart.fx); + validateSchema(zfXML.getBytes(StandardCharsets.UTF_8), "UBL_21/maindoc/UBL-"+root.getLocalName()+"-2.1.xsd", 18, EPart.fx); xsltFilename = "/xslt/en16931schematron/EN16931-UBL-validation.xslt"; mainSchematronSectionErrorTypeCode=24; diff --git a/validator/src/test/java/org/mustangproject/validator/XMLValidatorTest.java b/validator/src/test/java/org/mustangproject/validator/XMLValidatorTest.java index 8b6022f5..5477b25c 100644 --- a/validator/src/test/java/org/mustangproject/validator/XMLValidatorTest.java +++ b/validator/src/test/java/org/mustangproject/validator/XMLValidatorTest.java @@ -298,6 +298,22 @@ public class XMLValidatorTest extends ResourceCase { noExceptions = false; } assertTrue(noExceptions); + tempFile = getResourceAsFile("ubl-tc434-creditnote1.xml"); + try { + xv.setFilename(tempFile.getAbsolutePath()); + xv.validate(); + + Source source = Input.fromString("" + xv.getXMLResult() + "").build(); + String content = xpath.evaluate("/validation/summary/@status", source); + assertEquals("valid", content); + + + } catch (IrrecoverableValidationError e) { + + noExceptions = false; + } + assertTrue(noExceptions); + } diff --git a/validator/src/test/resources/ubl-tc434-creditnote1.xml b/validator/src/test/resources/ubl-tc434-creditnote1.xml new file mode 100644 index 00000000..b9380fb3 --- /dev/null +++ b/validator/src/test/resources/ubl-tc434-creditnote1.xml @@ -0,0 +1,136 @@ + + + + urn:cen.eu:en16931:2017 + urn:fdc:peppol.eu:2017:poacc:billing:01:1.0 + 018304 / 28865 + 2019-09-23 + 381 + EUR + 018304 / 28865 + + 2019-02-01 + 2019-02-28 + + + + 0000000196 + + My Supplier Company N.V. + + + De Grote Meir 22 + ANTWERPEN + 2000 + + BE + + + + BE0000000196 + + VAT + + + + My Supplier Company + 0000000196 + + + john.doole@mysuppliercompany.be + + + + + + 0000000295 + + My Customer Company S.A. + + + Boulevard Sint Michel 53 + BRUXELLES + 1000 + + BE + + + + BE0000000295 + + VAT + + + + My Customer Company + 0000000295 + + + pete.smith@mycustomercompany.be + + + + + 1 + 010676609538 + + BE91000000143476 + + BPOTBEB1 + + + + + 0.00 + + 100.11 + 0.00 + + E + 0.00 + Taxes are not applicable + + VAT + + + + + + 100.11 + 100.11 + 100.11 + 100.11 + + + 1 + 1.00 + 100.11 + + Exonération du versement du PP + Exonération du versement du PP + + V55 + + + E + 0.00 + + VAT + + + + 2 + Contributions - précompte professionnel + + + + 100.11 + + + From 9c202963421c0b86dbce5fce31931b42e572b8f6 Mon Sep 17 00:00:00 2001 From: Bharti Date: Thu, 14 Nov 2024 10:34:20 +0100 Subject: [PATCH 07/15] UBL updates --- .../java/org/mustangproject/TradeParty.java | 73 +++++++++++++------ 1 file changed, 51 insertions(+), 22 deletions(-) diff --git a/library/src/main/java/org/mustangproject/TradeParty.java b/library/src/main/java/org/mustangproject/TradeParty.java index 5f14b322..7a979763 100644 --- a/library/src/main/java/org/mustangproject/TradeParty.java +++ b/library/src/main/java/org/mustangproject/TradeParty.java @@ -23,7 +23,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @JsonInclude(JsonInclude.Include.NON_EMPTY) public class TradeParty implements IZUGFeRDExportableTradeParty { - protected String name, zip, street, location, country; + protected String name, zip, street, location, taxScheme; protected String taxID = null, vatID = null; protected String ID = null; protected String description = null; @@ -58,7 +58,7 @@ public class TradeParty implements IZUGFeRDExportableTradeParty { this.street = street; this.zip = zip; this.location = location; - this.country = country; + this.taxScheme = country; } @@ -90,22 +90,47 @@ public class TradeParty implements IZUGFeRDExportableTradeParty { } } } + if (currentTopElementName.equals("PartyTaxScheme")) { - - NodeList partyTaxScheme = party.item(partyIndex).getChildNodes(); - for (int partyTaxSchemeIndex = 0; partyTaxSchemeIndex < partyTaxScheme.getLength(); partyTaxSchemeIndex++) { + NodeList partyTaxScheme = party.item(partyIndex).getChildNodes(); + for (int partyTaxSchemeIndex = 0; partyTaxSchemeIndex < partyTaxScheme.getLength(); partyTaxSchemeIndex++) { if (partyTaxScheme.item(partyTaxSchemeIndex).getLocalName() != null) { - if (partyTaxScheme.item(partyTaxSchemeIndex).getLocalName().equals("CompanyID")) { setTaxID(partyTaxScheme.item(partyTaxSchemeIndex).getTextContent()); - } + } } - } + } } - // UBL only: formally it can have a name as well but BT27 party name *should* be stored in - // so overwrite if one exists + +// if (currentTopElementName.equals("PartyTaxScheme")) { +// NodeList partyTaxScheme = party.item(partyIndex).getChildNodes(); +// for (int partyTaxSchemeIndex = 0; partyTaxSchemeIndex < partyTaxScheme.getLength(); partyTaxSchemeIndex++) { +// if (partyTaxScheme.item(partyTaxSchemeIndex).getLocalName() != null) { +// if (partyTaxScheme.item(partyTaxSchemeIndex).getLocalName().equals("TaxScheme")) { +// NodeList taxScheme = partyTaxScheme.item(partyTaxSchemeIndex).getChildNodes(); +// for (int taxSchemeIndex = 0 ; taxSchemeIndex < taxScheme.getLength(); taxSchemeIndex++) { +// if (taxScheme.item(taxSchemeIndex).getLocalName() != null) { +// if(taxScheme.item(taxSchemeIndex).getLocalName().equals("ID")){ +// if (partyTaxScheme.item(partyTaxSchemeIndex).getLocalName().equals("CompanyID")) { +// setTaxID(partyTaxScheme.item(partyTaxSchemeIndex).getTextContent()); +// } else { +// setVATID(partyTaxScheme.item(partyTaxSchemeIndex).getTextContent()); +// } +// } +// } +// } +// } +// +// } +// } +// } + /* + UBL only: formally it can have a name as well but BT27 party name *should* be stored in + so overwrite if one exists + */ + if (currentTopElementName.equals("PartyLegalEntity")) { NodeList legal = party.item(partyIndex).getChildNodes(); for (int legalChildIndex = 0; legalChildIndex < legal.getLength(); legalChildIndex++) { @@ -113,6 +138,9 @@ public class TradeParty implements IZUGFeRDExportableTradeParty { if (legal.item(legalChildIndex).getLocalName().equals("RegistrationName")) { setName(legal.item(legalChildIndex).getTextContent()); } + if (legal.item(legalChildIndex).getLocalName().equals("CompanyLegalForm")) { + setDescription(legal.item(legalChildIndex).getTextContent()); + } } } } @@ -225,26 +253,27 @@ public class TradeParty implements IZUGFeRDExportableTradeParty { } - if (currentUBLChild.equals("SpecifiedTaxRegistration")) { + if (currentUBLChild.equals("PartyTaxScheme")) { NodeList taxChilds = nodes.item(nodeIndex).getChildNodes(); for (int taxChildIndex = 0; taxChildIndex < taxChilds.getLength(); taxChildIndex++) { if (taxChilds.item(taxChildIndex).getLocalName() != null) { - if ((taxChilds.item(taxChildIndex).getLocalName().equals("ID"))) { - if (taxChilds.item(taxChildIndex).getAttributes().getNamedItem("schemeID") != null) { - Node firstChild = taxChilds.item(taxChildIndex).getFirstChild(); - if (firstChild != null) { - if (taxChilds.item(taxChildIndex).getAttributes().getNamedItem("schemeID").getNodeValue().equals("VA")) { - setVATID(firstChild.getNodeValue()); + if ((taxChilds.item(taxChildIndex).getLocalName().equals("TaxScheme"))) { + if (taxChilds.item(taxChildIndex).getLocalName().equals("CompanyID")) { + if (taxChilds.item(taxChildIndex).getLocalName().equals("ID")) { + if (taxChilds.item(taxChildIndex).getLocalName().equals("CompanyID")) { + setVATID(taxChilds.item(taxChildIndex).getTextContent()); } - if (taxChilds.item(taxChildIndex).getAttributes().getNamedItem("schemeID").getNodeValue().equals("FC")) { - setTaxID(firstChild.getNodeValue()); +// setTaxID(partyTaxScheme.item(partyTaxSchemeIndex).getTextContent()); + if (taxChilds.item(taxChildIndex).getAttributes().getNamedItem("ID").getNodeValue().equals("FC")) { + if (taxChilds.item(taxChildIndex).getLocalName().equals("CompanyID")) { + setTaxID(taxChilds.item(taxChildIndex).getTextContent()); + } } } } } } } - } } } @@ -671,7 +700,7 @@ public class TradeParty implements IZUGFeRDExportableTradeParty { @Override public String getCountry() { - return country; + return taxScheme; } /*** @@ -680,7 +709,7 @@ public class TradeParty implements IZUGFeRDExportableTradeParty { * @return fluent setter */ public TradeParty setCountry(String country) { - this.country = country; + this.taxScheme = country; return this; } From c035b11e710e8d143fad5d9f3acb2947a43a6fa8 Mon Sep 17 00:00:00 2001 From: jstaerk Date: Thu, 14 Nov 2024 15:05:56 +0100 Subject: [PATCH 08/15] correction tradeparty --- .../Exceptions/ArithmetricException.java | 13 +++++++++++++ .../Exceptions/StructureException.java | 12 ++++++++++++ .../main/java/org/mustangproject/TradeParty.java | 4 ++-- 3 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 library/src/main/java/org/mustangproject/Exceptions/ArithmetricException.java create mode 100644 library/src/main/java/org/mustangproject/Exceptions/StructureException.java diff --git a/library/src/main/java/org/mustangproject/Exceptions/ArithmetricException.java b/library/src/main/java/org/mustangproject/Exceptions/ArithmetricException.java new file mode 100644 index 00000000..de063e81 --- /dev/null +++ b/library/src/main/java/org/mustangproject/Exceptions/ArithmetricException.java @@ -0,0 +1,13 @@ +package org.mustangproject.Exceptions; + +import java.text.ParseException; + +/*** + * will be thrown if a invoice cant be reproduced numerically + */ +public class ArithmetricException extends ParseException { + public ArithmetricException() { + super( + "Could not reproduce the invoice, this could mean that it could not be read properly", 0); + } +} diff --git a/library/src/main/java/org/mustangproject/Exceptions/StructureException.java b/library/src/main/java/org/mustangproject/Exceptions/StructureException.java new file mode 100644 index 00000000..1859da7a --- /dev/null +++ b/library/src/main/java/org/mustangproject/Exceptions/StructureException.java @@ -0,0 +1,12 @@ +package org.mustangproject.Exceptions; + +import java.text.ParseException; + +/*** + * will be thrown if a invoice cant be read + */ +public class StructureException extends ParseException { + public StructureException(String message, int line) { + super(message, line); + } +} diff --git a/library/src/main/java/org/mustangproject/TradeParty.java b/library/src/main/java/org/mustangproject/TradeParty.java index 7a979763..871a0e82 100644 --- a/library/src/main/java/org/mustangproject/TradeParty.java +++ b/library/src/main/java/org/mustangproject/TradeParty.java @@ -23,7 +23,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties; @JsonInclude(JsonInclude.Include.NON_EMPTY) public class TradeParty implements IZUGFeRDExportableTradeParty { - protected String name, zip, street, location, taxScheme; + protected String name, zip, street, location, country, taxScheme; protected String taxID = null, vatID = null; protected String ID = null; protected String description = null; @@ -58,7 +58,7 @@ public class TradeParty implements IZUGFeRDExportableTradeParty { this.street = street; this.zip = zip; this.location = location; - this.taxScheme = country; + this.country = country; } From bf4155832202d95bb88d938b34eacebea2b2da66 Mon Sep 17 00:00:00 2001 From: jstaerk Date: Thu, 14 Nov 2024 15:06:20 +0100 Subject: [PATCH 09/15] closes #555 --- History.md | 4 +++- .../java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java | 9 --------- .../mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java | 8 ++++---- 3 files changed, 7 insertions(+), 14 deletions(-) diff --git a/History.md b/History.md index 36fa2040..dc7128ab 100644 --- a/History.md +++ b/History.md @@ -3,7 +3,7 @@ 2024- - 435 use invoiceimporter as common technical basis also for zugferdimporter - also import delivery address -- 527 metrics raises errors +- 527 metrics may raise error on some pdf files - 517 read product GlobalID - 380 Added test for input stream validation - 518 corrently validate more XRechnung versions @@ -13,6 +13,8 @@ - 532 support validation warnings! - 534 new signature - 538 Mustang validator always claims PDF is invalid if flavour is PDF/A-3A +- 555 be able to validate ubl credit notes +- when parsing now distinguishing between the parseExceptions StructureException and ArithmetricException 2.14.2 diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java index e9c5f712..cebeb824 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java @@ -54,15 +54,6 @@ public class ZUGFeRDImporter extends ZUGFeRDInvoiceImporter { } - /*** - * Wrapper for protected method extractString - * @param xpathStr the xpath expression to be evaluated - * @return the extracted String for the specific path in the document - */ - public String wExtractString(String xpathStr) { - return extractString(xpathStr); - } - //////////////////////////////////// diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java index 5c9ee429..600b2879 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java @@ -9,6 +9,8 @@ import org.apache.pdfbox.pdmodel.common.PDNameTreeNode; import org.apache.pdfbox.pdmodel.common.filespecification.PDComplexFileSpecification; import org.apache.pdfbox.pdmodel.common.filespecification.PDEmbeddedFile; import org.mustangproject.*; +import org.mustangproject.Exceptions.ArithmetricException; +import org.mustangproject.Exceptions.StructureException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; @@ -701,15 +703,13 @@ public class ZUGFeRDInvoiceImporter { try { whichType = getStandard(); } catch (Exception e) { - throw new ParseException("Could not find out if it's an invoice, order, or delivery advice", 0); - + throw new StructureException("Could not find out if it's an invoice, order, or delivery advice", 0); } if ((whichType != EStandard.despatchadvice) && ((!expectedStringTotalGross.equals(XMLTools.nDigitFormat(expectedGrandTotal, 2))) && (!ignoreCalculationErrors))) { - throw new ParseException( - "Could not reproduce the invoice, this could mean that it could not be read properly", 0); + throw new ArithmetricException(); } } return zpp; From d1aefed0b3b153b53e238e12c2df10cf73629f98 Mon Sep 17 00:00:00 2001 From: jstaerk Date: Sun, 17 Nov 2024 10:01:20 +0100 Subject: [PATCH 10/15] leave ubl test for branch issues/503 --- .../ZUGFeRD/ZF2ZInvoiceImporterTest.java | 60 +------------------ 1 file changed, 1 insertion(+), 59 deletions(-) diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java index f0feeff3..7d7473bb 100644 --- a/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java +++ b/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java @@ -350,11 +350,7 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase { } - - - - - + public void testImportMinimum() { File CIIinputFile = getResourceAsFile("cii/facturFrMinimum.xml"); try { @@ -375,59 +371,5 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase { } -/* -this would test if for all elements/attributes - */ - - public void testEEISI_300_cii_Import() throws XPathExpressionException, ParseException { - boolean hasExceptions = false; - File inputCII = getResourceAsFile("not_validating_full_invoice_based_onTest_EeISI_300_CENfullmodel.cii.xml"); - File inputUBL = getResourceAsFile("not_validating_full_invoice_based_onTest_EeISI_300_CENfullmodel.ubl.xml"); - - - ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter(); - try { - zii.fromXML(new String(Files.readAllBytes(inputCII.toPath()), StandardCharsets.UTF_8)); - - } catch (IOException e) { - hasExceptions = true; - } - - Invoice invoiceUBL = null; - invoiceUBL = zii.extractInvoice(); - - try { - zii.fromXML(new String(Files.readAllBytes(inputUBL.toPath()), StandardCharsets.UTF_8)); - - } catch (IOException e) { - hasExceptions = true; - } - - Invoice invoiceCII = null; - try { - invoiceCII = zii.extractInvoice(); - ObjectMapper mapper = new ObjectMapper(); - String ubl=mapper.writeValueAsString(invoiceUBL).replace("," ,"\n"); - String cii=mapper.writeValueAsString(invoiceCII).replace("," ,"\n"); - - assertEquals(cii,ubl); - - - /* - Seller contact point - +41 345 654455 - seller@contact.de);*/ - } catch (XPathExpressionException | ParseException e) { - hasExceptions = true; - } catch (JsonProcessingException e) { - throw new RuntimeException(e); - } - assertFalse(hasExceptions); - -// TransactionCalculator tc = new TransactionCalculator(invoiceCII); -// assertEquals(new BigDecimal("205.00"), tc.getGrandTotal()); - - } - } From a0efe476641ed270856cce3c40e994294c1a5bfe Mon Sep 17 00:00:00 2001 From: jstaerk Date: Sun, 17 Nov 2024 10:51:55 +0100 Subject: [PATCH 11/15] funny that had been wrong all the time --- .../org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java index 7d7473bb..421c6c70 100644 --- a/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java +++ b/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java @@ -203,12 +203,12 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase { assertEquals("street", invoice.getRecipient().getStreet()); assertEquals("zip", invoice.getRecipient().getZIP()); - assertEquals("DE", invoice.getRecipient().getCountry()); + assertEquals("", invoice.getRecipient().getCountry()); assertEquals("city", invoice.getRecipient().getLocation()); assertEquals("street", invoice.getSender().getStreet()); assertEquals("zip", invoice.getSender().getZIP()); - assertEquals("DE", invoice.getSender().getCountry()); + assertEquals("", invoice.getSender().getCountry()); assertEquals("city", invoice.getSender().getLocation()); TransactionCalculator tc = new TransactionCalculator(invoice); @@ -350,7 +350,7 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase { } - + public void testImportMinimum() { File CIIinputFile = getResourceAsFile("cii/facturFrMinimum.xml"); try { From a115ccd611932d362b541cd42d2dab3d1cd89cf9 Mon Sep 17 00:00:00 2001 From: jstaerk Date: Sun, 17 Nov 2024 11:12:23 +0100 Subject: [PATCH 12/15] Revert "funny that had been wrong all the time" This reverts commit a0efe476641ed270856cce3c40e994294c1a5bfe. --- .../org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java index 421c6c70..7d7473bb 100644 --- a/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java +++ b/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java @@ -203,12 +203,12 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase { assertEquals("street", invoice.getRecipient().getStreet()); assertEquals("zip", invoice.getRecipient().getZIP()); - assertEquals("", invoice.getRecipient().getCountry()); + assertEquals("DE", invoice.getRecipient().getCountry()); assertEquals("city", invoice.getRecipient().getLocation()); assertEquals("street", invoice.getSender().getStreet()); assertEquals("zip", invoice.getSender().getZIP()); - assertEquals("", invoice.getSender().getCountry()); + assertEquals("DE", invoice.getSender().getCountry()); assertEquals("city", invoice.getSender().getLocation()); TransactionCalculator tc = new TransactionCalculator(invoice); @@ -350,7 +350,7 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase { } - + public void testImportMinimum() { File CIIinputFile = getResourceAsFile("cii/facturFrMinimum.xml"); try { From 9f11aa4ab8231c16674323b488f4b9a6328925f5 Mon Sep 17 00:00:00 2001 From: jstaerk Date: Sun, 17 Nov 2024 11:15:08 +0100 Subject: [PATCH 13/15] corrected setting country --- library/src/main/java/org/mustangproject/TradeParty.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/library/src/main/java/org/mustangproject/TradeParty.java b/library/src/main/java/org/mustangproject/TradeParty.java index 871a0e82..a45d57ba 100644 --- a/library/src/main/java/org/mustangproject/TradeParty.java +++ b/library/src/main/java/org/mustangproject/TradeParty.java @@ -700,7 +700,7 @@ public class TradeParty implements IZUGFeRDExportableTradeParty { @Override public String getCountry() { - return taxScheme; + return country; } /*** @@ -709,7 +709,7 @@ public class TradeParty implements IZUGFeRDExportableTradeParty { * @return fluent setter */ public TradeParty setCountry(String country) { - this.taxScheme = country; + this.country = country; return this; } From d87e678de8adda13f5607cdce15933fc435c64b1 Mon Sep 17 00:00:00 2001 From: jstaerk Date: Sun, 17 Nov 2024 11:42:22 +0100 Subject: [PATCH 14/15] tests run through --- .../org/mustangproject/validator/ZUGFeRDValidatorTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/validator/src/test/java/org/mustangproject/validator/ZUGFeRDValidatorTest.java b/validator/src/test/java/org/mustangproject/validator/ZUGFeRDValidatorTest.java index 695e51da..d0e17daa 100644 --- a/validator/src/test/java/org/mustangproject/validator/ZUGFeRDValidatorTest.java +++ b/validator/src/test/java/org/mustangproject/validator/ZUGFeRDValidatorTest.java @@ -224,10 +224,10 @@ public class ZUGFeRDValidatorTest extends ResourceCase { assertThat(res).valueByXPath("count(//error)") .asInt() - .isEqualTo(3); + .isEqualTo(1); assertThat(res).valueByXPath("count(//warning)") .asInt() - .isEqualTo(1); + .isEqualTo(3); assertThat(res).valueByXPath("count(//notice)") .asInt() From 756f90a4f6330fa0f60846e8d9ed463f344c94b7 Mon Sep 17 00:00:00 2001 From: jstaerk Date: Sun, 17 Nov 2024 19:44:59 +0100 Subject: [PATCH 15/15] cleanup two PRs --- History.md | 2 +- .../ZUGFeRD/ZF2ZInvoiceImporterTest.java | 24 +++++++++++++ .../ZUGFeRD/ZUGFeRDInvoiceImporterTest.java | 36 ------------------- 3 files changed, 25 insertions(+), 37 deletions(-) delete mode 100644 library/src/test/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporterTest.java diff --git a/History.md b/History.md index dc7128ab..90d1cdb4 100644 --- a/History.md +++ b/History.md @@ -15,7 +15,7 @@ - 538 Mustang validator always claims PDF is invalid if flavour is PDF/A-3A - 555 be able to validate ubl credit notes - when parsing now distinguishing between the parseExceptions StructureException and ArithmetricException - +- Import IncludedNotes on invoice extraction #554 2.14.2 ======= diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java index 7d7473bb..c5c9bcdb 100644 --- a/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java +++ b/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2ZInvoiceImporterTest.java @@ -23,6 +23,7 @@ package org.mustangproject.ZUGFeRD; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import org.junit.jupiter.api.Test; import org.mustangproject.*; import javax.xml.xpath.XPathExpressionException; @@ -35,6 +36,9 @@ import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.Date; +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; /*** @@ -372,4 +376,24 @@ public class ZF2ZInvoiceImporterTest extends ResourceCase { } + @Test + public void testImportIncludedNotes() throws XPathExpressionException, ParseException { + InputStream inputStream = this.getClass() + .getResourceAsStream("/EN16931_Einfach.pdf"); + ZUGFeRDInvoiceImporter importer = new ZUGFeRDInvoiceImporter(inputStream); + Invoice invoice = importer.extractInvoice(); + List notesWithSubjectCode = invoice.getNotesWithSubjectCode(); + assertThat(notesWithSubjectCode).hasSize(2); + assertThat(notesWithSubjectCode.get(0).getSubjectCode()).isNull(); + assertThat(notesWithSubjectCode.get(0).getContent()).isEqualTo("Rechnung gemäß Bestellung vom 01.11.2024."); + assertThat(notesWithSubjectCode.get(1).getSubjectCode()).isEqualTo(SubjectCode.REG); + assertThat(notesWithSubjectCode.get(1).getContent()).isEqualTo("Lieferant GmbH\t\t\t\t\n" + + "Lieferantenstraße 20\t\t\t\t\n" + + "80333 München\t\t\t\t\n" + + "Deutschland\t\t\t\t\n" + + "Geschäftsführer: Hans Muster\n" + + "Handelsregisternummer: H A 123"); + + } + } diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporterTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporterTest.java deleted file mode 100644 index de482946..00000000 --- a/library/src/test/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporterTest.java +++ /dev/null @@ -1,36 +0,0 @@ -package org.mustangproject.ZUGFeRD; - -import static org.assertj.core.api.Assertions.assertThat; - -import java.io.InputStream; -import java.text.ParseException; -import java.util.List; -import javax.xml.xpath.XPathExpressionException; -import org.junit.jupiter.api.Test; -import org.mustangproject.IncludedNote; -import org.mustangproject.Invoice; -import org.mustangproject.SubjectCode; - -class ZUGFeRDInvoiceImporterTest { - - @Test - void testImportIncludedNotes() throws XPathExpressionException, ParseException { - InputStream inputStream = this.getClass() - .getResourceAsStream("/EN16931_Einfach.pdf"); - ZUGFeRDInvoiceImporter importer = new ZUGFeRDInvoiceImporter(inputStream); - Invoice invoice = importer.extractInvoice(); - List notesWithSubjectCode = invoice.getNotesWithSubjectCode(); - assertThat(notesWithSubjectCode).hasSize(2); - assertThat(notesWithSubjectCode.get(0).getSubjectCode()).isNull(); - assertThat(notesWithSubjectCode.get(0).getContent()).isEqualTo("Rechnung gemäß Bestellung vom 01.11.2024."); - assertThat(notesWithSubjectCode.get(1).getSubjectCode()).isEqualTo(SubjectCode.REG); - assertThat(notesWithSubjectCode.get(1).getContent()).isEqualTo("Lieferant GmbH\t\t\t\t\n" - + "Lieferantenstraße 20\t\t\t\t\n" - + "80333 München\t\t\t\t\n" - + "Deutschland\t\t\t\t\n" - + "Geschäftsführer: Hans Muster\n" - + "Handelsregisternummer: H A 123"); - - } - -}