From 3015de02a5874cbb513e47c0153470dfe729b36d Mon Sep 17 00:00:00 2001 From: Christian Schwerdtfeger Date: Mon, 14 Oct 2019 17:31:32 +0200 Subject: [PATCH] - Added possibility to specify delivery date in "week of year" or "month of year" format, through introduction of new IZUGFeRDDate interface. Keeping backward compatibility by providing both methods in IZUGFeRDExportableTransaction - Added possibility to specify "LineTwo" in Recipient Address - Limited pdfbox version to maximum 2.0.17 because otherwise 3.0.0-SNAPSHOT was pulled in which was broken because of missing ByteArrayDataSource --- pom.xml | 4 +- .../mustangproject/ZUGFeRD/IZUGFeRDDate.java | 13 +++ .../ZUGFeRD/IZUGFeRDExportableContact.java | 9 ++ .../IZUGFeRDExportableTransaction.java | 11 ++ .../ZUGFeRD/ZUGFeRD2PullProvider.java | 27 ++++- .../ZUGFeRD/ZUGFeRDDateFormat.java | 28 +++++ .../ZUGFeRDTransactionModelConverter.java | 21 +++- .../ZUGFeRD/IZUGFeRDDateImpl.java | 30 +++++ .../IZUGFeRDExportableTransactionImpl.java | 11 ++ .../mustangproject/ZUGFeRD/ZF2EdgeTest.java | 12 +- .../ZUGFeRDTransactionModelConverterTest.java | 107 +++++++++++++++++- 11 files changed, 254 insertions(+), 19 deletions(-) create mode 100644 src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDDate.java create mode 100644 src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDDateFormat.java create mode 100644 src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDDateImpl.java diff --git a/pom.xml b/pom.xml index adda2ac2..6b6eb5c0 100644 --- a/pom.xml +++ b/pom.xml @@ -79,12 +79,12 @@ org.apache.pdfbox preflight - [2.0.15,) + [2.0.15,2.0.17] org.apache.pdfbox pdfbox - [2.0.15,) + [2.0.15,2.0.17] org.dom4j diff --git a/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDDate.java b/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDDate.java new file mode 100644 index 00000000..3134a3b3 --- /dev/null +++ b/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDDate.java @@ -0,0 +1,13 @@ +package org.mustangproject.ZUGFeRD; + +import java.util.Date; + +public interface IZUGFeRDDate { + + Date getDate(); + + default ZUGFeRDDateFormat getFormat() { + return ZUGFeRDDateFormat.DATE; + } + +} diff --git a/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableContact.java b/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableContact.java index 289fa0c9..f5312ff8 100644 --- a/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableContact.java +++ b/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableContact.java @@ -124,4 +124,13 @@ public interface IZUGFeRDExportableContact { return null; } + /** + * returns additional address information which is display in xml tag "LineTwo" + * + * @return additional address information + */ + default String getAdditionalAddress() { + return null; + } + } diff --git a/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableTransaction.java b/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableTransaction.java index ba603eb2..51f78131 100644 --- a/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableTransaction.java +++ b/src/main/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableTransaction.java @@ -131,6 +131,7 @@ public interface IZUGFeRDExportableTransaction { * @deprecated use getTradeSettlement * @return an array of IZUGFeRDTradeSettlementPayment */ + @Deprecated default IZUGFeRDTradeSettlementPayment[] getTradeSettlementPayment() { return null; } @@ -231,6 +232,16 @@ public interface IZUGFeRDExportableTransaction { */ Date getDeliveryDate(); + /** + * get delivery date in more specific form. If this and getDeliveryDate() are + * specified, this value will be taken + * + * @return instance holding date and format + */ + default IZUGFeRDDate getZFDeliveryDate() { + return null; + } + /** * get main invoice currency used on the invoice diff --git a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java b/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java index 359c6c00..886f08af 100644 --- a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java +++ b/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java @@ -24,6 +24,7 @@ import java.io.UnsupportedEncodingException; import java.math.BigDecimal; import java.math.RoundingMode; import java.text.SimpleDateFormat; +import java.util.Date; import java.util.HashMap; import java.util.logging.Level; import java.util.logging.Logger; @@ -78,6 +79,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider { private ZUGFeRDConformanceLevel level; private String paymentTermsDescription; + @Override public void setProfile(ZUGFeRDConformanceLevel level) { this.level = level; } @@ -85,6 +87,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider { /** * enables the flag to indicate a test invoice in the XML structure */ + @Override public void setTest() { } @@ -203,6 +206,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider { return hm; } + @Override public String getProfile() { // return "urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_1.2"; return "urn:cen.eu:en16931:2017"; @@ -390,8 +394,11 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider { // + " \n" + " \n" //$NON-NLS-1$ + " " + XMLTools.encodeXML(trans.getRecipient().getZIP()) + "\n" //$NON-NLS-1$ //$NON-NLS-2$ - + " " + XMLTools.encodeXML(trans.getRecipient().getStreet()) + "\n" //$NON-NLS-1$ //$NON-NLS-2$ - + " " + XMLTools.encodeXML(trans.getRecipient().getLocation()) + "\n" //$NON-NLS-1$ //$NON-NLS-2$ + + " " + XMLTools.encodeXML(trans.getRecipient().getStreet()) + "\n"; //$NON-NLS-1$ //$NON-NLS-2$ + if (trans.getRecipient().getAdditionalAddress() != null) { + xml += " " + XMLTools.encodeXML(trans.getRecipient().getAdditionalAddress()) + "\n"; //$NON-NLS-1$ //$NON-NLS-2$ + } + xml += " " + XMLTools.encodeXML(trans.getRecipient().getLocation()) + "\n" //$NON-NLS-1$ //$NON-NLS-2$ + " " + XMLTools.encodeXML(trans.getRecipient().getCountry()) + "\n" //$NON-NLS-1$ //$NON-NLS-2$ + " \n"; //$NON-NLS-1$ if (trans.getRecipient().getVATID() != null) { @@ -406,8 +413,20 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider { // + " \n" + " \n" //$NON-NLS-1$ + " \n" + " \n" - + " " - + zugferdDateFormat.format(trans.getDeliveryDate()) + "\n" + + " "; + + if (trans.getZFDeliveryDate() != null) { + ZUGFeRDDateFormat dateFormat = trans.getZFDeliveryDate().getFormat(); + Date date = trans.getZFDeliveryDate().getDate(); + xml += "" + + dateFormat.getFormatter().format(date) + ""; + } else if (trans.getDeliveryDate() != null) { + xml += "" + zugferdDateFormat.format(trans.getDeliveryDate()) + + ""; + } else { + throw new IllegalStateException("No delivery date provided"); + } + xml += "\n" + " \n" /* * + " \n" + diff --git a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDDateFormat.java b/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDDateFormat.java new file mode 100644 index 00000000..3457fe18 --- /dev/null +++ b/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDDateFormat.java @@ -0,0 +1,28 @@ +package org.mustangproject.ZUGFeRD; + +import java.text.SimpleDateFormat; + +import org.mustangproject.ZUGFeRD.model.DateTimeTypeConstants; + +public enum ZUGFeRDDateFormat { + + MONTH_OF_YEAR(DateTimeTypeConstants.MONTH, new SimpleDateFormat("yyyyMM")), + WEEK_OF_YEAR(DateTimeTypeConstants.WEEK, new SimpleDateFormat("yyyyww")), + DATE(DateTimeTypeConstants.DATE, new SimpleDateFormat("yyyyMMdd")); + + private String dateTimeType; + private SimpleDateFormat formatter; + + private ZUGFeRDDateFormat(String dateTimeType, SimpleDateFormat formatter) { + this.dateTimeType = dateTimeType; + this.formatter = formatter; + } + + public String getDateTimeType() { + return dateTimeType; + } + + public SimpleDateFormat getFormatter() { + return formatter; + } +} diff --git a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDTransactionModelConverter.java b/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDTransactionModelConverter.java index 17331cac..e7fca721 100644 --- a/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDTransactionModelConverter.java +++ b/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDTransactionModelConverter.java @@ -248,6 +248,12 @@ class ZUGFeRDTransactionModelConverter { buyerAddress.setValue(trans.getRecipient().getStreet()); buyerAddressType.setLineOne(buyerAddress); + if (trans.getRecipient().getAdditionalAddress() != null) { + TextType buyerAdditionalAddress = xmlFactory.createTextType(); + buyerAdditionalAddress.setValue(trans.getRecipient().getAdditionalAddress()); + buyerAddressType.setLineTwo(buyerAdditionalAddress); + } + CodeType buyerPostcode = xmlFactory.createCodeType(); buyerPostcode.setValue(trans.getRecipient().getZIP()); buyerAddressType.getPostcodeCode().add(buyerPostcode); @@ -385,9 +391,18 @@ class ZUGFeRDTransactionModelConverter { DateTimeType deliveryDate = xmlFactory.createDateTimeType(); DateTimeType.DateTimeString deliveryDateString = xmlFactory .createDateTimeTypeDateTimeString(); - deliveryDateString.setFormat(DateTimeTypeConstants.DATE); - deliveryDateString.setValue(zugferdDateFormat.format(trans - .getDeliveryDate())); + IZUGFeRDDate zfDeliveryDate = trans.getZFDeliveryDate(); + if (zfDeliveryDate != null) { + ZUGFeRDDateFormat deliveryDateFormat = zfDeliveryDate.getFormat(); + deliveryDateString.setFormat(deliveryDateFormat.getDateTimeType()); + deliveryDateString.setValue( + deliveryDateFormat.getFormatter().format(zfDeliveryDate.getDate())); + } else if (trans.getDeliveryDate() != null) { + deliveryDateString.setFormat(DateTimeTypeConstants.DATE); + deliveryDateString.setValue(zugferdDateFormat.format(trans.getDeliveryDate())); + } else { + throw new IllegalStateException("No delivery date provided"); + } deliveryDate.setDateTimeString(deliveryDateString); deliveryEvent.getOccurrenceDateTime().add(deliveryDate); tradeDelivery.getActualDeliverySupplyChainEvent().add(deliveryEvent); diff --git a/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDDateImpl.java b/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDDateImpl.java new file mode 100644 index 00000000..01a4d19c --- /dev/null +++ b/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDDateImpl.java @@ -0,0 +1,30 @@ +package org.mustangproject.ZUGFeRD; + +import java.util.Date; + +public class IZUGFeRDDateImpl implements IZUGFeRDDate { + + private Date date; + private ZUGFeRDDateFormat format = ZUGFeRDDateFormat.DATE; + + public IZUGFeRDDateImpl setDate(Date date) { + this.date = date; + return this; + } + + public IZUGFeRDDateImpl setFormat(ZUGFeRDDateFormat format) { + this.format = format; + return this; + } + + @Override + public Date getDate() { + return date; + } + + @Override + public ZUGFeRDDateFormat getFormat() { + return format; + } + +} diff --git a/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableTransactionImpl.java b/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableTransactionImpl.java index f1d5d001..eda39ae0 100644 --- a/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableTransactionImpl.java +++ b/src/test/java/org/mustangproject/ZUGFeRD/IZUGFeRDExportableTransactionImpl.java @@ -32,6 +32,7 @@ public class IZUGFeRDExportableTransactionImpl implements IZUGFeRDExportableTran private IZUGFeRDExportableItem[] zFItems; private IZUGFeRDExportableContact recipient; private IZUGFeRDTradeSettlementPayment[] settlementPayments; + private IZUGFeRDDate zfDeliveryDate; private String ownTaxID; private String ownVATID; private String ownOrganisationName; @@ -149,6 +150,11 @@ public class IZUGFeRDExportableTransactionImpl implements IZUGFeRDExportableTran return referenceNumber; } + @Override + public IZUGFeRDDate getZFDeliveryDate() { + return zfDeliveryDate; + } + public IZUGFeRDExportableTransactionImpl setNumber(String number) { this.number = number; return this; @@ -234,6 +240,11 @@ public class IZUGFeRDExportableTransactionImpl implements IZUGFeRDExportableTran return this; } + public IZUGFeRDExportableTransactionImpl setZfDeliveryDate(IZUGFeRDDate zfDeliveryDate) { + this.zfDeliveryDate = zfDeliveryDate; + return this; + } + public IZUGFeRDExportableTransactionImpl setCurrency(String currency) { this.currency = currency; return this; diff --git a/src/test/java/org/mustangproject/ZUGFeRD/ZF2EdgeTest.java b/src/test/java/org/mustangproject/ZUGFeRD/ZF2EdgeTest.java index b68f5bd2..54955fa3 100644 --- a/src/test/java/org/mustangproject/ZUGFeRD/ZF2EdgeTest.java +++ b/src/test/java/org/mustangproject/ZUGFeRD/ZF2EdgeTest.java @@ -19,11 +19,6 @@ *********************************************************************** */ package org.mustangproject.ZUGFeRD; -import junit.framework.Test; -import junit.framework.TestSuite; -import org.junit.FixMethodOrder; -import org.junit.runners.MethodSorters; - import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; @@ -33,6 +28,12 @@ import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; +import org.junit.FixMethodOrder; +import org.junit.runners.MethodSorters; + +import junit.framework.Test; +import junit.framework.TestSuite; + @FixMethodOrder(MethodSorters.NAME_ASCENDING) public class ZF2EdgeTest extends MustangReaderTestCase implements IZUGFeRDExportableTransaction { final String TARGET_PDF = "./target/testout-ZF2newEdge.pdf"; @@ -286,7 +287,6 @@ public class ZF2EdgeTest extends MustangReaderTestCase implements IZUGFeRDExport try { assertEquals(zi.getVersion(), 2); } catch (Exception e) { - // TODO Auto-generated catch block e.printStackTrace(); } diff --git a/src/test/java/org/mustangproject/ZUGFeRD/ZUGFeRDTransactionModelConverterTest.java b/src/test/java/org/mustangproject/ZUGFeRD/ZUGFeRDTransactionModelConverterTest.java index 5497d282..1f1a071d 100644 --- a/src/test/java/org/mustangproject/ZUGFeRD/ZUGFeRDTransactionModelConverterTest.java +++ b/src/test/java/org/mustangproject/ZUGFeRD/ZUGFeRDTransactionModelConverterTest.java @@ -18,14 +18,15 @@ *********************************************************************** */ package org.mustangproject.ZUGFeRD; -import org.junit.Test; -import org.mustangproject.ZUGFeRD.model.CrossIndustryDocumentType; - -import javax.xml.bind.JAXBElement; import java.math.BigDecimal; import java.util.Date; import java.util.GregorianCalendar; +import javax.xml.bind.JAXBElement; + +import org.junit.Test; +import org.mustangproject.ZUGFeRD.model.CrossIndustryDocumentType; + public class ZUGFeRDTransactionModelConverterTest { @Test public void convertToModel_convertsMinimalTransactionToValidXml() throws Exception { @@ -65,10 +66,108 @@ public class ZUGFeRDTransactionModelConverterTest { // evaluation ZUGFeRDXMLAssert.assertValidZugferd(actual); } + + @Test + public void convertToModel_convertsWithDateFormatToValidXml() throws Exception { + // setup + IZUGFeRDExportableTransaction transaction = new IZUGFeRDExportableTransactionImpl() + .setIssueDate(createDate(2000, 1, 1)) + .setZfDeliveryDate(createZfDate(2000, 1, 2, ZUGFeRDDateFormat.DATE)).setDueDate(createDate(2000, 1, 3)) + .setNumber("num") + .setRecipient(new IZUGFeRDExportableContactImpl().setName("recipient name") + .setStreet("recipient street").setLocation("recipient city").setCountry("recipient country")) + .setOwnOrganisationName("own org").setOwnStreet("own street").setOwnCountry("own country") + .setOwnLocation("own city") + .setTradeSettlementPayment(new IZUGFeRDTradeSettlementPaymentImpl().setOwnBankName("own bank")) + .setZFItems(new IZUGFeRDExportableItemImpl() + .setProduct(new IZUGFeRDExportableProductImpl().setVatPercent(new BigDecimal("1.19")) + .setName("product name").setDescription("product description").setUnit("product unit")) + .setQuantity(BigDecimal.ONE).setPrice(BigDecimal.TEN)); + + // execution + final JAXBElement actual = new ZUGFeRDTransactionModelConverter(transaction) + .convertToModel(); + + // evaluation + ZUGFeRDXMLAssert.assertValidZugferd(actual); + } + + @Test + public void convertToModel_convertsWithWeekFormatToValidXml() throws Exception { + // setup + IZUGFeRDExportableTransaction transaction = new IZUGFeRDExportableTransactionImpl() + .setIssueDate(createDate(2000, 1, 1)) + .setZfDeliveryDate(createZfDate(2000, 1, 2, ZUGFeRDDateFormat.WEEK_OF_YEAR)) + .setDueDate(createDate(2000, 1, 3)).setNumber("num") + .setRecipient(new IZUGFeRDExportableContactImpl().setName("recipient name") + .setStreet("recipient street").setLocation("recipient city").setCountry("recipient country")) + .setOwnOrganisationName("own org").setOwnStreet("own street").setOwnCountry("own country") + .setOwnLocation("own city") + .setTradeSettlementPayment(new IZUGFeRDTradeSettlementPaymentImpl().setOwnBankName("own bank")) + .setZFItems(new IZUGFeRDExportableItemImpl() + .setProduct(new IZUGFeRDExportableProductImpl().setVatPercent(new BigDecimal("1.19")) + .setName("product name").setDescription("product description").setUnit("product unit")) + .setQuantity(BigDecimal.ONE).setPrice(BigDecimal.TEN)); + + // execution + final JAXBElement actual = new ZUGFeRDTransactionModelConverter(transaction) + .convertToModel(); + + // evaluation + ZUGFeRDXMLAssert.assertValidZugferd(actual); + } + + @Test + public void convertToModel_convertsWithMonthFormatToValidXml() throws Exception { + // setup + IZUGFeRDExportableTransaction transaction = new IZUGFeRDExportableTransactionImpl() + .setIssueDate(createDate(2000, 1, 1)) + .setZfDeliveryDate(createZfDate(2000, 1, 2, ZUGFeRDDateFormat.MONTH_OF_YEAR)) + .setDueDate(createDate(2000, 1, 3)) + .setNumber("num") + .setRecipient(new IZUGFeRDExportableContactImpl() + .setName("recipient name") + .setStreet("recipient street") + .setLocation("recipient city") + .setCountry("recipient country") + ) + .setOwnOrganisationName("own org") + .setOwnStreet("own street") + .setOwnCountry("own country") + .setOwnLocation("own city") + .setTradeSettlementPayment(new IZUGFeRDTradeSettlementPaymentImpl().setOwnBankName("own bank")) + .setZFItems( + new IZUGFeRDExportableItemImpl() + .setProduct(new IZUGFeRDExportableProductImpl() + .setVatPercent(new BigDecimal("1.19")) + .setName("product name") + .setDescription("product description") + .setUnit("product unit") + ) + .setQuantity(BigDecimal.ONE) + .setPrice(BigDecimal.TEN) + ); + + // execution + final JAXBElement actual = + new ZUGFeRDTransactionModelConverter(transaction).convertToModel(); + + // evaluation + ZUGFeRDXMLAssert.assertValidZugferd(actual); + } private static Date createDate(int year, int month, int day) { final GregorianCalendar calendar = new GregorianCalendar(); calendar.set(year, month - 1, day); return calendar.getTime(); } + + private static IZUGFeRDDate createZfDate(int year, int month, int day, ZUGFeRDDateFormat format) { + final GregorianCalendar calendar = new GregorianCalendar(); + calendar.set(year, month - 1, day); + IZUGFeRDDateImpl date = new IZUGFeRDDateImpl(); + date.setDate(calendar.getTime()); + date.setFormat(format); + return date; + } }