Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement input stream validation starting from 2.8.0 #378

Closed
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
secondd UBL test
jstaerk committed Sep 12, 2023
commit 6f0139d28a2f69147181f095d98429afe390824e
Original file line number Diff line number Diff line change
@@ -413,11 +413,8 @@ public static void main(String[] args) {
} else if ((action != null) && (action.equals("a3only"))) {
performConvert(sourceName, outName);
optionsRecognized = true;
} else if ((action != null) && (action.equals("pdf"))) {
performVisualization(sourceName, lang, outName, true);
optionsRecognized = true;
} else if ((action != null) && (action.equals("visualize"))) {
performVisualization(sourceName, lang, outName, false);
performVisualization(sourceName, lang, outName);
optionsRecognized = true;
} else if ((action != null) && (action.equals("upgrade"))) {
performUpgrade(sourceName, outName);
33 changes: 31 additions & 2 deletions library/src/main/java/org/mustangproject/Item.java
Original file line number Diff line number Diff line change
@@ -84,20 +84,49 @@ public Item(NodeList itemChilds, boolean recalcPrice) {
}
}
}
if ((currentUBLItemChildNode.getLocalName() != null) && (currentUBLItemChildNode.getLocalName().equals("SellersItemIdentification"))) {
for (Node currentUBLSellerIDNodes : XMLTools.asList(currentUBLItemChildNode.getChildNodes())) {
if ((currentUBLSellerIDNodes.getLocalName() != null) && (currentUBLSellerIDNodes.getLocalName().equals("ID"))) {
sellerAssignedID = currentUBLSellerIDNodes.getTextContent();
}
}
}
}
}

if ((lineTrade != null) && (lineTrade.equals("Price"))) {
// ubl
// PriceAmount with currencyID and BaseQuantity with unitCode
NodeList UBLpriceChilds = itemChilds.item(itemChildIndex).getChildNodes();
boolean isAllowance=true;
String allowanceCharge="";
for (Node currentUBLPriceChildNode : XMLTools.asList(UBLpriceChilds)) {

if ((currentUBLPriceChildNode.getLocalName() != null) && (currentUBLPriceChildNode.getLocalName().equals("PriceAmount"))) {
price = currentUBLPriceChildNode.getTextContent();
}
if ((currentUBLPriceChildNode.getLocalName() != null) && (currentUBLPriceChildNode.getLocalName().equals("BaseQuantity"))) {
basisQuantity = currentUBLPriceChildNode.getTextContent();
}
}/* not needed because already reflected in net price
if ((currentUBLPriceChildNode.getLocalName() != null) && (currentUBLPriceChildNode.getLocalName().equals("AllowanceCharge"))) {
for (Node currentUBLAllowanceChildNode : XMLTools.asList(currentUBLPriceChildNode.getChildNodes())) {
if ((currentUBLAllowanceChildNode.getLocalName()!=null)&&(currentUBLAllowanceChildNode.getLocalName().equals("ChargeIndicator"))) {
if (currentUBLAllowanceChildNode.getTextContent().equalsIgnoreCase("true")) {
isAllowance=false;
}
}
if ((currentUBLAllowanceChildNode.getLocalName()!=null)&&(currentUBLAllowanceChildNode.getLocalName().equals("Amount"))) {
allowanceCharge=currentUBLAllowanceChildNode.getTextContent();
}


}
if (isAllowance) {
// addAllowance(new Allowance(new BigDecimal(allowanceCharge)));
} else {
// addAllowance(new Charge(new BigDecimal(allowanceCharge)));
}
}*/
}

}
@@ -187,7 +216,7 @@ public Item(NodeList itemChilds, boolean recalcPrice) {
}
if ((tradeProductChilds.item(tradeProductChildIndex).getLocalName() != null)
&& (tradeProductChilds.item(tradeProductChildIndex).getLocalName()
.equals("SellerAssignedID"))) {
.equals("SellerAssignedID") ) ) {
sellerAssignedID = tradeProductChilds.item(tradeProductChildIndex).getTextContent();
}
if ((tradeProductChilds.item(tradeProductChildIndex).getLocalName() != null)
Original file line number Diff line number Diff line change
@@ -115,12 +115,30 @@ public Invoice extractInto(Invoice zpp) throws XPathExpressionException, ParseEx
{
// UBL...
number = extractString("//*[local-name()=\"Invoice\"]/*[local-name()=\"ID\"]").trim();
issueDate=new SimpleDateFormat("yyyy-MM-dd")
.parse(extractString("//*[local-name()=\"Invoice\"]/*[local-name()=\"IssueDate\"]").trim());
dueDate=new SimpleDateFormat("yyyy-MM-dd")
.parse(extractString("//*[local-name()=\"Invoice\"]/*[local-name()=\"DueDate\"]").trim());
deliveryDate=new SimpleDateFormat("yyyy-MM-dd")
.parse(extractString("//*[local-name()=\"Delivery\"]/*[local-name()=\"ActualDeliveryDate\"]").trim());
String issueDateStr=extractString("//*[local-name()=\"Invoice\"]/*[local-name()=\"IssueDate\"]").trim();
if (!issueDateStr.equals("")) {
issueDate=new SimpleDateFormat("yyyy-MM-dd")
.parse(issueDateStr);
}
// else there is hopefully a invoice period
String issuePeriodFrom=extractString("//*[local-name()=\"InvoicePeriod\"]/*[local-name()=\"StartDate\"]").trim();
String issuePeriodTo=extractString("//*[local-name()=\"InvoicePeriod\"]/*[local-name()=\"EndDate\"]").trim();
if (!issuePeriodFrom.equals("")&&!issuePeriodTo.equals("")) {
zpp.setDetailedDeliveryPeriod(new SimpleDateFormat("yyyy-MM-dd").parse(issuePeriodFrom), new SimpleDateFormat("yyyy-MM-dd").parse(issuePeriodTo));

}


String dueDateStr=extractString("//*[local-name()=\"Invoice\"]/*[local-name()=\"DueDate\"]").trim();
if (!dueDateStr.equals("")) {
dueDate = new SimpleDateFormat("yyyy-MM-dd")
.parse(dueDateStr);
}
String deliveryDateStr=extractString("//*[local-name()=\"Delivery\"]/*[local-name()=\"ActualDeliveryDate\"]").trim();
if (!deliveryDateStr.equals("")) {
deliveryDate = new SimpleDateFormat("yyyy-MM-dd")
.parse(deliveryDateStr);
}
}
xpr = xpath.compile("//*[local-name()=\"ApplicableHeaderTradeDelivery\"]");
NodeList headerTradeDeliveryNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
@@ -157,7 +175,7 @@ public Invoice extractInto(Invoice zpp) throws XPathExpressionException, ParseEx
}
}

