diff --git a/library/src/main/java/org/mustangproject/XMLTools.java b/library/src/main/java/org/mustangproject/XMLTools.java index 4c2877b3..cf3d6386 100644 --- a/library/src/main/java/org/mustangproject/XMLTools.java +++ b/library/src/main/java/org/mustangproject/XMLTools.java @@ -1,6 +1,32 @@ package org.mustangproject; +import java.math.BigDecimal; +import java.math.RoundingMode; + public class XMLTools { + + + public static String nDigitFormat(BigDecimal value, int scale) { + /* + * I needed 123,45, locale independent.I tried + * NumberFormat.getCurrencyInstance().format( 12345.6789 ); but that is locale + * specific.I also tried DecimalFormat df = new DecimalFormat( "0,00" ); + * df.setDecimalSeparatorAlwaysShown(true); df.setGroupingUsed(false); + * DecimalFormatSymbols symbols = new DecimalFormatSymbols(); + * symbols.setDecimalSeparator(','); symbols.setGroupingSeparator(' '); + * df.setDecimalFormatSymbols(symbols); + * + * but that would not switch off grouping. Although I liked very much the + * (incomplete) "BNF diagram" in + * http://docs.oracle.com/javase/tutorial/i18n/format/decimalFormat.html in the + * end I decided to calculate myself and take eur+sparator+cents + * + */ + return value.setScale(scale, RoundingMode.HALF_UP).toPlainString(); + + } + + public static String encodeXML(CharSequence s) { StringBuilder sb = new StringBuilder(); int len = s.length(); diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/LineCalc.java b/library/src/main/java/org/mustangproject/ZUGFeRD/LineCalc.java new file mode 100644 index 00000000..d0ad2238 --- /dev/null +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/LineCalc.java @@ -0,0 +1,39 @@ +package org.mustangproject.ZUGFeRD; + +import java.math.BigDecimal; + +public class LineCalc { + private BigDecimal totalGross; + private BigDecimal priceGross; + private BigDecimal itemTotalNetAmount; + private BigDecimal itemTotalVATAmount; + + public LineCalc(IZUGFeRDExportableItem currentItem) { + BigDecimal multiplicator = currentItem.getProduct().getVATPercent().divide(new BigDecimal(100)) + .add(new BigDecimal(1)); + priceGross = currentItem.getPrice(); // see https://github.com/ZUGFeRD/mustangproject/issues/159 + totalGross = currentItem.getQuantity().multiply(currentItem.getPrice()).divide(currentItem.getBasisQuantity()) + .multiply(multiplicator); + itemTotalNetAmount = currentItem.getQuantity().multiply(currentItem.getPrice()).divide(currentItem.getBasisQuantity()) + .setScale(2, BigDecimal.ROUND_HALF_UP); + itemTotalVATAmount = totalGross.subtract(itemTotalNetAmount); + } + + public BigDecimal getItemTotalNetAmount() { + return itemTotalNetAmount; + } + + public BigDecimal getItemTotalVATAmount() { + return itemTotalVATAmount; + } + + public BigDecimal getItemTotalGrossAmount() { + return itemTotalVATAmount; + } + + public BigDecimal getPriceGross() { + return priceGross; + } + + +} diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD1PullProvider.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD1PullProvider.java index ecec99fb..a63ac46c 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD1PullProvider.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD1PullProvider.java @@ -39,40 +39,6 @@ import java.util.logging.Logger; public class ZUGFeRD1PullProvider implements IXMLProvider, IProfileProvider { - private class LineCalc { - private BigDecimal totalGross; - private BigDecimal priceGross; - private BigDecimal itemTotalNetAmount; - private BigDecimal itemTotalVATAmount; - - public LineCalc(IZUGFeRDExportableItem currentItem) { - BigDecimal multiplicator = currentItem.getProduct().getVATPercent().divide(new BigDecimal(100)) - .add(new BigDecimal(1)); - priceGross = currentItem.getPrice().multiply(multiplicator); - totalGross = currentItem.getQuantity().multiply(currentItem.getPrice()).divide(currentItem.getBasisQuantity()) - .multiply(multiplicator); - itemTotalNetAmount = currentItem.getQuantity().multiply(currentItem.getPrice()).divide(currentItem.getBasisQuantity()) - .setScale(2, BigDecimal.ROUND_HALF_UP); - itemTotalVATAmount = totalGross.subtract(itemTotalNetAmount); - } - - public BigDecimal getItemTotalNetAmount() { - return itemTotalNetAmount; - } - - public BigDecimal getItemTotalVATAmount() { - return itemTotalVATAmount; - } - - public BigDecimal getItemTotalGrossAmount() { - return itemTotalVATAmount; - } - - public BigDecimal getPriceGross() { - return priceGross; - } - - } //// MAIN CLASS @@ -92,41 +58,20 @@ public class ZUGFeRD1PullProvider implements IXMLProvider, IProfileProvider { @Override public void setTest() { } - - public static String nDigitFormat(BigDecimal value, int scale) { - /* - * I needed 123,45, locale independent.I tried - * NumberFormat.getCurrencyInstance().format( 12345.6789 ); but that is locale - * specific.I also tried DecimalFormat df = new DecimalFormat( "0,00" ); - * df.setDecimalSeparatorAlwaysShown(true); df.setGroupingUsed(false); - * DecimalFormatSymbols symbols = new DecimalFormatSymbols(); - * symbols.setDecimalSeparator(','); symbols.setGroupingSeparator(' '); - * df.setDecimalFormatSymbols(symbols); - * - * but that would not switch off grouping. Although I liked very much the - * (incomplete) "BNF diagram" in - * http://docs.oracle.com/javase/tutorial/i18n/format/decimalFormat.html in the - * end I decided to calculate myself and take eur+sparator+cents - * - */ - return value.setScale(scale, RoundingMode.HALF_UP).toPlainString(); - - } - private String vatFormat(BigDecimal value) { - return ZUGFeRD1PullProvider.nDigitFormat(value, 2); + return XMLTools.nDigitFormat(value, 2); } private String currencyFormat(BigDecimal value) { - return ZUGFeRD1PullProvider.nDigitFormat(value, 2); + return XMLTools.nDigitFormat(value, 2); } private String priceFormat(BigDecimal value) { - return ZUGFeRD1PullProvider.nDigitFormat(value, 4); + return XMLTools.nDigitFormat(value, 4); } private String quantityFormat(BigDecimal value) { - return ZUGFeRD1PullProvider.nDigitFormat(value, 4); + return XMLTools.nDigitFormat(value, 4); } @Override @@ -314,81 +259,6 @@ public class ZUGFeRD1PullProvider implements IXMLProvider, IProfileProvider { + " \n" + " \n"; - int lineID = 0; - for (IZUGFeRDExportableItem currentItem : trans.getZFItems()) { - lineID++; - taxCategoryCode=currentItem.getProduct().getTaxCategoryCode(); - if (currentItem.getProduct().getTaxExemptionReason() != null) { - exemptionReason="" + XMLTools.encodeXML(currentItem.getProduct().getTaxExemptionReason()) + ""; - } - - LineCalc lc = new LineCalc(currentItem); - xml = xml + " \n" + - " \n" - + " " + lineID + "\n" //$NON-NLS-2$ - + " \n" - + " \n" - + " \n" - + " " + priceFormat(lc.getPriceGross()) - + "\n" - + " " + quantityFormat(currentItem.getBasisQuantity()) +"\n" - // + " \n" - // + " false\n" - // + " 0.6667\n" - // + " Rabatt\n" - // + " \n" - + " \n" - + " \n" - + " " + priceFormat(currentItem.getPrice()) - + "\n" - + " " + quantityFormat(currentItem.getBasisQuantity()) +"\n" - + " \n" - + " \n" - - - + " \n" - + " " //$NON-NLS-2$ - + quantityFormat(currentItem.getQuantity()) + "\n" - + " \n" - + " \n" - + " \n" - + " VAT\n" - + exemptionReason - + " "+currentItem.getProduct().getTaxCategoryCode()+"\n" - - + " " - + vatFormat(currentItem.getProduct().getVATPercent()) + "\n" - + " \n" - + " \n" - + " " + currencyFormat(lc.getItemTotalNetAmount()) - + "\n" - + " \n"; - if (currentItem.getAdditionalReferencedDocumentID()!=null) { - xml=xml + " "+currentItem.getAdditionalReferencedDocumentID()+"130\n"; - - } - xml=xml + " \n" - + " \n"; - // + " 4012345001235\n" - if (currentItem.getProduct().getSellerAssignedID() != null) { - xml = xml + " " - + XMLTools.encodeXML(currentItem.getProduct().getSellerAssignedID()) + "\n"; - } - if (currentItem.getProduct().getBuyerAssignedID() != null) { - xml = xml + " " - + XMLTools.encodeXML(currentItem.getProduct().getBuyerAssignedID()) + "\n"; - } - xml = xml + " " + XMLTools.encodeXML(currentItem.getProduct().getName()) + "\n" //$NON-NLS-2$ - + " " + XMLTools.encodeXML(currentItem.getProduct().getDescription()) - + "\n" - + " \n" - - + " \n"; - - } - xml = xml + " \n"; if (trans.getReferenceNumber() != null) { xml = xml + " " + XMLTools.encodeXML(trans.getReferenceNumber()) + "\n"; @@ -398,20 +268,13 @@ public class ZUGFeRD1PullProvider implements IXMLProvider, IProfileProvider { if (trans.getOwnForeignOrganisationID()!=null) { xml = xml + " " + XMLTools.encodeXML(trans.getOwnForeignOrganisationID()) + "\n"; } - + if ((trans.getOwnContact()!=null)&&(trans.getOwnContact().getGlobalID()!=null)&&(trans.getOwnContact().getGlobalIDScheme()!=null)) { xml = xml + " " - + XMLTools.encodeXML(trans.getOwnContact().getGlobalID()) + "\n"; + + XMLTools.encodeXML(trans.getOwnContact().getGlobalID()) + "\n"; } xml = xml + " " + XMLTools.encodeXML(trans.getOwnOrganisationName()) + "\n"; //$NON-NLS-2$ - if ((trans.getOwnVATID()!=null)&&(trans.getOwnOrganisationName()!=null)) { - - xml = xml + " \n" + " " - + XMLTools.encodeXML(trans.getOwnVATID()) + "\n" - + " "; - } - if (trans.getOwnContact() != null) { xml = xml + "\n" + " " + XMLTools.encodeXML(trans.getOwnContact().getName()) + "\n"; @@ -430,7 +293,6 @@ public class ZUGFeRD1PullProvider implements IXMLProvider, IProfileProvider { xml = xml + " "; } - xml = xml + " \n" + " " + XMLTools.encodeXML(trans.getOwnZIP()) + "\n" + " " + XMLTools.encodeXML(trans.getOwnStreet()) + "\n" + " " + XMLTools.encodeXML(trans.getOwnLocation()) @@ -444,27 +306,33 @@ public class ZUGFeRD1PullProvider implements IXMLProvider, IProfileProvider { + " \n" + " \n" + " \n"; - // + " GE2020211\n" - // + " 4000001987658\n" - - xml+=getContactAsXML(trans.getRecipient()); - xml += " \n"; + // + " GE2020211\n" + // + " 4000001987658\n" + + xml+=getContactAsXML(trans.getRecipient()); + if ((trans.getOwnVATID()!=null)&&(trans.getOwnOrganisationName()!=null)) { + xml = xml + " \n" + " " + + XMLTools.encodeXML(trans.getOwnVATID()) + "\n" + + " "; + } + + xml += " \n"; if (trans.getBuyerOrderReferencedDocumentID()!=null) { - xml = xml + " \n" - + " " - + XMLTools.encodeXML(trans.getBuyerOrderReferencedDocumentID()) + "\n" - + " \n"; + xml = xml + " \n" + + " " + + XMLTools.encodeXML(trans.getBuyerOrderReferencedDocumentID()) + "\n" + + " \n"; } xml = xml + " \n" + " \n" ; if (this.trans.getDeliveryAddress()!=null) { xml += ""+ - getContactAsXML(this.trans.getDeliveryAddress())+ - ""; + getContactAsXML(this.trans.getDeliveryAddress())+ + ""; } - - xml+= " \n" + + xml+= " \n" + " "; if (trans.getZFDeliveryDate() != null) { @@ -551,26 +419,104 @@ public class ZUGFeRD1PullProvider implements IXMLProvider, IProfileProvider { xml = xml + " \n" + " " + currencyFormat(getTotal()) + "\n" //$NON-NLS-2$ - // currencyID=\"EUR\" + // currencyID=\"EUR\" + " 0.00\n" // currencyID=\"EUR\" + " 0.00\n" // - // currencyID=\"EUR\" + // currencyID=\"EUR\" // + " 5.80\n" // + " 14.73\n" + " " + currencyFormat(getTotal()) + "\n" //$NON-NLS-2$ - // // - // currencyID=\"EUR\" + // // + // currencyID=\"EUR\" + " " + currencyFormat(getTotalGross().subtract(getTotal())) + "\n" + " " + currencyFormat(getTotalGross()) + "\n" //$NON-NLS-2$ - // // - // currencyID=\"EUR\" + // // + // currencyID=\"EUR\" + " " + currencyFormat(getTotalPrepaid()) + "\n" + " " + currencyFormat(getTotalGross().subtract(getTotalPrepaid())) + "\n" //$NON-NLS-2$ - // // - // currencyID=\"EUR\" + // // + // currencyID=\"EUR\" + " \n" + " \n"; + + + int lineID = 0; + for (IZUGFeRDExportableItem currentItem : trans.getZFItems()) { + lineID++; + taxCategoryCode=currentItem.getProduct().getTaxCategoryCode(); + if (currentItem.getProduct().getTaxExemptionReason() != null) { + exemptionReason="" + XMLTools.encodeXML(currentItem.getProduct().getTaxExemptionReason()) + ""; + } + + + LineCalc lc = new LineCalc(currentItem); + xml = xml + " \n" + + " \n" + + " " + lineID + "\n" //$NON-NLS-2$ + + " \n" + + " \n" + + " \n" + + " " + priceFormat(lc.getPriceGross()) + + "\n" + + " " + quantityFormat(currentItem.getBasisQuantity()) +"\n" + // + " \n" + // + " false\n" + // + " 0.6667\n" + // + " Rabatt\n" + // + " \n" + + " \n" + + " \n" + + " " + priceFormat(currentItem.getPrice()) + + "\n" + + " " + quantityFormat(currentItem.getBasisQuantity()) +"\n" + + " \n" + + " \n" + + + + " \n" + + " " //$NON-NLS-2$ + + quantityFormat(currentItem.getQuantity()) + "\n" + + " \n" + + " \n" + + " \n" + + " VAT\n" + + exemptionReason + + " "+currentItem.getProduct().getTaxCategoryCode()+"\n" + + + " " + + vatFormat(currentItem.getProduct().getVATPercent()) + "\n" + + " \n" + + " \n" + + " " + currencyFormat(lc.getItemTotalNetAmount()) + + "\n" + + " \n"; + if (currentItem.getAdditionalReferencedDocumentID()!=null) { + xml=xml + " "+currentItem.getAdditionalReferencedDocumentID()+"130\n"; + + } + xml=xml + " \n" + + " \n"; + // + " 4012345001235\n" + if (currentItem.getProduct().getSellerAssignedID() != null) { + xml = xml + " " + + XMLTools.encodeXML(currentItem.getProduct().getSellerAssignedID()) + "\n"; + } + if (currentItem.getProduct().getBuyerAssignedID() != null) { + xml = xml + " " + + XMLTools.encodeXML(currentItem.getProduct().getBuyerAssignedID()) + "\n"; + } + xml = xml + " " + XMLTools.encodeXML(currentItem.getProduct().getName()) + "\n" //$NON-NLS-2$ + + " " + XMLTools.encodeXML(currentItem.getProduct().getDescription()) + + "\n" + + " \n" + + + " \n"; + + } + // + " \n" // + " \n" // + " \n" diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java index d51a4b43..8b6128d8 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRD2PullProvider.java @@ -38,41 +38,6 @@ import org.mustangproject.XMLTools; public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider { - private class LineCalc { - private BigDecimal totalGross; - private BigDecimal priceGross; - private BigDecimal itemTotalNetAmount; - private BigDecimal itemTotalVATAmount; - - public LineCalc(IZUGFeRDExportableItem currentItem) { - BigDecimal multiplicator = currentItem.getProduct().getVATPercent().divide(new BigDecimal(100)) - .add(new BigDecimal(1)); - priceGross = currentItem.getPrice().multiply(multiplicator); - totalGross = currentItem.getQuantity().multiply(currentItem.getPrice()).divide(currentItem.getBasisQuantity()) - .multiply(multiplicator); - itemTotalNetAmount = currentItem.getQuantity().multiply(currentItem.getPrice()).divide(currentItem.getBasisQuantity()) - .setScale(2, BigDecimal.ROUND_HALF_UP); - itemTotalVATAmount = totalGross.subtract(itemTotalNetAmount); - } - - public BigDecimal getItemTotalNetAmount() { - return itemTotalNetAmount; - } - - public BigDecimal getItemTotalVATAmount() { - return itemTotalVATAmount; - } - - public BigDecimal getItemTotalGrossAmount() { - return itemTotalVATAmount; - } - - public BigDecimal getPriceGross() { - return priceGross; - } - - } - //// MAIN CLASS protected byte[] zugferdData; @@ -92,40 +57,20 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider { public void setTest() { } - public static String nDigitFormat(BigDecimal value, int scale) { - /* - * I needed 123,45, locale independent.I tried - * NumberFormat.getCurrencyInstance().format( 12345.6789 ); but that is locale - * specific.I also tried DecimalFormat df = new DecimalFormat( "0,00" ); - * df.setDecimalSeparatorAlwaysShown(true); df.setGroupingUsed(false); - * DecimalFormatSymbols symbols = new DecimalFormatSymbols(); - * symbols.setDecimalSeparator(','); symbols.setGroupingSeparator(' '); - * df.setDecimalFormatSymbols(symbols); - * - * but that would not switch off grouping. Although I liked very much the - * (incomplete) "BNF diagram" in - * http://docs.oracle.com/javase/tutorial/i18n/format/decimalFormat.html in the - * end I decided to calculate myself and take eur+sparator+cents - * - */ - return value.setScale(scale, RoundingMode.HALF_UP).toPlainString(); - - } - private String vatFormat(BigDecimal value) { - return ZUGFeRD2PullProvider.nDigitFormat(value, 2); + return XMLTools.nDigitFormat(value, 2); } private String currencyFormat(BigDecimal value) { - return ZUGFeRD2PullProvider.nDigitFormat(value, 2); + return XMLTools.nDigitFormat(value, 2); } private String priceFormat(BigDecimal value) { - return ZUGFeRD2PullProvider.nDigitFormat(value, 4); + return XMLTools.nDigitFormat(value, 4); } private String quantityFormat(BigDecimal value) { - return ZUGFeRD2PullProvider.nDigitFormat(value, 4); + return XMLTools.nDigitFormat(value, 4); } @Override diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/BaseTest.java b/library/src/test/java/org/mustangproject/ZUGFeRD/BaseTest.java index 8d3152b6..9695fc0e 100644 --- a/library/src/test/java/org/mustangproject/ZUGFeRD/BaseTest.java +++ b/library/src/test/java/org/mustangproject/ZUGFeRD/BaseTest.java @@ -32,6 +32,7 @@ import java.text.SimpleDateFormat; import java.util.Calendar; import java.util.Date; import java.util.GregorianCalendar; +import org.mustangproject.XMLTools; public class BaseTest extends TestCase { /** @@ -51,15 +52,15 @@ public class BaseTest extends TestCase { } public void testCorrectDigits() { - assertEquals("0.00", ZUGFeRD2PullProvider.nDigitFormat(new BigDecimal(0),2)); - assertEquals("-1.10", ZUGFeRD2PullProvider.nDigitFormat(new BigDecimal("-1.10"),2)); - assertEquals("-1.10", ZUGFeRD2PullProvider.nDigitFormat(new BigDecimal("-1.1"),2)); - assertEquals("-1.01", ZUGFeRD2PullProvider.nDigitFormat(new BigDecimal("-1.01"),2)); - assertEquals("20000123.35", ZUGFeRD2PullProvider.nDigitFormat(new BigDecimal("20000123.3489"),2)); - assertEquals("20000123.34", ZUGFeRD2PullProvider.nDigitFormat(new BigDecimal("20000123.3419"),2)); - assertEquals("12.00", ZUGFeRD2PullProvider.nDigitFormat(new BigDecimal("12"),2)); - assertEquals("12", ZUGFeRD2PullProvider.nDigitFormat(new BigDecimal("12"),0)); - assertEquals("20000123.342", ZUGFeRD2PullProvider.nDigitFormat(new BigDecimal("20000123.3419"),3)); + assertEquals("0.00", XMLTools.nDigitFormat(new BigDecimal(0),2)); + assertEquals("-1.10", XMLTools.nDigitFormat(new BigDecimal("-1.10"),2)); + assertEquals("-1.10", XMLTools.nDigitFormat(new BigDecimal("-1.1"),2)); + assertEquals("-1.01", XMLTools.nDigitFormat(new BigDecimal("-1.01"),2)); + assertEquals("20000123.35", XMLTools.nDigitFormat(new BigDecimal("20000123.3489"),2)); + assertEquals("20000123.34", XMLTools.nDigitFormat(new BigDecimal("20000123.3419"),2)); + assertEquals("12.00", XMLTools.nDigitFormat(new BigDecimal("12"),2)); + assertEquals("12", XMLTools.nDigitFormat(new BigDecimal("12"),0)); + assertEquals("20000123.342", XMLTools.nDigitFormat(new BigDecimal("20000123.3419"),3)); } } diff --git a/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2Test.java b/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2Test.java index b80b8b37..d14257e7 100644 --- a/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2Test.java +++ b/library/src/test/java/org/mustangproject/ZUGFeRD/ZF2Test.java @@ -229,7 +229,7 @@ public class ZF2Test extends MustangReaderTestCase { assertEquals(zi.getLineItemList().get(0).product.getSellerAssignedID(), ""); assertEquals(zi.getLineItemList().get(0).getLineTotalAmount().toString(), "160.00"); assertEquals(zi.getLineItemList().get(0).getQuantity().toString(), "1.0000"); - assertEquals(zi.getLineItemList().get(0).getGrossPrice().toString(), "171.2000"); + assertEquals(zi.getLineItemList().get(0).getGrossPrice().toString(), "160.0000"); assertEquals(zi.getLineItemList().get(0).product.getVATPercent().toString(), "7.00"); assertEquals(zi.getLineItemList().get(0).product.getName(), "Künstlerische Gestaltung (Stunde): Einer Beispielrechnung"); assertEquals(zi.getLineItemList().get(0).product.getDescription(), "");