diff --git a/History.md b/History.md index 248a960c..ccc1d053 100644 --- a/History.md +++ b/History.md @@ -1,3 +1,10 @@ +595 +591 +577 +575 +573 +601 + 2.15.1 ======= - #566 Failed to parse PDF - Could not reproduce the invoice diff --git a/Mustang-CLI/src/main/java/org/mustangproject/commandline/FileChecker.java b/Mustang-CLI/src/main/java/org/mustangproject/commandline/FileChecker.java index 2a587c72..e0899108 100644 --- a/Mustang-CLI/src/main/java/org/mustangproject/commandline/FileChecker.java +++ b/Mustang-CLI/src/main/java/org/mustangproject/commandline/FileChecker.java @@ -51,7 +51,9 @@ public class FileChecker { if ((!isPDF) && (!thisRun.shallIgnoreFileExt())) { return false; } - ZUGFeRDImporter zi = new ZUGFeRDImporter(filename); + ZUGFeRDImporter zi = new ZUGFeRDImporter(); + zi.doIgnoreCalculationErrors(); + zi.setPDFFilename(filename); try { if (zi.canParse()) { thisRun.incZUGFeRDCount(zi.getVersion()); diff --git a/library/src/main/java/org/mustangproject/IncludedNote.java b/library/src/main/java/org/mustangproject/IncludedNote.java index db34e793..0bcf3133 100644 --- a/library/src/main/java/org/mustangproject/IncludedNote.java +++ b/library/src/main/java/org/mustangproject/IncludedNote.java @@ -9,77 +9,72 @@ import com.fasterxml.jackson.annotation.JsonInclude; @JsonIgnoreProperties(ignoreUnknown = true) @JsonInclude(JsonInclude.Include.NON_EMPTY) public class IncludedNote { - private String content; + private String content; - private SubjectCode subjectCode; + private SubjectCode subjectCode; - private static final String INCLUDE_START = ""; - private static final String INCLUDE_END = ""; - private static final String CONTENT_START = ""; - private static final String CONTENT_END = ""; - private static final String SUBJECT_CODE_START = ""; - private static final String SUBJECT_CODE_END = ""; + private static final String INCLUDE_START = ""; + private static final String INCLUDE_END = ""; + private static final String CONTENT_START = ""; + private static final String CONTENT_END = ""; + private static final String SUBJECT_CODE_START = ""; + private static final String SUBJECT_CODE_END = ""; - public IncludedNote(String content, SubjectCode subjectCode) { - this.content = content; - this.subjectCode = subjectCode; - } + public IncludedNote(String content, SubjectCode subjectCode) { + this.content = content; + this.subjectCode = subjectCode; + } /** * bean constructor */ - public IncludedNote() { + public IncludedNote() { } - public static IncludedNote generalNote(String content) { - return new IncludedNote(content, SubjectCode.AAI); - } + public static IncludedNote generalNote(String content) { + return new IncludedNote(content, SubjectCode.AAI); + } - public static IncludedNote regulatoryNote(String content) { - return new IncludedNote(content, SubjectCode.REG); - } + public static IncludedNote regulatoryNote(String content) { + return new IncludedNote(content, SubjectCode.REG); + } - public static IncludedNote legalNote(String content) { - return new IncludedNote(content, SubjectCode.ABL); - } + public static IncludedNote legalNote(String content) { + return new IncludedNote(content, SubjectCode.ABL); + } - public static IncludedNote customsNote(String content) { - return new IncludedNote(content, SubjectCode.CUS); - } + public static IncludedNote customsNote(String content) { + return new IncludedNote(content, SubjectCode.CUS); + } - public static IncludedNote sellerNote(String content) { - return new IncludedNote(content, SubjectCode.SUR); - } + public static IncludedNote sellerNote(String content) { + return new IncludedNote(content, SubjectCode.SUR); + } - public static IncludedNote taxNote(String content) { - return new IncludedNote(content, SubjectCode.TXD); - } + public static IncludedNote taxNote(String content) { + return new IncludedNote(content, SubjectCode.TXD); + } - public static IncludedNote introductionNote(String content) { - return new IncludedNote(content, SubjectCode.ACY); - } + public static IncludedNote introductionNote(String content) { + return new IncludedNote(content, SubjectCode.ACY); + } - public static IncludedNote discountBonusNote(String content) { - return new IncludedNote(content, SubjectCode.AAK); - } + public static IncludedNote discountBonusNote(String content) { + return new IncludedNote(content, SubjectCode.AAK); + } - public static IncludedNote unspecifiedNote(String content) { - return new IncludedNote(content, null); - } + public static IncludedNote unspecifiedNote(String content) { + return new IncludedNote(content, null); + } - public String getContent() { - return content; - } + public String getContent() { + return content; + } - public IncludedNote setContent(String content) { - this.content = content; - return this; -} - - public SubjectCode getSubjectCode() { - return subjectCode; - } + public SubjectCode getSubjectCode() { + return subjectCode; + } public IncludedNote setSubjectCode(SubjectCode subjectCode) { @@ -93,13 +88,13 @@ public class IncludedNote { } - public String toCiiXml(){ - String result = INCLUDE_START + CONTENT_START + - XMLTools.encodeXML(getContent() )+ CONTENT_END; - if (getSubjectCode() != null) { - result += SUBJECT_CODE_START + getSubjectCode() + SUBJECT_CODE_END; - } - return result + INCLUDE_END; - } - + public String toCiiXml() { + String result = INCLUDE_START + CONTENT_START + + XMLTools.encodeXML(getContent()) + CONTENT_END; + if (getSubjectCode() != null) { + result += SUBJECT_CODE_START + getSubjectCode() + SUBJECT_CODE_END; + } + return result + INCLUDE_END; + } + } diff --git a/library/src/main/java/org/mustangproject/Product.java b/library/src/main/java/org/mustangproject/Product.java index 83cf4543..cc19932d 100644 --- a/library/src/main/java/org/mustangproject/Product.java +++ b/library/src/main/java/org/mustangproject/Product.java @@ -23,9 +23,9 @@ import java.util.Map; public class Product implements IZUGFeRDExportableProduct { protected String unit, name, sellerAssignedID, buyerAssignedID; - protected String description=""; - protected String taxExemptionReason=null; - protected String taxCategoryCode=null; + protected String description = ""; + protected String taxExemptionReason = null; + protected String taxCategoryCode = null; protected BigDecimal VATPercent; protected boolean isReverseCharge = false; protected boolean isIntraCommunitySupply = false; @@ -61,8 +61,6 @@ public class Product implements IZUGFeRDExportableProduct { }); - - nodeMap.getAsString("SellerAssignedID").ifPresent(this::setSellerAssignedID); nodeMap.getAsString("BuyerAssignedID").ifPresent(this::setBuyerAssignedID); nodeMap.getAsString("Name").ifPresent(this::setName); @@ -155,7 +153,7 @@ public class Product implements IZUGFeRDExportableProduct { * @param taxExemptionReasonText String e.g. Kleinunternehmer gemäß §19 UStG https://github.com/ZUGFeRD/mustangproject/issues/463 * @return fluent setter */ - public Product setTaxExemptionReason(String taxExemptionReasonText) { + public Product setTaxExemptionReason(String taxExemptionReasonText) { taxExemptionReason = taxExemptionReasonText; return this; } @@ -177,7 +175,7 @@ public class Product implements IZUGFeRDExportableProduct { * @param code e.g. S (normal tax), Z=zero rated, E (e.g. small business) or K (intrra community supply) see also https://github.com/ZUGFeRD/mustangproject/issues/463 * @return fluent setter */ - public Product setTaxCategoryCode(String code) { + public Product setTaxCategoryCode(String code) { taxCategoryCode = code; return this; } @@ -304,18 +302,22 @@ public class Product implements IZUGFeRDExportableProduct { * @return fluent setter */ public Product setVATPercent(BigDecimal VATPercent) { - this.VATPercent = VATPercent; + if (VATPercent == null) { + this.VATPercent = BigDecimal.ZERO; + } else { + this.VATPercent = VATPercent; + } return this; } @Override public String getCountryOfOrigin() { - return this.countryOfOrigin; + return this.countryOfOrigin; } public Product setCountryOfOrigin(String countryOfOrigin) { - this.countryOfOrigin = countryOfOrigin; - return this; + this.countryOfOrigin = countryOfOrigin; + return this; } @Override @@ -328,16 +330,16 @@ public class Product implements IZUGFeRDExportableProduct { } public Product setAttributes(Map attributes) { - this.attributes.clear(); + this.attributes.clear(); if (attributes != null) { this.attributes.putAll(attributes); } - return this; + return this; } - public Product addAttribute(String name, String value ) { - this.attributes.put(name, value); - return this; + public Product addAttribute(String name, String value) { + this.attributes.put(name, value); + return this; } @Override diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/LineCalculator.java b/library/src/main/java/org/mustangproject/ZUGFeRD/LineCalculator.java index 2f997991..e319ec73 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/LineCalculator.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/LineCalculator.java @@ -44,12 +44,18 @@ public class LineCalculator { BigDecimal multiplicator = vatPercent.divide(BigDecimal.valueOf(100)); priceGross = currentItem.getPrice(); // see https://github.com/ZUGFeRD/mustangproject/issues/159 price = priceGross.subtract(allowance).add(charge); + + BigDecimal quantity=BigDecimal.ZERO; + if ((currentItem!=null)&&(currentItem.getQuantity()!=null)) { + quantity=currentItem.getQuantity(); + } + // Division/Zero occurred here. // Used the setScale only because that's also done in getBasisQuantity BigDecimal basisQuantity = currentItem.getBasisQuantity().compareTo(BigDecimal.ZERO) == 0 ? BigDecimal.ONE.setScale(4) : currentItem.getBasisQuantity(); - itemTotalNetAmount = currentItem.getQuantity().multiply(getPrice()).divide(basisQuantity, 18, RoundingMode.HALF_UP) + itemTotalNetAmount = quantity.multiply(getPrice()).divide(basisQuantity, 18, RoundingMode.HALF_UP) .subtract(allowanceItemTotal).setScale(2, RoundingMode.HALF_UP); itemTotalVATAmount = itemTotalNetAmount.multiply(multiplicator); } diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/TransactionCalculator.java b/library/src/main/java/org/mustangproject/ZUGFeRD/TransactionCalculator.java index 0b7ca5e3..8740e157 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/TransactionCalculator.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/TransactionCalculator.java @@ -167,7 +167,11 @@ public class TransactionCalculator implements IAbsoluteValueProvider { final String vatDueDateTypeCode = trans.getVATDueDateTypeCode(); for (IZUGFeRDExportableItem currentItem : trans.getZFItems()) { - BigDecimal percent = currentItem.getProduct().getVATPercent(); + BigDecimal percent = null; + if (currentItem.getProduct()!=null) + { + percent=currentItem.getProduct().getVATPercent(); + } if (percent != null) { LineCalculator lc = new LineCalculator(currentItem); VATAmount itemVATAmount = new VATAmount(lc.getItemTotalNetAmount(), lc.getItemTotalVATAmount(), diff --git a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java index 8833161d..abff63bb 100644 --- a/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java +++ b/library/src/main/java/org/mustangproject/ZUGFeRD/ZUGFeRDInvoiceImporter.java @@ -558,7 +558,10 @@ public class ZUGFeRDInvoiceImporter { // UBL... number = extractString("//*[local-name()=\"Invoice\"]/*[local-name()=\"ID\"]").trim(); typeCode = extractString("//*[local-name()=\"Invoice\"]/*[local-name()=\"InvoiceTypeCode\"]").trim(); - issueDate = new SimpleDateFormat("yyyy-MM-dd").parse(extractString("//*[local-name()=\"Invoice\"]/*[local-name()=\"IssueDate\"]").trim()); + String issueDateStr = extractString("//*[local-name()=\"Invoice\"]/*[local-name()=\"IssueDate\"]").trim(); + if (issueDateStr.length()>0) { + issueDate = new SimpleDateFormat("yyyy-MM-dd").parse(issueDateStr); + } String dueDt = extractString("//*[local-name()=\"Invoice\"]/*[local-name()=\"DueDate\"]").trim(); if (dueDt.length() > 0) { dueDate = new SimpleDateFormat("yyyy-MM-dd").parse(dueDt); @@ -777,7 +780,7 @@ public class ZUGFeRDInvoiceImporter { } - zpp.setDueDate(dueDate).setDeliveryDate(deliveryDate).setIssueDate(issueDate).setSender(new TradeParty(SellerNodes)).setRecipient(new TradeParty(BuyerNodes)).setNumber(number).setDocumentCode(typeCode); + zpp.setIssueDate(issueDate).setDueDate(dueDate).setDeliveryDate(deliveryDate).setSender(new TradeParty(SellerNodes)).setRecipient(new TradeParty(BuyerNodes)).setNumber(number).setDocumentCode(typeCode); if ((directDebitMandateID != null) && (IBAN != null)) { DirectDebit d = new DirectDebit(IBAN, directDebitMandateID); diff --git a/library/src/main/java/org/mustangproject/util/NodeMap.java b/library/src/main/java/org/mustangproject/util/NodeMap.java index 46b82a9a..77064d07 100644 --- a/library/src/main/java/org/mustangproject/util/NodeMap.java +++ b/library/src/main/java/org/mustangproject/util/NodeMap.java @@ -106,7 +106,14 @@ public class NodeMap { * @return the text content of the matching node, converted to BigDecimal */ public Optional getAsBigDecimal(String... localNames) { - return getNode(localNames).map(Node::getTextContent).map(s->new BigDecimal(s.trim())); + return getNode(localNames).map(Node::getTextContent).map(s->{ + try { + return new BigDecimal(s.trim()); + } catch (NumberFormatException e) { + return null; + } + + }); } /**