xpr = xpath.compile("//*[local-name()=\"ApplicableHeaderTradeAgreement\"]");
xpr = xpath.compile("//*[local-name()=\"ApplicableHeaderTradeAgreement\"]|//*[local-name()=\"OrderReference\"]");
NodeList headerTradeAgreementNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
String buyerOrderIssuerAssignedID = null;
String sellerOrderIssuerAssignedID = null;
@@ -197,6 +215,15 @@ public Invoice extractInto(Invoice zpp) throws XPathExpressionException, ParseEx

}

if (sellerOrderIssuerAssignedID==null) {
//UBL?
sellerOrderIssuerAssignedID=extractString("//*[local-name()=\"OrderReference\"]/*[local-name()=\"SalesOrderID\"]");
}

if (buyerOrderIssuerAssignedID==null) {
//UBL?
buyerOrderIssuerAssignedID=extractString("//*[local-name()=\"OrderReference\"]/*[local-name()=\"ID\"]");
}

xpr = xpath.compile("//*[local-name()=\"ApplicableHeaderTradeSettlement\"]|//*[local-name()=\"ApplicableSupplyChainTradeSettlement\"]");
NodeList headerTradeSettlementNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
@@ -269,11 +296,11 @@ public Invoice extractInto(Invoice zpp) throws XPathExpressionException, ParseEx
// be read,
// so the invoice remains arithmetically correct
// -> parse document level charges+allowances
xpr = xpath.compile("//*[local-name()=\"SpecifiedTradeAllowanceCharge\"]");
xpr = xpath.compile("//*[local-name()=\"SpecifiedTradeAllowanceCharge\"]|//*[local-name()=\"Invoice\"]/*[local-name()=\"AllowanceCharge\"]");
NodeList chargeNodes = (NodeList) xpr.evaluate(getDocument(), XPathConstants.NODESET);
for (int i = 0; i < chargeNodes.getLength(); i++) {
NodeList chargeNodeChilds = chargeNodes.item(i).getChildNodes();
boolean isCharge = true;
Boolean isCharge = null;
String chargeAmount = null;
String reason = null;
String taxPercent = null;
@@ -288,28 +315,42 @@ public Invoice extractInto(Invoice zpp) throws XPathExpressionException, ParseEx
if ((indicatorChilds.item(indicatorChildIndex).getLocalName() != null)
&& (indicatorChilds.item(indicatorChildIndex).getLocalName()
.equals("Indicator"))) {
isCharge = indicatorChilds.item(indicatorChildIndex).getTextContent()
.equalsIgnoreCase("true");
if (indicatorChilds.item(indicatorChildIndex).getTextContent()
.equalsIgnoreCase("true")) {
isCharge=Boolean.TRUE;
} else {
isCharge=Boolean.FALSE;
}
}
}
if (isCharge==null) {
// ubl (has no indicator)
if (chargeNodeChilds.item(chargeChildIndex).getTextContent()
.equalsIgnoreCase("true")) {
isCharge=Boolean.TRUE;
} else {
isCharge=Boolean.FALSE;
}
}
} else if (chargeChildName.equals("ActualAmount")) {
} else if ((chargeChildName.equals("ActualAmount"))||(chargeChildName.equals("Amount"))) {
// ActualAmount is CII, Amount is UBL
chargeAmount = chargeNodeChilds.item(chargeChildIndex).getTextContent();
} else if (chargeChildName.equals("Reason")) {
reason = chargeNodeChilds.item(chargeChildIndex).getTextContent();
} else if (chargeChildName.equals("CategoryTradeTax")) {
} else if (chargeChildName.equals("CategoryTradeTax")||chargeChildName.equals("TaxCategory")/*UBL*/) {
NodeList taxChilds = chargeNodeChilds.item(chargeChildIndex).getChildNodes();
for (int taxChildIndex = 0; taxChildIndex < taxChilds.getLength(); taxChildIndex++) {
String taxItemName = taxChilds.item(taxChildIndex).getLocalName();
if ((taxItemName != null) && (taxItemName.equals("RateApplicablePercent")
|| taxItemName.equals("ApplicablePercent"))) {
|| taxItemName.equals("ApplicablePercent")|| taxItemName.equals("Percent"/*UBL*/))) {
taxPercent = taxChilds.item(taxChildIndex).getTextContent();
}
}
}
}
}

