diff --git a/Mustang-CLI/src/test/java/org/mustangproject/commandline/CliIT.java b/Mustang-CLI/src/test/java/org/mustangproject/commandline/CliIT.java index 73c35cd0..a6cf0bd9 100644 --- a/Mustang-CLI/src/test/java/org/mustangproject/commandline/CliIT.java +++ b/Mustang-CLI/src/test/java/org/mustangproject/commandline/CliIT.java @@ -1,8 +1,6 @@ package org.mustangproject.commandline; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; +import java.io.*; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; @@ -10,18 +8,43 @@ import java.nio.file.Paths; import java.util.concurrent.TimeUnit; import static org.junit.jupiter.api.Assertions.assertTrue; + import org.junit.jupiter.api.Test; public class CliIT { + public static File getResourceAsFile(String resourcePath) { + try { + InputStream in = ClassLoader.getSystemClassLoader().getResourceAsStream(resourcePath); + if (in == null) { + return null; + } + + File tempFile = File.createTempFile(String.valueOf(in.hashCode()), ".tmp"); + tempFile.deleteOnExit(); + + try (FileOutputStream out = new FileOutputStream(tempFile)) { + // copy stream + byte[] buffer = new byte[1024]; + int bytesRead; + while ((bytesRead = in.read(buffer)) != -1) { + out.write(buffer, 0, bytesRead); + } + } + return tempFile; + } catch (IOException e) { + return null; + } + } + @Test public void testCii2Ubl() throws Exception { Path output = Paths.get("target/ubl.xml"); Files.deleteIfExists(output); Path jar = Files.newDirectoryStream(Paths.get("target"), "Mustang-CLI-*.jar").iterator().next(); ProcessBuilder pb = new ProcessBuilder("java", "-jar", jar.toString(), - "--action", "ubl", "--source", "src/test/resources/cii.xml", "--out", - output.toString()); + "--action", "ubl", "--source", "src/test/resources/cii.xml", "--out", + output.toString()); pb.redirectErrorStream(true); Process process = pb.start(); String result = getOutput(process); @@ -43,4 +66,17 @@ public class CliIT { return builder.toString(); } + @Test + public void testMetric() { + StatRun sr = new StatRun(); + File tempFile = getResourceAsFile("corrupt-factur-x-waytoosmall.pdf"); + + FileChecker fc = new FileChecker(tempFile.getAbsolutePath(), sr); + + fc.checkForZUGFeRD(); + System.out.print(fc.getOutputLine()); + + + } + } diff --git a/Mustang-CLI/src/test/resources/corrupt-factur-x-waytoosmall.pdf b/Mustang-CLI/src/test/resources/corrupt-factur-x-waytoosmall.pdf new file mode 100644 index 00000000..672888d1 --- /dev/null +++ b/Mustang-CLI/src/test/resources/corrupt-factur-x-waytoosmall.pdf @@ -0,0 +1,2 @@ +%PDF-1.4 +%ª«¬­ diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java index 6d044371..e20226de 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java @@ -78,7 +78,7 @@ public class ZUGFeRDInvoiceImporter { protected ArrayList fileAttachments = new ArrayList<>(); - protected ZUGFeRDInvoiceImporter() { + public ZUGFeRDInvoiceImporter() { //constructor for extending classes } @@ -90,7 +90,7 @@ public class ZUGFeRDInvoiceImporter { setInputStream(pdfStream); } - public void setPDFFilename(String pdfFilename){ + public void setPDFFilename(String pdfFilename) { try (InputStream bis = Files.newInputStream(Paths.get(pdfFilename), StandardOpenOption.READ)) { extractLowLevel(bis); } catch (final IOException e) { @@ -134,7 +134,8 @@ public class ZUGFeRDInvoiceImporter { if (Arrays.equals(pad, pdfSignature)) { // we have a pdf - try (PDDocument doc = Loader.loadPDF(IOUtils.toByteArray(pdfStream))) { + try { + PDDocument doc = Loader.loadPDF(IOUtils.toByteArray(pdfStream)); // PDDocumentInformation info = doc.getDocumentInformation(); final PDDocumentNameDictionary names = new PDDocumentNameDictionary(doc.getDocumentCatalog()); //start @@ -169,6 +170,9 @@ public class ZUGFeRDInvoiceImporter { extractFiles(namesL); } } + } catch (Exception e) { + LOGGER.error("Failed to parse PDF", e); + //ignore otherwise } } else { // no PDF probably XML @@ -307,7 +311,7 @@ public class ZUGFeRDInvoiceImporter { NodeList SellerNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET); XPathExpression shipEx = xpath.compile("//*[local-name()=\"ShipToTradeParty\"]"); NodeList deliveryNodes = (NodeList) shipEx.evaluate(getDocument(), XPathConstants.NODESET); - if (deliveryNodes!=null) { + if (deliveryNodes != null) { zpp.setDeliveryAddress(new TradeParty(deliveryNodes)); } @@ -460,10 +464,13 @@ public class ZUGFeRDInvoiceImporter { xpr = xpath.compile("//*[local-name()=\"ApplicableHeaderTradeSettlement\"]|//*[local-name()=\"ApplicableSupplyChainTradeSettlement\"]"); NodeList headerTradeSettlementNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET); List bankDetails = new ArrayList<>(); + String directDebitMandateID = null; + String IBAN = null, BIC = null; for (int i = 0; i < headerTradeSettlementNodes.getLength(); i++) { // nodes.item(i).getTextContent())) { Node headerTradeSettlementNode = headerTradeSettlementNodes.item(i); + NodeList headerTradeSettlementChilds = headerTradeSettlementNode.getChildNodes(); for (int settlementChildIndex = 0; settlementChildIndex < headerTradeSettlementChilds.getLength(); settlementChildIndex++) { if ((headerTradeSettlementChilds.item(settlementChildIndex).getLocalName() != null) @@ -478,13 +485,17 @@ public class ZUGFeRDInvoiceImporter { } } } + if ((paymentTermChilds.item(paymentTermChildIndex).getLocalName() != null) && (paymentTermChilds.item(paymentTermChildIndex).getLocalName().equals("DirectDebitMandateID"))) { + directDebitMandateID = paymentTermChilds.item(paymentTermChildIndex).getTextContent(); + } } } if ((headerTradeSettlementChilds.item(settlementChildIndex).getLocalName() != null) && (headerTradeSettlementChilds.item(settlementChildIndex).getLocalName().equals("SpecifiedTradeSettlementPaymentMeans"))) { NodeList paymentMeansChilds = headerTradeSettlementChilds.item(settlementChildIndex).getChildNodes(); - String IBAN = null, BIC = null; + IBAN = null; + BIC = null; for (int paymentMeansChildIndex = 0; paymentMeansChildIndex < paymentMeansChilds.getLength(); paymentMeansChildIndex++) { if ((paymentMeansChilds.item(paymentMeansChildIndex).getLocalName() != null) && (paymentMeansChilds.item(paymentMeansChildIndex).getLocalName().equals("PayeePartyCreditorFinancialAccount") || paymentMeansChilds.item(paymentMeansChildIndex).getLocalName().equals("PayerPartyDebtorFinancialAccount"))) { @@ -558,7 +569,7 @@ public class ZUGFeRDInvoiceImporter { NodeList paymentTermChilds = paymentMeansChilds.item(meansChildIndex).getChildNodes(); for (int paymentTermChildIndex = 0; paymentTermChildIndex < paymentTermChilds.getLength(); paymentTermChildIndex++) { if ((paymentTermChilds.item(paymentTermChildIndex).getLocalName() != null) && (paymentTermChilds.item(paymentTermChildIndex).getLocalName().equals("ID"))) { - String IBAN = paymentTermChilds.item(paymentTermChildIndex).getTextContent(); + IBAN = paymentTermChilds.item(paymentTermChildIndex).getTextContent(); if (IBAN != null) { BankDetails bd = new BankDetails(IBAN); bankDetails.add(bd); @@ -571,6 +582,11 @@ public class ZUGFeRDInvoiceImporter { zpp.setDueDate(dueDate).setDeliveryDate(deliveryDate).setIssueDate(issueDate).setSender(new TradeParty(SellerNodes)).setRecipient(new TradeParty(BuyerNodes)).setNumber(number).setDocumentCode(typeCode); + if ((directDebitMandateID != null) && (IBAN != null)) { + DirectDebit d = new DirectDebit(IBAN, directDebitMandateID); + zpp.getSender().addDebitDetails(d); + } + bankDetails.forEach(bankDetail -> zpp.getSender().addBankDetails(bankDetail)); if (payeeNodes.getLength() > 0) { @@ -707,7 +723,7 @@ public class ZUGFeRDInvoiceImporter { && ((!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); + "Could not reproduce the invoice, this could mean that it could not be read properly exp "+expectedStringTotalGross+" is "+XMLTools.nDigitFormat(expectedGrandTotal, 2), 0); } } return zpp;