From 3d455509fcd5c189164e465566cb3d1ce5a447ca Mon Sep 17 00:00:00 2001 From: Sebastian Sieber Date: Mon, 29 Aug 2022 09:33:09 +0200 Subject: [PATCH] Extend importer Importer reads BillingSpecifiedPeriod of ApplicableHeaderTradeSettlement and SpecifiedLineTradeSettlement. Add ZugferdImporter#getDetailedDeliveryPeriodFrom and ZugferdImporter#getDetailedDeliveryPeriodTo. Fix extractIssuerAssignedID. --- .../ZUGFeRD/ZUGFeRDImporter.java | 68 +++++- .../ZUGFeRD/InvoicingPeriodTestCase.java | 43 ++++ .../resources/factur-x_invoicingPeriod.xml | 219 ++++++++++++++++++ 3 files changed, 318 insertions(+), 12 deletions(-) create mode 100644 library/src/test/java/org/mustangproject/ZUGFeRD/InvoicingPeriodTestCase.java create mode 100644 library/src/test/resources/factur-x_invoicingPeriod.xml diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java index 92dced87..7df95f14 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDImporter.java @@ -21,7 +21,9 @@ import java.math.BigDecimal; import java.nio.file.Files; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; +import java.text.SimpleDateFormat; import java.util.ArrayList; +import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -258,8 +260,9 @@ public class ZUGFeRDImporter { case "urn:ferd:CrossIndustryDocument:invoice:1p0:extended": case "urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended": return "EXTENDED"; - } - return ""; + default: + return ""; + } } /** @@ -303,9 +306,9 @@ public class ZUGFeRDImporter { private String extractIssuerAssignedID(String propertyName) { try { if (getVersion() == 1) { - return extractString("//*[local-name() = 'BuyerOrderReferencedDocument']//*[local-name() = 'ID']"); + return extractString("//*[local-name() = '" + propertyName + "']//*[local-name() = 'ID']"); } else { - return extractString("//*[local-name() = 'BuyerOrderReferencedDocument']//*[local-name() = 'IssuerAssignedID']"); + return extractString("//*[local-name() = '" + propertyName + "']//*[local-name() = 'IssuerAssignedID']"); } } catch (final Exception e) { Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e); @@ -335,6 +338,21 @@ public class ZUGFeRDImporter { return ""; } } + + public Date getDetailedDeliveryPeriodFrom(){ + final String toParse = extractString( + "//*[local-name() = 'ApplicableHeaderTradeSettlement']" + + "//*[local-name() = 'BillingSpecifiedPeriod']" + + "//*[local-name() = 'StartDateTime']//*[local-name() = 'DateTimeString']"); + return tryDate(toParse); + } + public Date getDetailedDeliveryPeriodTo(){ + final String toParse = extractString( + "//*[local-name() = 'ApplicableHeaderTradeSettlement']" + + "//*[local-name() = 'BillingSpecifiedPeriod']" + + "//*[local-name() = 'EndDateTime']//*[local-name() = 'DateTimeString']"); + return tryDate(toParse); + } /** * @return the TaxBasisTotalAmount @@ -754,8 +772,6 @@ public class ZUGFeRDImporter { public PostalTradeAddress getSellerTradePartyAddress() { NodeList nl = null; - final PostalTradeAddress address = new PostalTradeAddress(); - try { if (getVersion() == 1) { nl = getNodeListByPath("//*[local-name() = 'CrossIndustryDocument']//*[local-name() = 'SpecifiedSupplyChainTradeTransaction']//*[local-name() = 'ApplicableSupplyChainTradeAgreement']//*[local-name() = 'SellerTradeParty']//*[local-name() = 'PostalTradeAddress']"); @@ -913,6 +929,20 @@ public class ZUGFeRDImporter { node = getNodeByName(node.getChildNodes(), "CalculatedAmount"); lineItem.setTax(tryBigDecimal(getNodeValue(node))); } + node = getNodeByName(nn.getChildNodes(), "BillingSpecifiedPeriod"); + if (node != null) { + final Node start = getNodeByName(node.getChildNodes(), "StartDateTime"); + Node dateTimeStart = null; + if(start != null) { + dateTimeStart = getNodeByName(start.getChildNodes(), "DateTimeString"); + } + final Node end = getNodeByName(node.getChildNodes(), "EndDateTime"); + Node dateTimeEnd = null; + if(end != null) { + dateTimeEnd = getNodeByName(end.getChildNodes(), "DateTimeString"); + } + lineItem.setDetailedDeliveryPeriod(tryDate(dateTimeStart), tryDate(dateTimeEnd)); + } node = getNodeByName(nn.getChildNodes(), "SpecifiedTradeSettlementLineMonetarySummation"); if (node != null) { @@ -1016,11 +1046,9 @@ public class ZUGFeRDImporter { * @return A String or empty String, if no value was found */ private String getNodeValue(Node node) { - if (node != null) { - if (node.getFirstChild() != null) { - return node.getFirstChild().getNodeValue(); - } - } + if (node != null && node.getFirstChild() != null) { + return node.getFirstChild().getNodeValue(); + } return ""; } @@ -1034,10 +1062,26 @@ public class ZUGFeRDImporter { return new BigDecimal(nodeValue); } catch (final Exception e) { try { - return new BigDecimal(Float.valueOf(nodeValue)); + return BigDecimal.valueOf(Float.valueOf(nodeValue)); } catch (final Exception ex) { return new BigDecimal("0.00"); } } } + private Date tryDate(Node node) { + final String nodeValue = getNodeValue(node); + if (nodeValue.isEmpty()) { + return null; + } + return tryDate(nodeValue); + } + + private static Date tryDate(String toParse) { + final SimpleDateFormat formatter = ZUGFeRDDateFormat.DATE.getFormatter(); + try { + return formatter.parse(toParse); + } catch (final Exception e) { + return null; + } + } } diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/InvoicingPeriodTestCase.java b/library/src/test/java/org/mustangproject/ZUGFeRD/InvoicingPeriodTestCase.java new file mode 100644 index 00000000..42f0c0e0 --- /dev/null +++ b/library/src/test/java/org/mustangproject/ZUGFeRD/InvoicingPeriodTestCase.java @@ -0,0 +1,43 @@ +package org.mustangproject.ZUGFeRD; + +import static org.junit.Assert.assertEquals; + +import java.io.IOException; +import java.nio.charset.Charset; +import java.text.ParseException; +import java.util.Date; + +import org.junit.Test; + +public class InvoicingPeriodTestCase { + @Test + public void readBillingSpecification() throws IOException { + final String file = ResourceUtilities.readFile(Charset.defaultCharset(), + "src/test/resources/factur-x_invoicingPeriod.xml"); + final ZUGFeRDImporter zi = new XRechnungImporter(file.getBytes()); + + // Reading ZUGFeRD + assertEquals(date("20220829"), zi.getLineItemList().get(0).getDetailedDeliveryPeriodFrom()); + assertEquals(date("20220831"), zi.getLineItemList().get(0).getDetailedDeliveryPeriodTo()); + assertEquals(date("20220901"), zi.getLineItemList().get(1).getDetailedDeliveryPeriodFrom()); + assertEquals(date("20220902"), zi.getLineItemList().get(1).getDetailedDeliveryPeriodTo()); + assertEquals(null, zi.getLineItemList().get(2).getDetailedDeliveryPeriodFrom()); + assertEquals(date("20220909"), zi.getLineItemList().get(2).getDetailedDeliveryPeriodTo()); + assertEquals(date("20220826"), zi.getDetailedDeliveryPeriodFrom()); + assertEquals(date("20220902"), zi.getDetailedDeliveryPeriodTo()); + //general asserts + assertEquals("1634.76", zi.getAmount()); + assertEquals("RE1000", zi.getInvoiceID()); + assertEquals("Sell", zi.getSellerTradePartyAddress().getCityName()); + assertEquals("Beier", zi.getBuyerTradePartyName()); + } + + private Date date(String toParse){ + try { + return ZUGFeRDDateFormat.DATE.getFormatter().parse(toParse); + } + catch (final ParseException e) { + return null; + } + } +} diff --git a/library/src/test/resources/factur-x_invoicingPeriod.xml b/library/src/test/resources/factur-x_invoicingPeriod.xml new file mode 100644 index 00000000..13e4c182 --- /dev/null +++ b/library/src/test/resources/factur-x_invoicingPeriod.xml @@ -0,0 +1,219 @@ + + + + + + + urn:cen.eu:en16931:2017 + + + + RE1000 + 380 + + 20220826 + + + Sellerie GmbH +Weg 42 +65432 Sell +DE + + + + + + 1 + + + AWE01J + Suite_Enterprise month yearly + + + + + 959.4000 + 1.0000 + + + 959.4000 + 1.0000 + + + + 1.0000 + + + + VAT + S + 19.00 + + + + 20220829 + + + 20220831 + + + + 959.40 + + + + + + 2 + + + BWP12M + Suite_Plus year monthly + + + + + 54.9500 + 1.0000 + + + 54.9500 + 1.0000 + + + + 1.0000 + + + + VAT + S + 19.00 + + + + 20220901 + + + 20220902 + + + + 54.95 + + + + + + 3 + + + CWS12J + Suite_Starter year yearly + + + + + 359.4000 + 1.0000 + + + 359.4000 + 1.0000 + + + + 1.0000 + + + + VAT + S + 19.00 + + + + 20220909 + + + + 359.40 + + + + + + Sellerie GmbH + + all_suite@test.com all_suite@test.com + + 06661556 + + + all_suite@test.com + + + + 65432 + Weg 42 + Sell + DE + + + DE327606228 + + + + 10010 + Beier + + 55569 + Industriestr. 12 + Musterstadt + DE + + + + + + + 20220826 + + + + + RE1000 + EUR + + 261.01 + VAT + 1373.75 + S + 19.00 + + + + 20220826 + + + 20220902 + + + + Zahlbar ohne Abzug bis 26.08.2022 + + + 1373.75 + 0.00 + 0.00 + 1373.75 + 261.01 + 1634.76 + 0.00 + 1634.76 + + + +