if (isCharge) {
if (isCharge.booleanValue()) {
Charge c = new Charge(new BigDecimal(chargeAmount));
if (reason != null) {
c.setReason(reason);
@@ -346,7 +387,7 @@ public Invoice extractInto(Invoice zpp) throws XPathExpressionException, ParseEx
&& ((!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 (would have expected a grand total of "+expectedStringTotalGross+" instead of "+XMLTools.nDigitFormat(expectedGrandTotal, 2)+"), this could mean that it could not be read properly", 0);
}
}
return zpp;
Original file line number Diff line number Diff line change
@@ -173,6 +173,31 @@ public void testEdgeInvoiceImport() {

}

public void testEdgeInvoiceImportUBL() {

boolean hasExceptions=false;
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter();
File expectedResult = getResourceAsFile("testout-ZF2PushEdge.ubl.xml");

Invoice invoice = null;
try {
String xml = new String(Files.readAllBytes(expectedResult.toPath()), StandardCharsets.UTF_8).replace("\r", "").replace("\n", "");

zii.fromXML(xml);

invoice = zii.extractInvoice();
} catch (XPathExpressionException | ParseException | IOException e) {
hasExceptions = true;
}

assertFalse(hasExceptions);
// Reading ZUGFeRD
assertEquals("4711", invoice.getZFItems()[0].getProduct().getSellerAssignedID());
assertEquals("9384", invoice.getSellerOrderReferencedDocumentID());
assertEquals("28934", invoice.getBuyerOrderReferencedDocumentID());

}

public void testZF1Import() {

ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter("./target/testout-MustangGnuaccountingBeispielRE-20171118_506zf1.pdf");
@@ -235,6 +260,27 @@ public void testItemAllowancesChargesImport() {
assertEquals(new BigDecimal("18.33"), tc.getGrandTotal());
}

public void testItemAllowancesChargesImportUBL() {

boolean hasExceptions=false;
ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter();
File expectedResult = getResourceAsFile("testout-ZF2PushItemChargesAllowances.ubl.xml");

Invoice invoice = null;
try {
String xml = new String(Files.readAllBytes(expectedResult.toPath()), StandardCharsets.UTF_8).replace("\r", "").replace("\n", "");

zii.fromXML(xml);

invoice = zii.extractInvoice();
} catch (XPathExpressionException | ParseException | IOException e) {
hasExceptions = true;
}
assertFalse(hasExceptions);
TransactionCalculator tc = new TransactionCalculator(invoice);
assertEquals(new BigDecimal("18.33"), tc.getGrandTotal());
}

public void testBasisQuantityImport() {

ZUGFeRDInvoiceImporter zii = new ZUGFeRDInvoiceImporter("./target/testout-ZF2newEdge.pdf");