Merge branch 'master' into master

This commit is contained in:
Jochen Staerk
2019-08-12 13:18:11 +02:00
committed by GitHub
48 changed files with 7172 additions and 1405 deletions

View File

@@ -18,7 +18,7 @@
*********************************************************************** */
package org.mustangproject.ZUGFeRD;
public class CustomXMLProvider implements IXMLProvider {
public class CustomXMLProvider implements IXMLProvider, IProfileProvider {
protected byte[] zugferdData;
@@ -48,4 +48,14 @@ public class CustomXMLProvider implements IXMLProvider {
}
@Override
public String getProfile() {
// TODO Auto-generated method stub
return null;
}
@Override
public void setProfile(ZUGFeRDConformanceLevel level) {
// TODO Auto-generated method stub
}
}

View File

@@ -22,6 +22,13 @@ import java.io.IOException;
import java.io.InputStream;
public interface IExporterFactory {
/**
* factory: loads a PDF file and returns an appropriate exporter
*
* @param pdfFilename binary of a PDF/A1 compliant document
* @return the generated exporter
* @throws IOException if anything is wrong with filename
*/
public ZUGFeRDExporter load(String pdfFilename) throws IOException;
/**
@@ -29,6 +36,8 @@ public interface IExporterFactory {
* metadata level, this will not e.g. convert graphics to JPG-2000)
*
* @param pdfBinary binary of a PDF/A1 compliant document
* @return the generated exporter
* @throws IOException (should not happen at all)
*/
public ZUGFeRDExporter load(byte[] pdfBinary) throws IOException;
@@ -37,7 +46,8 @@ public interface IExporterFactory {
* metadata level, this will not e.g. convert graphics to JPG-2000)
*
* @param pdfSource source to read a PDF/A1 compliant document from
* @throws IOException
* @throws IOException if anything is wrong with inputstream
* @return the generated ZUGFeRDExporter
*/
public ZUGFeRDExporter load(InputStream pdfSource) throws IOException;

View File

@@ -0,0 +1,27 @@
/** **********************************************************************
*
* Copyright 2018 Jochen Staerk
*
* Use is subject to license terms.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
* See the License for the specific language governing permissions and
* limitations under the License.
*
*********************************************************************** */
package org.mustangproject.ZUGFeRD;
public interface IProfileProvider {
public String getProfile();
public void setProfile(ZUGFeRDConformanceLevel level);
}

View File

@@ -19,11 +19,11 @@
package org.mustangproject.ZUGFeRD;
/**
* Mustangproject's ZUGFeRD implementation Neccessary interface for ZUGFeRD exporter Licensed under the APLv2
* Mustangproject's ZUGFeRD implementation neccessary interface for ZUGFeRD exporter Licensed under the APLv2
*
* @author jstaerk
* @version 1.2.0
* @date 2014-05-10
* dated 2014-05-10
*/
@@ -38,6 +38,24 @@ public interface IZUGFeRDExportableContact {
return null;
}
/**
* customer global identification assigned by the seller
*
* @return customer identification
*/
default String getGlobalID() {
return null;
}
/**
* customer global identification scheme
*
* @return customer identification
*/
default String getGlobalIDScheme() {
return null;
}
/**
* First and last name of the recipient
@@ -48,6 +66,14 @@ public interface IZUGFeRDExportableContact {
return null;
}
default String getPhone() {
return null;
}
default String getEMail() {
return null;
}
/**
* Postal code of the recipient

View File

@@ -27,7 +27,7 @@ import java.math.BigDecimal;
*
* @author jstaerk
* @version 1.2.0
* @date 2014-05-10
* dated 2014-05-10
*/
public interface IZUGFeRDExportableProduct {

View File

@@ -27,12 +27,21 @@ package org.mustangproject.ZUGFeRD;
* */
import java.util.Date;
import java.math.BigDecimal;
import java.util.Date;
import org.mustangproject.ZUGFeRD.model.DocumentCodeTypeConstants;
public interface IZUGFeRDExportableTransaction {
/**
* appears in /rsm:CrossIndustryDocument/rsm:HeaderExchangedDocument/ram:Name
* @return Name of document
*/
default String getDocumentName() {
return "RECHNUNG";
}
/**
*
*
@@ -65,7 +74,7 @@ public interface IZUGFeRDExportableTransaction {
/**
* this should be the full sender institution name, details, manager and tax registration. It is one of the few functions which may return null. e.g.
* <p/>
* <p>
* Lieferant GmbH Lieferantenstraße 20 80333 München Deutschland Geschäftsführer: Hans Muster Handelsregisternummer: H A 123
*
* @return null or full sender institution name, details, manager and tax registration
@@ -84,6 +93,15 @@ public interface IZUGFeRDExportableTransaction {
return null;
}
/**
* who processed the order
*
* @return the contact person at the supplier side
*/
default IZUGFeRDExportableContact getOwnContact() {
return null;
}
IZUGFeRDAllowanceCharge[] getZFAllowances();
@@ -106,53 +124,11 @@ public interface IZUGFeRDExportableTransaction {
/**
* BIC of the sender
*
* @return the BIC code of the recipient sender's bank
* the creditors payment informations
*
* @return an array of IZUGFeRDTradeSettlementPayment
*/
default String getOwnBIC() {
return null;
}
/**
* BLZ of the sender
*
* @return the BLZ code of the recipient sender's bank
*/
default String getOwnBLZ() {
return null;
}
/**
* Bank name of the sender
*
* @return the name of the sender's bank
*/
default String getOwnBankName() {
return null;
}
/**
* IBAN of the sender
*
* @return the IBAN of the invoice sender's bank account
*/
default String getOwnIBAN() {
return null;
}
/**
* IBAN of the sender
*
* @return the Account Number of the invoice sender's bank account
*/
default String getOwnKto() {
return null;
}
IZUGFeRDTradeSettlementPayment[] getTradeSettlementPayment();
/**
@@ -253,16 +229,6 @@ public interface IZUGFeRDExportableTransaction {
}
/**
* get payment information text. e.g. Bank transfer
*
* @return payment information text
*/
default String getOwnPaymentInfoText() {
return null;
}
/**
* get payment term descriptional text e.g. Bis zum 22.10.2015 ohne Abzug
*
@@ -282,7 +248,6 @@ public interface IZUGFeRDExportableTransaction {
return null;
}
/**
* get reference number of the purchase order this invoice is based on
*
@@ -352,4 +317,23 @@ public interface IZUGFeRDExportableTransaction {
return null;
}
/**
* get the ID of the BuyerOrderReferencedDocument, which sits in the ApplicableSupplyChainTradeAgreement
* @return the ID of the document
*/
default String getBuyerOrderReferencedDocumentID() { return null; }
/**
* get the issue timestamp of the BuyerOrderReferencedDocument, which sits in the ApplicableSupplyChainTradeAgreement
* @return the IssueDateTime in format CCYY-MM-DDTHH:MM:SS
*/
default String getBuyerOrderReferencedDocumentIssueDateTime() { return null; }
/**
* get the TotalPrepaidAmount located in SpecifiedTradeSettlementMonetarySummation (v1) or
* SpecifiedTradeSettlementHeaderMonetarySummation (v2)
* @return the total sum (incl. VAT) of prepayments, i.e. the difference between GrandTotalAmount
* and DuePayableAmount
*/
default BigDecimal getTotalPrepaidAmount() { return BigDecimal.ZERO; }
}

View File

@@ -0,0 +1,81 @@
/** **********************************************************************
*
* Copyright 2019 by ak on 12.04.19.
*
* Use is subject to license terms.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
* See the License for the specific language governing permissions and
* limitations under the License.
*
*********************************************************************** */
package org.mustangproject.ZUGFeRD;
public interface IZUGFeRDTradeSettlementPayment {
/**
* get payment information text. e.g. Bank transfer
*
* @return payment information text
*/
default String getOwnPaymentInfoText() {
return null;
}
/**
* BIC of the sender
*
* @return the BIC code of the recipient sender's bank
*/
default String getOwnBIC() {
return null;
}
/**
* BLZ of the sender
*
* @return the BLZ code of the recipient sender's bank
*/
default String getOwnBLZ() {
return null;
}
/**
* Bank name of the sender
*
* @return the name of the sender's bank
*/
default String getOwnBankName() {
return null;
}
/**
* IBAN of the sender
*
* @return the IBAN of the invoice sender's bank account
*/
default String getOwnIBAN() {
return null;
}
/**
* IBAN of the sender
*
* @return the Account Number of the invoice sender's bank account
*/
default String getOwnKto() {
return null;
}
}

View File

@@ -27,20 +27,20 @@ import java.math.BigDecimal;
*
* @author jstaerk
* @version 1.2.0
* @date 2015-10-29
* dated 2015-10-29
*/
public class VATAmount {
public VATAmount(BigDecimal basis, BigDecimal calculated, String documentCode) {
public VATAmount(BigDecimal basis, BigDecimal calculated, String categoryCode) {
super();
this.basis = basis;
this.calculated = calculated;
this.documentCode = documentCode;
this.categoryCode = categoryCode;
}
BigDecimal basis, calculated;
String documentCode;
String categoryCode;
public BigDecimal getBasis() {
return basis;
@@ -58,20 +58,39 @@ public class VATAmount {
this.calculated = calculated;
}
/**
*
* @deprecated Use {@link #getCategoryCode() instead}
* @return String with category code
*/
@Deprecated
public String getDocumentCode() {
return documentCode;
return categoryCode;
}
/**
* @param documentCode as String
* @deprecated Use {@link #setCategoryCode(String)} instead
*/
@Deprecated
public void setDocumentCode(String documentCode) {
this.documentCode = documentCode;
this.categoryCode = documentCode;
}
public String getCategoryCode() {
return categoryCode;
}
public void setCategoryCode(String categoryCode) {
this.categoryCode = categoryCode;
}
public VATAmount add(VATAmount v) {
return new VATAmount(basis.add(v.getBasis()), calculated.add(v.getCalculated()), this.documentCode);
return new VATAmount(basis.add(v.getBasis()), calculated.add(v.getCalculated()), this.categoryCode);
}
public VATAmount subtract(VATAmount v) {
return new VATAmount(basis.subtract(v.getBasis()), calculated.subtract(v.getCalculated()), this.documentCode);
return new VATAmount(basis.subtract(v.getBasis()), calculated.subtract(v.getCalculated()), this.categoryCode);
}
}

View File

@@ -52,11 +52,13 @@ public class XMPSchemaPDFAExtensions extends PDFAExtensionSchema {
public final String prefix_pdfaProperty = "pdfaProperty";
public String namespace = null;
public String prefix = null;
protected ZUGFeRDExporter exporter;
protected void setZUGFeRDVersion(int ver) {
namespace = ZUGFeRDExporter.getNamespaceForVersion(ver);
prefix = ZUGFeRDExporter.getPrefixForVersion(ver);
namespace = exporter.getNamespaceForVersion(ver);
prefix = exporter.getPrefixForVersion(ver);
}
@@ -87,14 +89,16 @@ public class XMPSchemaPDFAExtensions extends PDFAExtensionSchema {
return li;
}
public XMPSchemaPDFAExtensions(XMPMetadata metadata, int ZFVersion) {
public XMPSchemaPDFAExtensions(ZUGFeRDExporter ze, XMPMetadata metadata, int ZFVersion) {
super(metadata);
exporter=ze;
setZUGFeRDVersion(ZFVersion);
attachExtensions(metadata, true);
}
public XMPSchemaPDFAExtensions(XMPMetadata metadata, int ZFVersion, boolean withZF) {
public XMPSchemaPDFAExtensions(ZUGFeRDExporter ze, XMPMetadata metadata, int ZFVersion, boolean withZF) {
super(metadata);
exporter=ze;
setZUGFeRDVersion(ZFVersion);
attachExtensions(metadata, withZF);
}

View File

@@ -31,8 +31,13 @@ import org.apache.xmpbox.schema.XMPSchema;
public class XMPSchemaZugferd extends XMPSchema {
/**
/***
* This is what needs to be added to the RDF metadata - basically the name of the embedded Zugferd file
* @param metadata the xmp to be added to
* @param conformanceLevel e.g. conformanceLevel.EN16931
* @param URN the xml URI for the XMP
* @param prefix the xml namespace prefix for the XMP, zf for ZUGFeRD, fx for Factur-X
* @param filename the filename of the invoice
*/
public XMPSchemaZugferd(XMPMetadata metadata, ZUGFeRDConformanceLevel conformanceLevel, String URN, String prefix, String filename) {
super(metadata, URN, prefix, "ZUGFeRD Schema");

View File

@@ -19,6 +19,7 @@
package org.mustangproject.ZUGFeRD;
import org.mustangproject.ZUGFeRD.model.CrossIndustryDocumentType;
import org.mustangproject.ZUGFeRD.model.DocumentContextParameterTypeConstants;
import org.mustangproject.ZUGFeRD.model.ZFNamespacePrefixMapper;
import javax.xml.bind.JAXBContext;
@@ -27,13 +28,27 @@ import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import java.io.ByteArrayOutputStream;
public class ZUGFeRD1PullProvider implements IXMLProvider {
public class ZUGFeRD1PullProvider implements IXMLProvider, IProfileProvider {
protected byte[] zugferdData;
private Marshaller marshaller;
private boolean isTest;
private ZUGFeRDConformanceLevel level;
public void setProfile(ZUGFeRDConformanceLevel level) {
this.level = level;
}
public String getProfile() {
switch (level) {
case BASIC: return DocumentContextParameterTypeConstants.BASIC;
case COMFORT: return DocumentContextParameterTypeConstants.COMFORT;
default: return DocumentContextParameterTypeConstants.EXTENDED;
}
}
/**
@@ -59,7 +74,7 @@ public class ZUGFeRD1PullProvider implements IXMLProvider {
private String createZugferdXMLForTransaction(IZUGFeRDExportableTransaction trans) {
JAXBElement<CrossIndustryDocumentType> jaxElement =
new ZUGFeRDTransactionModelConverter(trans).withTest(isTest).convertToModel();
new ZUGFeRDTransactionModelConverter(trans).withTest(isTest).withProfile(getProfile()).convertToModel();
try {
return marshalJaxToXMLString(jaxElement);

View File

@@ -18,28 +18,42 @@
*********************************************************************** */
package org.mustangproject.ZUGFeRD;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringWriter;
import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.HashMap;
import java.util.logging.Level;
import java.util.logging.Logger;
public class ZUGFeRD2PullProvider implements IXMLProvider {
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.XMLWriter;
import org.mustangproject.toecount.Toecount;
public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider {
private class LineCalc {
private IZUGFeRDExportableItem currentItem = null;
private BigDecimal totalGross;
private BigDecimal itemTotalNetAmount;
private BigDecimal itemTotalVATAmount;
public LineCalc(IZUGFeRDExportableItem currentItem) {
this.currentItem = currentItem;
BigDecimal multiplicator = currentItem.getProduct().getVATPercent().divide(new BigDecimal(100)).add(new BigDecimal(1));
// priceGross=currentItem.getPrice().multiply(multiplicator);
BigDecimal multiplicator = currentItem.getProduct().getVATPercent().divide(new BigDecimal(100))
.add(new BigDecimal(1));
// priceGross=currentItem.getPrice().multiply(multiplicator);
totalGross = currentItem.getPrice().multiply(multiplicator).multiply(currentItem.getQuantity());
itemTotalNetAmount = currentItem.getQuantity().multiply(currentItem.getPrice()).setScale(2, BigDecimal.ROUND_HALF_UP);
itemTotalNetAmount = currentItem.getQuantity().multiply(currentItem.getPrice()).setScale(2,
BigDecimal.ROUND_HALF_UP);
itemTotalVATAmount = totalGross.subtract(itemTotalNetAmount);
}
@@ -53,77 +67,90 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
}
//// MAIN CLASS
protected byte[] zugferdData;
private IZUGFeRDExportableTransaction trans;
private boolean isTest;
private ZUGFeRDConformanceLevel level;
public void setProfile(ZUGFeRDConformanceLevel level) {
this.level = level;
}
/**
* enables the flag to indicate a test invoice in the XML structure
*/
public void setTest() {
isTest = true;
}
private String nDigitFormat(BigDecimal value, int scale) {
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(' ');
* 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
* 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
*
* This function will cut off, i.e. floor() subcent values Tests:
* System.err.println(utils.currencyFormat(new BigDecimal(0),
* ".")+"\n"+utils.currencyFormat(new BigDecimal("-1.10"),
* ",")+"\n"+utils.currencyFormat(new BigDecimal("-1.1"),
* ",")+"\n"+utils.currencyFormat(new BigDecimal("-1.01"),
* ",")+"\n"+utils.currencyFormat(new BigDecimal("20000123.3489"),
* ",")+"\n"+utils.currencyFormat(new BigDecimal("20000123.3419"),
* ",")+"\n"+utils.currencyFormat(new BigDecimal("12"), ","));
*
* results 0.00 -1,10 -1,10 -1,01 20000123,34 20000123,34 12,00
*/
value = value.setScale(scale, BigDecimal.ROUND_HALF_UP); // first, round so that e.g. 1.189999999999999946709294817992486059665679931640625 becomes 1.19
char[] repeat = new char[scale];
Arrays.fill(repeat, '0');
DecimalFormatSymbols otherSymbols = new DecimalFormatSymbols();
otherSymbols.setDecimalSeparator('.');
DecimalFormat dec = new DecimalFormat("0." + new String(repeat), otherSymbols);
return dec.format(value);
return value.setScale(scale, RoundingMode.HALF_UP).toPlainString();
}
private String vatFormat(BigDecimal value) {
return nDigitFormat(value, 2);
return ZUGFeRD2PullProvider.nDigitFormat(value, 2);
}
private String currencyFormat(BigDecimal value) {
return nDigitFormat(value, 2);
return ZUGFeRD2PullProvider.nDigitFormat(value, 2);
}
private String priceFormat(BigDecimal value) {
return nDigitFormat(value, 4);
return ZUGFeRD2PullProvider.nDigitFormat(value, 4);
}
private String quantityFormat(BigDecimal value) {
return nDigitFormat(value, 4);
return ZUGFeRD2PullProvider.nDigitFormat(value, 4);
}
@Override
public byte[] getXML() {
return zugferdData;
byte[] res = zugferdData;
StringWriter sw = new StringWriter();
Document document=null;
try {
document = DocumentHelper.parseText(new String(zugferdData));
} catch (DocumentException e1) {
Logger.getLogger(ZUGFeRD2PullProvider.class.getName()).log(Level.SEVERE, null, e1);
}
try {
OutputFormat format = OutputFormat.createPrettyPrint();
XMLWriter writer = new XMLWriter(sw, format);
writer.write(document);
res = sw.toString().getBytes("UTF-8");
} catch (IOException e) {
Logger.getLogger(ZUGFeRD2PullProvider.class.getName()).log(Level.SEVERE, null, e);
}
return res;
}
private BigDecimal getTotalPrepaid() {
if (trans.getTotalPrepaidAmount()==null) {
return new BigDecimal(0);
} else {
return trans.getTotalPrepaidAmount();
}
}
private BigDecimal getTotalGross() {
@@ -147,20 +174,20 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
}
/**
* which taxes have been used with which amounts in this transaction,
* empty for no taxes, or e.g. 19=>190 and 7=>14 if 1000 Eur were applicable
* to 19% VAT (=>190 EUR VAT) and 200 EUR were applicable to 7% (=>14 EUR VAT)
* 190 Eur
* which taxes have been used with which amounts in this transaction, empty for
* no taxes, or e.g. 19=>190 and 7=>14 if 1000 Eur were applicable to 19% VAT
* (=>190 EUR VAT) and 200 EUR were applicable to 7% (=>14 EUR VAT) 190 Eur
*
* @return which taxes have been used with which amounts in this invoice
*/
private HashMap<BigDecimal, VATAmount> getVATPercentAmountMap() {
HashMap<BigDecimal, VATAmount> hm = new HashMap<BigDecimal, VATAmount>();
HashMap<BigDecimal, VATAmount> hm = new HashMap<>();
for (IZUGFeRDExportableItem currentItem : trans.getZFItems()) {
BigDecimal percent = currentItem.getProduct().getVATPercent();
LineCalc lc = new LineCalc(currentItem);
VATAmount itemVATAmount = new VATAmount(lc.getItemTotalNetAmount(), lc.getItemTotalVATAmount(), trans.getDocumentCode());
VATAmount itemVATAmount = new VATAmount(lc.getItemTotalNetAmount(), lc.getItemTotalVATAmount(),
trans.getDocumentCode());
VATAmount current = hm.get(percent);
if (current == null) {
hm.put(percent, itemVATAmount);
@@ -171,61 +198,101 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
return hm;
}
public String getProfile() {
return "urn:cen.eu:en16931:2017";
}
public static String encodeXML(CharSequence s) {
StringBuilder sb = new StringBuilder();
int len = s.length();
for (int i=0;i<len;i++) {
int c = s.charAt(i);
if (c >= 0xd800 && c <= 0xdbff && i + 1 < len) {
c = ((c-0xd7c0)<<10) | (s.charAt(++i)&0x3ff); // UTF16 decode
}
if (c < 0x80) { // ASCII range: test most common case first
if (c < 0x20 && (c != '\t' && c != '\r' && c != '\n')) {
// Illegal XML character, even encoded. Skip or substitute
sb.append("&#xfffd;"); // Unicode replacement character
} else {
switch(c) {
case '&': sb.append("&amp;"); break;
case '>': sb.append("&gt;"); break;
case '<': sb.append("&lt;"); break;
// Uncomment next two if encoding for an XML attribute
// case '\'' sb.append("&apos;"); break;
// case '\"' sb.append("&quot;"); break;
// Uncomment next three if you prefer, but not required
// case '\n' sb.append("&#10;"); break;
// case '\r' sb.append("&#13;"); break;
// case '\t' sb.append("&#9;"); break;
default: sb.append((char)c);
}
}
} else if ((c >= 0xd800 && c <= 0xdfff) || c == 0xfffe || c == 0xffff) {
// Illegal XML character, even encoded. Skip or substitute
sb.append("&#xfffd;"); // Unicode replacement character
} else {
sb.append("&#x");
sb.append(Integer.toHexString(c));
sb.append(';');
}
}
return sb.toString();
}
@Override
public void generateXML(IZUGFeRDExportableTransaction trans) {
this.trans = trans;
SimpleDateFormat germanDateFormat = new SimpleDateFormat("dd.MM.yyyy"); //$NON-NLS-1$
SimpleDateFormat zugferdDateFormat = new SimpleDateFormat("yyyyMMdd"); //$NON-NLS-1$
String testBooleanStr = "false";
if (isTest) {
testBooleanStr = "true";
}
String senderReg = "";
if (trans.getOwnOrganisationFullPlaintextInfo() != null) {
senderReg = ""
+ "<ram:IncludedCINote>\n"
+ " <ram:Content>\n"
+ trans.getOwnOrganisationFullPlaintextInfo()
+ " </ram:Content>\n"
+ "<ram:SubjectCode>REG</ram:SubjectCode>\n"
+ "</ram:IncludedCINote>\n";
senderReg = "" + "<ram:IncludedNote>\n" + " <ram:Content>\n"
+ encodeXML(trans.getOwnOrganisationFullPlaintextInfo()) + " </ram:Content>\n"
+ "<ram:SubjectCode>REG</ram:SubjectCode>\n" + "</ram:IncludedNote>\n";
}
String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" //$NON-NLS-1$
+ "<rsm:CrossIndustryInvoice xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:rsm=\"urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100\""
// + " xsi:schemaLocation=\"urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100 ../Schema/ZUGFeRD1p0.xsd\""
// + "
// xsi:schemaLocation=\"urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100
// ../Schema/ZUGFeRD1p0.xsd\""
+ " xmlns:ram=\"urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100\""
+ " xmlns:udt=\"urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100\">\n" //$NON-NLS-1$
+ " <rsm:ExchangedDocumentContext>\n" //$NON-NLS-1$
// + " <ram:TestIndicator><udt:Indicator>"+testBooleanStr+"</udt:Indicator></ram:TestIndicator>\n" //$NON-NLS-1$
// + "
// <ram:TestIndicator><udt:Indicator>"+testBooleanStr+"</udt:Indicator></ram:TestIndicator>\n"
// //$NON-NLS-1$
+ " <ram:GuidelineSpecifiedDocumentContextParameter>\n" //$NON-NLS-1$
+ " <ram:ID>urn:cen.eu:en16931:2017:compliant:factur-x.eu:1p0:en16931</ram:ID>\n" //$NON-NLS-1$
+ " <ram:ID>" + getProfile() + "</ram:ID>\n" //$NON-NLS-1$
+ " </ram:GuidelineSpecifiedDocumentContextParameter>\n" //$NON-NLS-1$
+ " </rsm:ExchangedDocumentContext>\n" //$NON-NLS-1$
+ " <rsm:ExchangedDocument>\n" //$NON-NLS-1$
+ " <ram:ID>" + trans.getNumber() + "</ram:ID>\n" //$NON-NLS-1$ //$NON-NLS-2$
// + " <ram:Name>RECHNUNG</ram:Name>\n" //$NON-NLS-1$
+ " <ram:ID>" + encodeXML(trans.getNumber()) + "</ram:ID>\n" //$NON-NLS-1$ //$NON-NLS-2$
// + " <ram:Name>RECHNUNG</ram:Name>\n" //$NON-NLS-1$
+ " <ram:TypeCode>380</ram:TypeCode>\n" //$NON-NLS-1$
+ " <ram:IssueDateTime><udt:DateTimeString format=\"102\">" + zugferdDateFormat.format(trans.getIssueDate()) + "</udt:DateTimeString></ram:IssueDateTime>\n" //date format was 20130605 //$NON-NLS-1$ //$NON-NLS-2$
+ " <ram:IssueDateTime><udt:DateTimeString format=\"102\">" //$NON-NLS-1$
+ zugferdDateFormat.format(trans.getIssueDate()) + "</udt:DateTimeString></ram:IssueDateTime>\n" // date //$NON-NLS-1$
// format
// was
// 20130605
+ senderReg
// + " <IncludedNote>\n"
// + " <Content>\n"
// + "Rechnung gemäß Bestellung Nr. 2013-471331 vom 01.03.2013.\n"
// + "\n"
// + " </Content>\n"
// + " </IncludedNote>\n"
// + " <IncludedNote>\n"
// + " <Content>\n"
// + "Es bestehen Rabatt- und Bonusvereinbarungen.\n"
// + " </Content>\n"
// + " <SubjectCode>AAK</SubjectCode>\n"
// + " </IncludedNote>\n"
// + " <IncludedNote>\n"
// + " <Content>\n"
// + "Rechnung gemäß Bestellung Nr. 2013-471331 vom 01.03.2013.\n"
// + "\n"
// + " </Content>\n"
// + " </IncludedNote>\n"
// + " <IncludedNote>\n"
// + " <Content>\n"
// + "Es bestehen Rabatt- und Bonusvereinbarungen.\n"
// + " </Content>\n"
// + " <SubjectCode>AAK</SubjectCode>\n"
// + " </IncludedNote>\n"
+ " </rsm:ExchangedDocument>\n" //$NON-NLS-1$
+ " <rsm:SupplyChainTradeTransaction>\n"; //$NON-NLS-1$
int lineID = 0;
@@ -238,188 +305,243 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
+ " <ram:LineID>" + lineID + "</ram:LineID>\n" //$NON-NLS-1$ //$NON-NLS-2$
+ " </ram:AssociatedDocumentLineDocument>\n" //$NON-NLS-1$
+ " <ram:SpecifiedTradeProduct>\n" //$NON-NLS-1$
// + " <GlobalID schemeID=\"0160\">4012345001235</GlobalID>\n"
// + " <SellerAssignedID>KR3M</SellerAssignedID>\n"
// + " <BuyerAssignedID>55T01</BuyerAssignedID>\n"
+ " <ram:Name>" + currentItem.getProduct().getName() + "</ram:Name>\n" //$NON-NLS-1$ //$NON-NLS-2$
+ " <ram:Description>" + currentItem.getProduct().getDescription() + "</ram:Description>\n" //$NON-NLS-1$ //$NON-NLS-2$
// + " <GlobalID schemeID=\"0160\">4012345001235</GlobalID>\n"
// + " <SellerAssignedID>KR3M</SellerAssignedID>\n"
// + " <BuyerAssignedID>55T01</BuyerAssignedID>\n"
+ " <ram:Name>" + encodeXML(currentItem.getProduct().getName()) + "</ram:Name>\n" //$NON-NLS-1$ //$NON-NLS-2$
+ " <ram:Description>" + encodeXML(currentItem.getProduct().getDescription()) //$NON-NLS-1$
+ "</ram:Description>\n" //$NON-NLS-1$
+ " </ram:SpecifiedTradeProduct>\n" //$NON-NLS-1$
+ " <ram:SpecifiedLineTradeAgreement>\n" //$NON-NLS-1$
+ " <ram:GrossPriceProductTradePrice>\n" //$NON-NLS-1$
+ " <ram:ChargeAmount>" + priceFormat(currentItem.getPrice()) + "</ram:ChargeAmount>\n" //$NON-NLS-1$ //$NON-NLS-2$ //currencyID=\"EUR\"
+ " <ram:BasisQuantity unitCode=\"" + currentItem.getProduct().getUnit() + "\">1.0000</ram:BasisQuantity>\n" //$NON-NLS-1$ //$NON-NLS-2$
// + " <AppliedTradeAllowanceCharge>\n"
// + " <ChargeIndicator>false</ChargeIndicator>\n"
// + " <ActualAmount currencyID=\"EUR\">0.6667</ActualAmount>\n"
// + " <Reason>Rabatt</Reason>\n"
// + " </AppliedTradeAllowanceCharge>\n"
+ " <ram:ChargeAmount>" + priceFormat(currentItem.getPrice()) //$NON-NLS-1$
+ "</ram:ChargeAmount>\n" //$NON-NLS-1$ //currencyID=\"EUR\"
+ " <ram:BasisQuantity unitCode=\"" + encodeXML(currentItem.getProduct().getUnit()) //$NON-NLS-1$
+ "\">1.0000</ram:BasisQuantity>\n" //$NON-NLS-1$
// + " <AppliedTradeAllowanceCharge>\n"
// + " <ChargeIndicator>false</ChargeIndicator>\n"
// + " <ActualAmount currencyID=\"EUR\">0.6667</ActualAmount>\n"
// + " <Reason>Rabatt</Reason>\n"
// + " </AppliedTradeAllowanceCharge>\n"
+ " </ram:GrossPriceProductTradePrice>\n" //$NON-NLS-1$
+ " <ram:NetPriceProductTradePrice>\n" //$NON-NLS-1$
+ " <ram:ChargeAmount>" + priceFormat(currentItem.getPrice()) + "</ram:ChargeAmount>\n" //$NON-NLS-1$ //$NON-NLS-2$ // currencyID=\"EUR\"
+ " <ram:BasisQuantity unitCode=\"" + currentItem.getProduct().getUnit() + "\">1.0000</ram:BasisQuantity>\n" //$NON-NLS-1$ //$NON-NLS-2$
+ " <ram:ChargeAmount>" + priceFormat(currentItem.getPrice()) //$NON-NLS-1$
+ "</ram:ChargeAmount>\n" //$NON-NLS-1$ // currencyID=\"EUR\"
+ " <ram:BasisQuantity unitCode=\"" + encodeXML(currentItem.getProduct().getUnit()) //$NON-NLS-1$
+ "\">1.0000</ram:BasisQuantity>\n" //$NON-NLS-1$
+ " </ram:NetPriceProductTradePrice>\n" //$NON-NLS-1$
+ " </ram:SpecifiedLineTradeAgreement>\n" //$NON-NLS-1$
+ " <ram:SpecifiedLineTradeDelivery>\n" //$NON-NLS-1$
+ " <ram:BilledQuantity unitCode=\"" + currentItem.getProduct().getUnit() + "\">" + quantityFormat(currentItem.getQuantity()) + "</ram:BilledQuantity>\n" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ " <ram:BilledQuantity unitCode=\"" + encodeXML(currentItem.getProduct().getUnit()) + "\">" //$NON-NLS-1$ //$NON-NLS-2$
+ quantityFormat(currentItem.getQuantity()) + "</ram:BilledQuantity>\n" //$NON-NLS-1$
+ " </ram:SpecifiedLineTradeDelivery>\n" //$NON-NLS-1$
+ " <ram:SpecifiedLineTradeSettlement>\n" //$NON-NLS-1$
+ " <ram:ApplicableTradeTax>\n" //$NON-NLS-1$
+ " <ram:TypeCode>VAT</ram:TypeCode>\n" //$NON-NLS-1$
+ " <ram:CategoryCode>S</ram:CategoryCode>\n" //$NON-NLS-1$
+ " <ram:RateApplicablePercent>" + vatFormat(currentItem.getProduct().getVATPercent()) + "</ram:RateApplicablePercent>\n" //$NON-NLS-1$ //$NON-NLS-2$
+ " <ram:RateApplicablePercent>" //$NON-NLS-1$
+ vatFormat(currentItem.getProduct().getVATPercent()) + "</ram:RateApplicablePercent>\n" //$NON-NLS-1$
+ " </ram:ApplicableTradeTax>\n" //$NON-NLS-1$
+ " <ram:SpecifiedTradeSettlementLineMonetarySummation>\n" //$NON-NLS-1$
+ " <ram:LineTotalAmount>" + currencyFormat(lc.getItemTotalNetAmount()) + "</ram:LineTotalAmount>\n" //$NON-NLS-1$ //$NON-NLS-2$ // currencyID=\"EUR\"
+ " <ram:LineTotalAmount>" + currencyFormat(lc.getItemTotalNetAmount()) //$NON-NLS-1$
+ "</ram:LineTotalAmount>\n" //$NON-NLS-1$ // currencyID=\"EUR\"
+ " </ram:SpecifiedTradeSettlementLineMonetarySummation>\n" //$NON-NLS-1$
+ " </ram:SpecifiedLineTradeSettlement>\n" //$NON-NLS-1$
+ " </ram:IncludedSupplyChainTradeLineItem>\n"; //$NON-NLS-1$
}
xml = xml + " <ram:ApplicableHeaderTradeAgreement>\n"; //$NON-NLS-1$
if (trans.getReferenceNumber() != null) {
xml = xml + " <ram:BuyerReference>" + encodeXML(trans.getReferenceNumber()) + "</ram:BuyerReference>\n";
}
xml = xml + " <ram:SellerTradeParty>\n" //$NON-NLS-1$
// + " <GlobalID schemeID=\"0088\">4000001123452</GlobalID>\n"
+ " <ram:Name>" + encodeXML(trans.getOwnOrganisationName()) + "</ram:Name>\n"; //$NON-NLS-1$ //$NON-NLS-2$
if ((trans.getOwnVATID()!=null)&&(trans.getOwnOrganisationName()!=null)) {
xml = xml + " <ram:SpecifiedLegalOrganization>\n" + " <ram:ID schemeID='9930'>"
+ encodeXML(trans.getOwnVATID()) + "</ram:ID>\n" + " <ram:TradingBusinessName>"
+ encodeXML(trans.getOwnOrganisationName()) + "</ram:TradingBusinessName>\n"
+ " </ram:SpecifiedLegalOrganization>";
}
if (trans.getOwnContact() != null) {
xml = xml + "<ram:DefinedTradeContact>\n" + " <ram:PersonName>" + encodeXML(trans.getOwnContact().getName())
+ "</ram:PersonName>\n";
if (trans.getOwnContact().getPhone() != null) {
xml = xml + " <ram:TelephoneUniversalCommunication>\n" + " <ram:CompleteNumber>"
+ encodeXML(trans.getOwnContact().getPhone()) + "</ram:CompleteNumber>\n"
+ " </ram:TelephoneUniversalCommunication>\n";
}
if (trans.getOwnContact().getEMail() != null) {
xml = xml + " <ram:EmailURIUniversalCommunication>\n" + " <ram:URIID>"
+ encodeXML(trans.getOwnContact().getEMail()) + "</ram:URIID>\n"
+ " </ram:EmailURIUniversalCommunication>\n";
}
xml = xml + " </ram:DefinedTradeContact>";
}
xml = xml + " <ram:ApplicableHeaderTradeAgreement>\n" //$NON-NLS-1$
// + " <BuyerReference>AB-312</BuyerReference>\n"
+ " <ram:SellerTradeParty>\n" //$NON-NLS-1$
// + " <GlobalID schemeID=\"0088\">4000001123452</GlobalID>\n"
+ " <ram:Name>" + trans.getOwnOrganisationName() + "</ram:Name>\n" //$NON-NLS-1$ //$NON-NLS-2$
+ " <ram:PostalTradeAddress>\n"
+ " <ram:PostcodeCode>" + trans.getOwnZIP() + "</ram:PostcodeCode>\n"
+ " <ram:LineOne>" + trans.getOwnStreet() + "</ram:LineOne>\n"
+ " <ram:CityName>" + trans.getOwnLocation() + "</ram:CityName>\n"
+ " <ram:CountryID>" + trans.getOwnCountry() + "</ram:CountryID>\n"
+ " </ram:PostalTradeAddress>\n"
xml = xml + " <ram:PostalTradeAddress>\n" + " <ram:PostcodeCode>"
+ encodeXML(trans.getOwnZIP()) + "</ram:PostcodeCode>\n" + " <ram:LineOne>"
+ encodeXML(trans.getOwnStreet()) + "</ram:LineOne>\n" + " <ram:CityName>" + encodeXML(trans.getOwnLocation())
+ "</ram:CityName>\n" + " <ram:CountryID>" + encodeXML(trans.getOwnCountry())
+ "</ram:CountryID>\n" + " </ram:PostalTradeAddress>\n"
+ " <ram:SpecifiedTaxRegistration>\n" //$NON-NLS-1$
+ " <ram:ID schemeID=\"FC\">" + trans.getOwnTaxID() + "</ram:ID>\n" //$NON-NLS-1$ //$NON-NLS-2$
+ " <ram:ID schemeID=\"FC\">" + encodeXML(trans.getOwnTaxID()) + "</ram:ID>\n" //$NON-NLS-1$ //$NON-NLS-2$
+ " </ram:SpecifiedTaxRegistration>\n" //$NON-NLS-1$
+ " <ram:SpecifiedTaxRegistration>\n" //$NON-NLS-1$
+ " <ram:ID schemeID=\"VA\">" + trans.getOwnVATID() + "</ram:ID>\n" //$NON-NLS-1$ //$NON-NLS-2$
+ " <ram:ID schemeID=\"VA\">" + encodeXML(trans.getOwnVATID()) + "</ram:ID>\n" //$NON-NLS-1$ //$NON-NLS-2$
+ " </ram:SpecifiedTaxRegistration>\n" //$NON-NLS-1$
+ " </ram:SellerTradeParty>\n" //$NON-NLS-1$
+ " <ram:BuyerTradeParty>\n" //$NON-NLS-1$
// + " <ID>GE2020211</ID>\n"
// + " <GlobalID schemeID=\"0088\">4000001987658</GlobalID>\n"
+ " <ram:Name>" + trans.getRecipient().getName() + "</ram:Name>\n" //$NON-NLS-1$ //$NON-NLS-2$
// + " <DefinedTradeContact>\n"
// + " <PersonName>xxx</PersonName>\n"
// + " </DefinedTradeContact>\n"
// + " <ID>GE2020211</ID>\n"
// + " <GlobalID schemeID=\"0088\">4000001987658</GlobalID>\n"
+ " <ram:Name>" + encodeXML(trans.getRecipient().getName()) + "</ram:Name>\n" //$NON-NLS-1$ //$NON-NLS-2$
// + " <DefinedTradeContact>\n"
// + " <PersonName>xxx</PersonName>\n"
// + " </DefinedTradeContact>\n"
+ " <ram:PostalTradeAddress>\n" //$NON-NLS-1$
+ " <ram:PostcodeCode>" + trans.getRecipient().getZIP() + "</ram:PostcodeCode>\n" //$NON-NLS-1$ //$NON-NLS-2$
+ " <ram:LineOne>" + trans.getRecipient().getStreet() + "</ram:LineOne>\n" //$NON-NLS-1$ //$NON-NLS-2$
+ " <ram:CityName>" + trans.getRecipient().getLocation() + "</ram:CityName>\n" //$NON-NLS-1$ //$NON-NLS-2$
+ " <ram:CountryID>" + trans.getRecipient().getCountry() + "</ram:CountryID>\n" //$NON-NLS-1$ //$NON-NLS-2$
+ " </ram:PostalTradeAddress>\n" //$NON-NLS-1$
+ " <ram:SpecifiedTaxRegistration>\n" //$NON-NLS-1$
+ " <ram:ID schemeID=\"VA\">" + trans.getRecipient().getVATID() + "</ram:ID>\n" //$NON-NLS-1$ //$NON-NLS-2$
+ " </ram:SpecifiedTaxRegistration>\n" //$NON-NLS-1$
+ " </ram:BuyerTradeParty>\n" //$NON-NLS-1$
// + " <BuyerOrderReferencedDocument>\n"
// + " <IssueDateTime format=\"102\">20130301</IssueDateTime>\n"
// + " <ID>2013-471331</ID>\n"
// + " </BuyerOrderReferencedDocument>\n"
+ " <ram:PostcodeCode>" + encodeXML(trans.getRecipient().getZIP()) + "</ram:PostcodeCode>\n" //$NON-NLS-1$ //$NON-NLS-2$
+ " <ram:LineOne>" + encodeXML(trans.getRecipient().getStreet()) + "</ram:LineOne>\n" //$NON-NLS-1$ //$NON-NLS-2$
+ " <ram:CityName>" + encodeXML(trans.getRecipient().getLocation()) + "</ram:CityName>\n" //$NON-NLS-1$ //$NON-NLS-2$
+ " <ram:CountryID>" + encodeXML(trans.getRecipient().getCountry()) + "</ram:CountryID>\n" //$NON-NLS-1$ //$NON-NLS-2$
+ " </ram:PostalTradeAddress>\n"; //$NON-NLS-1$
if (trans.getRecipient().getVATID() != null) {
xml += " <ram:SpecifiedTaxRegistration>\n" //$NON-NLS-1$
+ " <ram:ID schemeID=\"VA\">" + encodeXML(trans.getRecipient().getVATID()) + "</ram:ID>\n" //$NON-NLS-1$ //$NON-NLS-2$
+ " </ram:SpecifiedTaxRegistration>\n"; //$NON-NLS-1$
}
xml += " </ram:BuyerTradeParty>\n" //$NON-NLS-1$
// + " <BuyerOrderReferencedDocument>\n"
// + " <IssueDateTime format=\"102\">20130301</IssueDateTime>\n"
// + " <ID>2013-471331</ID>\n"
// + " </BuyerOrderReferencedDocument>\n"
+ " </ram:ApplicableHeaderTradeAgreement>\n" //$NON-NLS-1$
+ " <ram:ApplicableHeaderTradeDelivery>\n"
+ " <ram:ActualDeliverySupplyChainEvent>\n"
+ " <ram:OccurrenceDateTime><udt:DateTimeString format=\"102\">" + zugferdDateFormat.format(trans.getDeliveryDate()) + "</udt:DateTimeString></ram:OccurrenceDateTime>\n"
+ " <ram:ApplicableHeaderTradeDelivery>\n" + " <ram:ActualDeliverySupplyChainEvent>\n"
+ " <ram:OccurrenceDateTime><udt:DateTimeString format=\"102\">"
+ zugferdDateFormat.format(trans.getDeliveryDate()) + "</udt:DateTimeString></ram:OccurrenceDateTime>\n"
+ " </ram:ActualDeliverySupplyChainEvent>\n"
/*
+ " <DeliveryNoteReferencedDocument>\n"
+ " <IssueDateTime format=\"102\">20130603</IssueDateTime>\n"
+ " <ID>2013-51112</ID>\n"
+ " </DeliveryNoteReferencedDocument>\n" */
+ " </ram:ApplicableHeaderTradeDelivery>\n"
+ " <ram:ApplicableHeaderTradeSettlement>\n" //$NON-NLS-1$
+ " <ram:PaymentReference>" + trans.getNumber() + "</ram:PaymentReference>\n" //$NON-NLS-1$ //$NON-NLS-2$
+ " <ram:InvoiceCurrencyCode>EUR</ram:InvoiceCurrencyCode>\n" //$NON-NLS-1$
+ " <ram:SpecifiedTradeSettlementPaymentMeans>\n" //$NON-NLS-1$
+ " <ram:TypeCode>42</ram:TypeCode>\n" //$NON-NLS-1$
+ " <ram:Information>Überweisung</ram:Information>\n" //$NON-NLS-1$
+ " <ram:PayeePartyCreditorFinancialAccount>\n" //$NON-NLS-1$
+ " <ram:IBANID>" + trans.getOwnIBAN() + "</ram:IBANID>\n" //$NON-NLS-1$ //$NON-NLS-2$
+ " <ram:ProprietaryID>" + trans.getOwnKto() + "</ram:ProprietaryID>\n" //$NON-NLS-1$ //$NON-NLS-2$
+ " </ram:PayeePartyCreditorFinancialAccount>\n" //$NON-NLS-1$
+ " <ram:PayeeSpecifiedCreditorFinancialInstitution>\n" //$NON-NLS-1$
+ " <ram:BICID>" + trans.getOwnBIC() + "</ram:BICID>\n" //$NON-NLS-1$ //$NON-NLS-2$
+ " <ram:GermanBankleitzahlID>" + trans.getOwnBLZ() + "</ram:GermanBankleitzahlID>\n" //$NON-NLS-1$ //$NON-NLS-2$
// + " <ram:Name>"+trans.getOwnBankName()+"</ram:Name>\n" //$NON-NLS-1$ //$NON-NLS-2$
+ " </ram:PayeeSpecifiedCreditorFinancialInstitution>\n" //$NON-NLS-1$
+ " </ram:SpecifiedTradeSettlementPaymentMeans>\n"; //$NON-NLS-1$
/*
* + " <DeliveryNoteReferencedDocument>\n" +
* " <IssueDateTime format=\"102\">20130603</IssueDateTime>\n" +
* " <ID>2013-51112</ID>\n" +
* " </DeliveryNoteReferencedDocument>\n"
*/
+ " </ram:ApplicableHeaderTradeDelivery>\n" + " <ram:ApplicableHeaderTradeSettlement>\n" //$NON-NLS-2$
+ " <ram:PaymentReference>" + encodeXML(trans.getNumber()) + "</ram:PaymentReference>\n" //$NON-NLS-1$ //$NON-NLS-2$
+ " <ram:InvoiceCurrencyCode>EUR</ram:InvoiceCurrencyCode>\n"; //$NON-NLS-1$
for (IZUGFeRDTradeSettlementPayment payment : trans.getTradeSettlementPayment()) {
xml += " <ram:SpecifiedTradeSettlementPaymentMeans>\n" //$NON-NLS-1$
+ " <ram:TypeCode>42</ram:TypeCode>\n" //$NON-NLS-1$
+ " <ram:Information>Überweisung</ram:Information>\n" //$NON-NLS-1$
+ " <ram:PayeePartyCreditorFinancialAccount>\n" //$NON-NLS-1$
+ " <ram:IBANID>" + encodeXML(payment.getOwnIBAN()) + "</ram:IBANID>\n"; //$NON-NLS-1$ //$NON-NLS-2$
if (payment.getOwnKto()!=null) {
xml+= " <ram:ProprietaryID>" + encodeXML(payment.getOwnKto()) + "</ram:ProprietaryID>\n"; //$NON-NLS-1$ //$NON-NLS-2$
}
xml+= " </ram:PayeePartyCreditorFinancialAccount>\n" //$NON-NLS-1$
+ " <ram:PayeeSpecifiedCreditorFinancialInstitution>\n" //$NON-NLS-1$
+ " <ram:BICID>" + encodeXML(payment.getOwnBIC()) + "</ram:BICID>\n" //$NON-NLS-1$ //$NON-NLS-2$
// + " <ram:Name>"+trans.getOwnBankName()+"</ram:Name>\n" //$NON-NLS-1$
// //$NON-NLS-2$
+ " </ram:PayeeSpecifiedCreditorFinancialInstitution>\n" //$NON-NLS-1$
+ " </ram:SpecifiedTradeSettlementPaymentMeans>\n"; //$NON-NLS-1$
}
HashMap<BigDecimal, VATAmount> VATPercentAmountMap = getVATPercentAmountMap();
for (BigDecimal currentTaxPercent : VATPercentAmountMap.keySet()) {
VATAmount amount = VATPercentAmountMap.get(currentTaxPercent);
if (amount != null) {
xml += " <ram:ApplicableTradeTax>\n" //$NON-NLS-1$
+ " <ram:CalculatedAmount>" + currencyFormat(amount.getCalculated()) + "</ram:CalculatedAmount>\n" //$NON-NLS-1$ //$NON-NLS-2$ //currencyID=\"EUR\"
+ " <ram:CalculatedAmount>" + currencyFormat(amount.getCalculated()) //$NON-NLS-1$
+ "</ram:CalculatedAmount>\n" //$NON-NLS-1$ //currencyID=\"EUR\"
+ " <ram:TypeCode>VAT</ram:TypeCode>\n" //$NON-NLS-1$
+ " <ram:BasisAmount>" + currencyFormat(amount.getBasis()) + "</ram:BasisAmount>\n" // currencyID=\"EUR\"
+ " <ram:CategoryCode>S</ram:CategoryCode>\n" //$NON-NLS-1$
+ " <ram:RateApplicablePercent>" + vatFormat(currentTaxPercent) + "</ram:RateApplicablePercent>\n" //$NON-NLS-1$
+ " </ram:ApplicableTradeTax>\n"; //$NON-NLS-1$
+ " <ram:RateApplicablePercent>" + vatFormat(currentTaxPercent) //$NON-NLS-1$
+ "</ram:RateApplicablePercent>\n" + " </ram:ApplicableTradeTax>\n"; //$NON-NLS-2$
}
}
/* xml+= "
+ " <SpecifiedTradeAllowanceCharge>\n"
+ " <ChargeIndicator>false</ChargeIndicator>\n"
+ " <BasisAmount currencyID=\"EUR\">10</BasisAmount>\n"
+ " <ActualAmount>1.00</ActualAmount>\n"
+ " <Reason>Sondernachlass</Reason>\n"
+ " <CategoryTradeTax>\n"
+ " <TypeCode>VAT</TypeCode>\n"
+ " <CategoryCode>S</CategoryCode>\n"
+ " <ApplicablePercent>19</ApplicablePercent>\n"
+ " </CategoryTradeTax>\n"
+ " </SpecifiedTradeAllowanceCharge>\n"
+ " <SpecifiedTradeAllowanceCharge>\n"
+ " <ChargeIndicator>false</ChargeIndicator>\n"
+ " <BasisAmount currencyID=\"EUR\">137.30</BasisAmount>\n"
+ " <ActualAmount>13.73</ActualAmount>\n"
+ " <Reason>Sondernachlass</Reason>\n"
+ " <CategoryTradeTax>\n"
+ " <TypeCode>VAT</TypeCode>\n"
+ " <CategoryCode>S</CategoryCode>\n"
+ " <ApplicablePercent>7</ApplicablePercent>\n"
+ " </CategoryTradeTax>\n"
+ " </SpecifiedTradeAllowanceCharge>\n"
+ " <SpecifiedLogisticsServiceCharge>\n"
+ " <Description>Versandkosten</Description>\n"
+ " <AppliedAmount>5.80</AppliedAmount>\n"
+ " <AppliedTradeTax>\n"
+ " <TypeCode>VAT</TypeCode>\n"
+ " <CategoryCode>S</CategoryCode>\n"
+ " <ApplicablePercent>7</ApplicablePercent>\n"
+ " </AppliedTradeTax>\n"
+ " </SpecifiedLogisticsServiceCharge>\n"*/
/*
* xml+= " + " <SpecifiedTradeAllowanceCharge>\n" +
* " <ChargeIndicator>false</ChargeIndicator>\n" +
* " <BasisAmount currencyID=\"EUR\">10</BasisAmount>\n" +
* " <ActualAmount>1.00</ActualAmount>\n" +
* " <Reason>Sondernachlass</Reason>\n" +
* " <CategoryTradeTax>\n" +
* " <TypeCode>VAT</TypeCode>\n" +
* " <CategoryCode>S</CategoryCode>\n" +
* " <ApplicablePercent>19</ApplicablePercent>\n" +
* " </CategoryTradeTax>\n" +
* " </SpecifiedTradeAllowanceCharge>\n" +
* " <SpecifiedTradeAllowanceCharge>\n" +
* " <ChargeIndicator>false</ChargeIndicator>\n" +
* " <BasisAmount currencyID=\"EUR\">137.30</BasisAmount>\n" +
* " <ActualAmount>13.73</ActualAmount>\n" +
* " <Reason>Sondernachlass</Reason>\n" +
* " <CategoryTradeTax>\n" +
* " <TypeCode>VAT</TypeCode>\n" +
* " <CategoryCode>S</CategoryCode>\n" +
* " <ApplicablePercent>7</ApplicablePercent>\n" +
* " </CategoryTradeTax>\n" +
* " </SpecifiedTradeAllowanceCharge>\n" +
* " <SpecifiedLogisticsServiceCharge>\n" +
* " <Description>Versandkosten</Description>\n" +
* " <AppliedAmount>5.80</AppliedAmount>\n" +
* " <AppliedTradeTax>\n" +
* " <TypeCode>VAT</TypeCode>\n" +
* " <CategoryCode>S</CategoryCode>\n" +
* " <ApplicablePercent>7</ApplicablePercent>\n" +
* " </AppliedTradeTax>\n" +
* " </SpecifiedLogisticsServiceCharge>\n"
*/
xml = xml + " <ram:SpecifiedTradePaymentTerms>\n" //$NON-NLS-1$
+ " <ram:Description>Zahlbar ohne Abzug bis " + germanDateFormat.format(trans.getDueDate()) + "</ram:Description>\n"
+ " <ram:DueDateDateTime><udt:DateTimeString format=\"102\">" + zugferdDateFormat.format(trans.getDueDate()) + "</udt:DateTimeString></ram:DueDateDateTime>\n"//20130704 //$NON-NLS-1$ //$NON-NLS-2$
+ " <ram:Description>Zahlbar ohne Abzug bis " + germanDateFormat.format(trans.getDueDate())
+ "</ram:Description>\n" + " <ram:DueDateDateTime><udt:DateTimeString format=\"102\">" //$NON-NLS-2$
+ zugferdDateFormat.format(trans.getDueDate()) + "</udt:DateTimeString></ram:DueDateDateTime>\n"// 20130704 //$NON-NLS-1$
+ " </ram:SpecifiedTradePaymentTerms>\n" //$NON-NLS-1$
+ " <ram:SpecifiedTradeSettlementHeaderMonetarySummation>\n" //$NON-NLS-1$
+ " <ram:LineTotalAmount>" + currencyFormat(getTotal()) + "</ram:LineTotalAmount>\n" //$NON-NLS-1$ //$NON-NLS-2$ currencyID=\"EUR\"
+ " <ram:ChargeTotalAmount>0.00</ram:ChargeTotalAmount>\n" //$NON-NLS-1$ currencyID=\"EUR\"
+ " <ram:AllowanceTotalAmount>0.00</ram:AllowanceTotalAmount>\n" //$NON-NLS-1$ // currencyID=\"EUR\"
// + " <ChargeTotalAmount currencyID=\"EUR\">5.80</ChargeTotalAmount>\n"
// + " <AllowanceTotalAmount currencyID=\"EUR\">14.73</AllowanceTotalAmount>\n"
+ " <ram:TaxBasisTotalAmount>" + currencyFormat(getTotal()) + "</ram:TaxBasisTotalAmount>\n" //$NON-NLS-1$ //$NON-NLS-2$ // currencyID=\"EUR\"
+ " <ram:TaxTotalAmount currencyID=\"EUR\">" + currencyFormat(getTotalGross().subtract(getTotal())) + "</ram:TaxTotalAmount>\n" //$NON-NLS-1$ //$NON-NLS-2$
+ " <ram:GrandTotalAmount>" + currencyFormat(getTotalGross()) + "</ram:GrandTotalAmount>\n" //$NON-NLS-1$ //$NON-NLS-2$ // currencyID=\"EUR\"
// + " <TotalPrepaidAmount currencyID=\"EUR\">0.00</TotalPrepaidAmount>\n"
+ " <ram:DuePayableAmount>" + currencyFormat(getTotalGross()) + "</ram:DuePayableAmount>\n" //$NON-NLS-1$ //$NON-NLS-2$ // currencyID=\"EUR\"
+ " <ram:LineTotalAmount>" + currencyFormat(getTotal()) + "</ram:LineTotalAmount>\n" //$NON-NLS-1$ //$NON-NLS-2$
// currencyID=\"EUR\"
+ " <ram:ChargeTotalAmount>0.00</ram:ChargeTotalAmount>\n" //$NON-NLS-1$ currencyID=\"EUR\"
+ " <ram:AllowanceTotalAmount>0.00</ram:AllowanceTotalAmount>\n" //$NON-NLS-1$ //
// currencyID=\"EUR\"
// + " <ChargeTotalAmount currencyID=\"EUR\">5.80</ChargeTotalAmount>\n"
// + " <AllowanceTotalAmount currencyID=\"EUR\">14.73</AllowanceTotalAmount>\n"
+ " <ram:TaxBasisTotalAmount>" + currencyFormat(getTotal()) + "</ram:TaxBasisTotalAmount>\n" //$NON-NLS-1$ //$NON-NLS-2$
// //
// currencyID=\"EUR\"
+ " <ram:TaxTotalAmount currencyID=\"EUR\">" //$NON-NLS-1$
+ currencyFormat(getTotalGross().subtract(getTotal())) + "</ram:TaxTotalAmount>\n" //$NON-NLS-1$
+ " <ram:GrandTotalAmount>" + currencyFormat(getTotalGross()) + "</ram:GrandTotalAmount>\n" //$NON-NLS-1$ //$NON-NLS-2$
// //
// currencyID=\"EUR\"
+ " <ram:TotalPrepaidAmount currencyID=\"EUR\">" + currencyFormat(getTotalPrepaid()) + "</ram:TotalPrepaidAmount>\n"
+ " <ram:DuePayableAmount>" + currencyFormat(getTotalGross().subtract(getTotalPrepaid())) + "</ram:DuePayableAmount>\n" //$NON-NLS-1$ //$NON-NLS-2$
// //
// currencyID=\"EUR\"
+ " </ram:SpecifiedTradeSettlementHeaderMonetarySummation>\n" //$NON-NLS-1$
+ " </ram:ApplicableHeaderTradeSettlement>\n"; //$NON-NLS-1$
// + " <IncludedSupplyChainTradeLineItem>\n"
// + " <AssociatedDocumentLineDocument>\n"
// + " <IncludedNote>\n"
// + " <Content>Wir erlauben uns Ihnen folgende Positionen aus der Lieferung Nr. 2013-51112 in Rechnung zu stellen:</Content>\n"
// + " </IncludedNote>\n"
// + " </AssociatedDocumentLineDocument>\n"
// + " </IncludedSupplyChainTradeLineItem>\n";
// + " <IncludedSupplyChainTradeLineItem>\n"
// + " <AssociatedDocumentLineDocument>\n"
// + " <IncludedNote>\n"
// + " <Content>Wir erlauben uns Ihnen folgende Positionen aus der Lieferung Nr.
// 2013-51112 in Rechnung zu stellen:</Content>\n"
// + " </IncludedNote>\n"
// + " </AssociatedDocumentLineDocument>\n"
// + " </IncludedSupplyChainTradeLineItem>\n";
xml = xml + " </rsm:SupplyChainTradeTransaction>\n" //$NON-NLS-1$
+ "</rsm:CrossIndustryInvoice>"; //$NON-NLS-1$
@@ -436,9 +558,8 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
zugferdData = zugferdRaw;
}
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} //$NON-NLS-1$
Logger.getLogger(Toecount.class.getName()).log(Level.SEVERE, null, e);
} // $NON-NLS-1$
}
}

View File

@@ -33,6 +33,7 @@ import org.apache.pdfbox.cos.COSArray;
import org.apache.pdfbox.cos.COSBase;
import org.apache.pdfbox.cos.COSDictionary;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.cos.COSObject;
import org.apache.pdfbox.pdmodel.*;
import org.apache.pdfbox.pdmodel.common.PDMetadata;
import org.apache.pdfbox.pdmodel.common.filespecification.PDComplexFileSpecification;
@@ -55,7 +56,7 @@ public class ZUGFeRDExporter implements Closeable {
public static final int DefaultZUGFeRDVersion = 1;
private static boolean isFacturX = false;
private boolean isFacturX = false;
/**
* To use the ZUGFeRD exporter, implement IZUGFeRDExportableTransaction in
@@ -96,7 +97,7 @@ public class ZUGFeRDExporter implements Closeable {
*/
protected String producer = "mustangproject";
/**
* Author/Creator attribute for PDF for PDF
* Author/Creator attribute for PDF
*/
protected String creator = "mustangproject";
/**
@@ -133,7 +134,7 @@ public class ZUGFeRDExporter implements Closeable {
additionalXMLs.put(filename, xml);
}
public static String getNamespaceForVersion(int ver) {
public String getNamespaceForVersion(int ver) {
if (isFacturX) {
return "urn:factur-x:pdfa:CrossIndustryDocument:invoice:1p0#";
} else if (ver == 1) {
@@ -146,7 +147,7 @@ public class ZUGFeRDExporter implements Closeable {
}
}
public static String getPrefixForVersion(int ver) {
public String getPrefixForVersion(int ver) {
if (isFacturX) {
return "fx";
} else {
@@ -154,11 +155,15 @@ public class ZUGFeRDExporter implements Closeable {
}
}
public static String getFilenameForVersion(int ver) {
public String getFilenameForVersion(int ver) {
if (isFacturX) {
return "factur-x.xml";
} else {
return "ZUGFeRD-invoice.xml";
if (ver==1) {
return "ZUGFeRD-invoice.xml";
} else {
return "zugferd-invoice.xml";
}
}
}
@@ -191,15 +196,16 @@ public class ZUGFeRDExporter implements Closeable {
/**
* All files are PDF/A-3, setConformance refers to the level conformance.
* <p/>
*
* PDF/A-3 has three conformance levels, called "A", "U" and "B".
* <p/>
* <p>
* PDF/A-3-B where B means only visually preservable, U -standard for Mustang-
* means visually and unicode preservable and A means full compliance, i.e.
* visually, unicode and structurally preservable and tagged PDF, i.e. useful
* metainformation for blind people.
* <p/>
* <p>
* Feel free to pass "A" as new level if you know what you are doing :-)
* @param newLevel "A", "U" or "B"
*
* @deprecated Use {@link ZUGFeRDExporterFromA1Factory} instead
*/
@@ -213,16 +219,17 @@ public class ZUGFeRDExporter implements Closeable {
/**
* All files are PDF/A-3, setConformance refers to the level conformance.
* <p/>
* <p>
* PDF/A-3 has three conformance levels, called "A", "U" and "B".
* <p/>
* <p>
* PDF/A-3-B where B means only visually preservable, U -standard for Mustang-
* means visually and unicode preservable and A means full compliance, i.e.
* visually, unicode and structurally preservable and tagged PDF, i.e. useful
* metainformation for blind people.
* <p/>
* <p>
* Feel free to pass "A" as new level if you know what you are doing :-)
*
* @param newLevel "A", "U" or "B"
* @deprecated Use
* {@link #setConformanceLevel(org.mustangproject.ZUGFeRD.PDFAConformanceLevel)}
* instead
@@ -247,27 +254,45 @@ public class ZUGFeRDExporter implements Closeable {
ignoreA1Errors = true;
}
/**
/***
* load from a pdf which is already A/3
* @param filename the PDF
* @throws IOException if anything is wrong with filename
* @deprecated Use the factory method {@link #createFromPDFA3(String)} instead
*/
@Deprecated
public void loadPDFA3(String filename) throws IOException {
doc = PDDocument.load(new File(filename));
}
/***
* factory create a ZUGFeRD exporter for a PDF/A-3 pdf file
* @param filename of the pdf
* @return the created ZUGFeRDExporter
* @throws IOException if something is wrong with filename
*/
public static ZUGFeRDExporter createFromPDFA3(String filename) throws IOException {
return new ZUGFeRDExporter(PDDocument.load(new File(filename)));
}
/**
* @deprecated Use the factory method {@link #createFromPDFA3(InputStream)}
* instead
* load from a pdf which is already A/3 from filestream
* @param file InputStream to load pdf from
* @deprecated Use the factory method {@link #createFromPDFA3(InputStream)} instead
* @throws IOException in case anything is wrong with file
*
*/
@Deprecated
public void loadPDFA3(InputStream file) throws IOException {
doc = PDDocument.load(file);
}
/***
* factory create a ZUGFeRD exporter for a PDF/A-3 inputstream
* @param pdfSource the InputStream of the pdf
* @return the created ZUGFeRDExporter
* @throws IOException (should not happen)
*/
public static ZUGFeRDExporter createFromPDFA3(InputStream pdfSource) throws IOException {
return new ZUGFeRDExporter(PDDocument.load(pdfSource));
}
@@ -275,7 +300,13 @@ public class ZUGFeRDExporter implements Closeable {
/**
* Makes A PDF/A3a-compliant document from a PDF-A1 compliant document (on the
* metadata level, this will not e.g. convert graphics to JPG-2000)
*
* @param filename the pdf
* @param producer the name of the xmp producer (app)
* @param creator the name of the xmp creator (user)
* @param attachZugferdHeaders whether to attach XMP ZUGFeRD headers
* @return the created PDFbox PDDocumentCatalog
* @throws IOException if anything is wrong with file
* @throws TransformerException in case of xml (XMP) parsing issues
* @deprecated use the {@link ZUGFeRDExporterFromA1Factory} instead
*/
@Deprecated
@@ -287,7 +318,18 @@ public class ZUGFeRDExporter implements Closeable {
return doc.getDocumentCatalog();
}
/**
/***
*
* Makes A PDF/A3a-compliant document from a PDF-A1 compliant document (on the
* metadata level, this will not e.g. convert graphics to JPG-2000)
* @param file the InputStream of the pdf
* @param producer the name of the xmp producer (app)
* @param creator the name of the xmp creator (user)
* @param attachZugferdHeaders whether to attach XMP ZUGFeRD headers
* @return the created PDFbox PDDocumentCatalog
* @throws IOException if anything is wrong with file
* @throws TransformerException in case of xml (XMP) parsing issues
* @deprecated use the {@link ZUGFeRDExporterFromA1Factory} instead
*/
@Deprecated
@@ -299,6 +341,7 @@ public class ZUGFeRDExporter implements Closeable {
return doc.getDocumentCatalog();
}
private IExporterFactory createPDFA1Factory() {
ZUGFeRDExporterFromA1Factory factory = new ZUGFeRDExporterFromA1Factory();
if (ignoreA1Errors) {
@@ -321,10 +364,11 @@ public class ZUGFeRDExporter implements Closeable {
* populate the XML. This parameter may be null, if so the XML data
* should hav ebeen set via
* <code>setZUGFeRDXMLData(byte[] zugferdData)</code>
* @throws IOException if anything is wrong with already loaded PDF
*/
public void PDFattachZugferdFile(IZUGFeRDExportableTransaction trans) throws IOException {
prepareDocument();
((IProfileProvider) xmlProvider).setProfile(profile);
xmlProvider.generateXML(trans);
String filename = getFilenameForVersion(ZFVersion);
PDFAttachGenericFile(doc, filename, "Alternative",
@@ -335,6 +379,11 @@ public class ZUGFeRDExporter implements Closeable {
}
}
/***
* Perform the final export to a now ZUGFeRD-enriched PDF file
* @param ZUGFeRDfilename the pdf file name
* @throws IOException if anything is wrong in the target location
*/
public void export(String ZUGFeRDfilename) throws IOException {
if (!documentPrepared) {
prepareDocument();
@@ -349,8 +398,17 @@ public class ZUGFeRDExporter implements Closeable {
}
}
/***
* Perform the final export to a now ZUGFeRD-enriched PDF file as OutputStream
* @param output the OutputStream
* @throws IOException if anything is wrong in the OutputStream
*/
public void export(OutputStream output) throws IOException {
if (!fileAttached) {
if (!documentPrepared) {
prepareDocument();
}
if ((!fileAttached) && (attachZUGFeRDHeaders)) {
throw new IOException(
"File must be attached (usually with PDFattachZugferdFile) before perfoming this operation");
}
@@ -369,7 +427,7 @@ public class ZUGFeRDExporter implements Closeable {
* @param description Human-readable description of the file content
* @param subType type of the data e.g. could be "text/xml" - mime like
* @param data the binary data of the file/attachment
* @throws java.io.IOException
* @throws java.io.IOException if anything is wrong with filename
*/
public void PDFAttachGenericFile(PDDocument doc, String filename, String relationship, String description,
String subType, byte[] data) throws IOException {
@@ -421,17 +479,27 @@ public class ZUGFeRDExporter implements Closeable {
doc.getDocumentCatalog().setNames(names);
// AF entry (Array) in catalog with the FileSpec
COSArray cosArray = (COSArray) doc.getDocumentCatalog().getCOSObject().getItem("AF");
if (cosArray == null) {
cosArray = new COSArray();
}
cosArray.add(fs);
COSDictionary dict2 = doc.getDocumentCatalog().getCOSObject();
COSArray array = new COSArray();
array.add(fs.getCOSObject()); // see below
dict2.setItem("AF", array);
doc.getDocumentCatalog().getCOSObject().setItem("AF", cosArray);
}
COSBase AFEntry = (COSBase)doc.getDocumentCatalog().getCOSObject().getItem("AF");
if ((AFEntry == null))
{
COSArray cosArray = new COSArray();
cosArray.add(fs);
doc.getDocumentCatalog().getCOSObject().setItem("AF", cosArray);
} else if (AFEntry instanceof COSArray)
{
COSArray cosArray = (COSArray)AFEntry;
cosArray.add(fs);
doc.getDocumentCatalog().getCOSObject().setItem("AF", cosArray);
} else if ((AFEntry instanceof COSObject) &&
((COSObject)AFEntry).getObject() instanceof COSArray)
{
COSArray cosArray = (COSArray)((COSObject)AFEntry).getObject();
cosArray.add(fs);
} else
{
throw new IOException("Unexpected object type for PDFDocument/Catalog/COSDictionary/Item(AF)");
}
}
/**
* Sets the ZUGFeRD XML data to be attached as a single byte array. This is
@@ -439,6 +507,7 @@ public class ZUGFeRDExporter implements Closeable {
* API or component.
*
* @param zugferdData XML data to be set as a byte array (XML file in raw form).
* @throws IOException (should not happen)
*/
public void setZUGFeRDXMLData(byte[] zugferdData) throws IOException {
CustomXMLProvider cus = new CustomXMLProvider();
@@ -488,19 +557,19 @@ public class ZUGFeRDExporter implements Closeable {
* neccessary PDF/A schema extension description to be able to add this
* information to RDF
*
* @param metadata
* @param metadata the PDFbox XMPMetadata object
*/
protected void addXMP(XMPMetadata metadata) {
if (attachZUGFeRDHeaders) {
XMPSchemaZugferd zf = new XMPSchemaZugferd(metadata, profile,
ZUGFeRDExporter.getNamespaceForVersion(ZFVersion), ZUGFeRDExporter.getPrefixForVersion(ZFVersion),
ZUGFeRDExporter.getFilenameForVersion(ZFVersion));
getNamespaceForVersion(ZFVersion), getPrefixForVersion(ZFVersion),
getFilenameForVersion(ZFVersion));
metadata.addSchema(zf);
}
XMPSchemaPDFAExtensions pdfaex = new XMPSchemaPDFAExtensions(metadata, ZFVersion, attachZUGFeRDHeaders);
XMPSchemaPDFAExtensions pdfaex = new XMPSchemaPDFAExtensions(this, metadata, ZFVersion, attachZUGFeRDHeaders);
pdfaex.setZUGFeRDVersion(ZFVersion);
metadata.addSchema(pdfaex);
@@ -517,12 +586,12 @@ public class ZUGFeRDExporter implements Closeable {
buffer.write(prefix.getBytes("UTF-8")); // see https://github.com/ZUGFeRD/mustangproject/issues/44
serializer.serialize(xmpMetadata, buffer, false);
buffer.write(suffix.getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (UnsupportedEncodingException e)
{
throw new TransformerException(e);
} catch (IOException e)
{
throw new TransformerException(e);
}
return buffer.toByteArray();
}
@@ -600,7 +669,7 @@ public class ZUGFeRDExporter implements Closeable {
/**
* the human author (use factory method instead)
*
* @param creator
* @param creator the (human) name who created the PDF
*/
@Deprecated
public void setCreator(String creator) {
@@ -610,7 +679,7 @@ public class ZUGFeRDExporter implements Closeable {
/**
* the CreatorTool attribute for the PDF
*
* @param creator
* @param creatorTool the application which created the PDF
*/
protected void setCreatorTool(String creatorTool) {
this.creatorTool = creatorTool;
@@ -619,7 +688,7 @@ public class ZUGFeRDExporter implements Closeable {
/**
* the authoring software (use factory method instead)
*
* @param producer
* @param producer the authoring software
*/
@Deprecated
public void setProducer(String producer) {
@@ -640,4 +709,17 @@ public class ZUGFeRDExporter implements Closeable {
this.attachZUGFeRDHeaders = attachZUGFeRDHeaders;
}
/**
* encapsulate the deprecated setters
* @param zfVersion 1 or 2
* @param zugferdConformanceLevel BASIC, COMFORT, EN16931, etc.
* @param creator PDF creator
* @param producer PDF producer
*/
public void configure(int zfVersion, ZUGFeRDConformanceLevel zugferdConformanceLevel, String creator, String producer) {
setZUGFeRDVersion(zfVersion);
setZUGFeRDConformanceLevel(zugferdConformanceLevel);
setCreator(creator);
setProducer(producer);
}
}

View File

@@ -63,20 +63,9 @@ public class ZUGFeRDExporterFromA3Factory implements IExporterFactory {
public ZUGFeRDExporter load(String pdfFilename) throws IOException {
ensurePDFIsValidPDFA(new FileDataSource(pdfFilename));
ZUGFeRDExporter zugFeRDExporter;
PDDocument doc = PDDocument.load(new File(pdfFilename));
zugFeRDExporter = new ZUGFeRDExporter(doc);
zugFeRDExporter.setZUGFeRDVersion(ZFVersion);
zugFeRDExporter.setZUGFeRDConformanceLevel(zugferdConformanceLevel);
zugFeRDExporter.setCreator(creator);
// Use creator as default for compatibility
zugFeRDExporter.setCreatorTool(creatorTool != null ? creatorTool : creator);
zugFeRDExporter.setProducer(producer);
zugFeRDExporter.setAttachZUGFeRDHeaders(attachZUGFeRDHeaders);
zugFeRDExporter.setPDFA3(ensurePDFisUpgraded);
return zugFeRDExporter;
try (FileInputStream pdf = new FileInputStream(pdfFilename)) {
return load(readAllBytes(pdf));
}
}
@@ -88,13 +77,9 @@ public class ZUGFeRDExporterFromA3Factory implements IExporterFactory {
*/
public ZUGFeRDExporter load(byte[] pdfBinary) throws IOException {
ensurePDFIsValidPDFA(new ByteArrayDataSource(new ByteArrayInputStream(pdfBinary)));
ZUGFeRDExporter zugFeRDExporter;
PDDocument doc = PDDocument.load(pdfBinary);
zugFeRDExporter = new ZUGFeRDExporter(doc);
zugFeRDExporter.setZUGFeRDVersion(ZFVersion);
zugFeRDExporter.setZUGFeRDConformanceLevel(zugferdConformanceLevel);
zugFeRDExporter.setCreator(creator);
zugFeRDExporter.setProducer(producer);
ZUGFeRDExporter zugFeRDExporter = new ZUGFeRDExporter(doc);
zugFeRDExporter.configure(ZFVersion, zugferdConformanceLevel, creator, producer);
zugFeRDExporter.setAttachZUGFeRDHeaders(attachZUGFeRDHeaders);
zugFeRDExporter.setPDFA3(ensurePDFisUpgraded);
@@ -173,14 +158,14 @@ public class ZUGFeRDExporterFromA3Factory implements IExporterFactory {
/**
* All files are PDF/A-3, setConformance refers to the level conformance.
* <p/>
* <p>
* PDF/A-3 has three coformance levels, called "A", "U" and "B".
* <p/>
* <p>
* PDF/A-3-B where B means only visually preservable, U -standard for Mustang-
* means visually and unicode preservable and A means full compliance, i.e.
* visually, unicode and structurally preservable and tagged PDF, i.e. useful
* metainformation for blind people.
* <p/>
* <p>
* Feel free to pass "A" as new level if you know what you are doing :-)
*/
public IExporterFactory setConformanceLevel(PDFAConformanceLevel newLevel) {

View File

@@ -32,6 +32,7 @@ import org.apache.pdfbox.pdmodel.PDEmbeddedFilesNameTreeNode;
import org.apache.pdfbox.pdmodel.common.PDNameTreeNode;
import org.apache.pdfbox.pdmodel.common.filespecification.PDComplexFileSpecification;
import org.apache.pdfbox.pdmodel.common.filespecification.PDEmbeddedFile;
import org.mustangproject.toecount.Toecount;
import org.w3c.dom.Document;
import org.xml.sax.SAXException;
@@ -45,31 +46,41 @@ import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
public class ZUGFeRDImporter {
/**
* @var if metadata has been found
* if metadata has been found
*/
private boolean containsMeta = false;
/**
* @var the reference (i.e. invoice number) of the sender
* map filenames of additional XML files to their contents
*/
private HashMap<String, byte[]> additionalXMLs = new HashMap<>();
/**
* Raw XML form of the extracted data - may be directly obtained.
*/
private byte[] rawXML = null;
/**
* XMP metadata
*/
private String xmpString = null; // XMP metadata
/**
* parsed Document
*/
private Document document;
public ZUGFeRDImporter(String pdfFilename) {
try {
BufferedInputStream bis = new BufferedInputStream(new FileInputStream(pdfFilename));
try (InputStream bis = Files.newInputStream(Paths.get(pdfFilename), StandardOpenOption.READ)) {
extractLowLevel(bis);
bis.close();
} catch (IOException e) {
e.printStackTrace();
Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e);
throw new ZUGFeRDExportException(e);
}
}
@@ -78,7 +89,7 @@ public class ZUGFeRDImporter {
try {
extractLowLevel(pdfStream);
} catch (IOException e) {
e.printStackTrace();
Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e);
throw new ZUGFeRDExportException(e);
}
}
@@ -122,15 +133,16 @@ public class ZUGFeRDImporter {
private void extractFiles(Map<String, PDComplexFileSpecification> names) throws IOException {
for (String filename : names.keySet()) {
for (String alias : names.keySet()) {
PDComplexFileSpecification fileSpec = names.get(alias);
String filename=fileSpec.getFilename();
/**
* currently (in the release candidate of version 1) only one attached file with
* the name ZUGFeRD-invoice.xml is allowed
* filenames for invoice data (ZUGFeRD v1 and v2, Factur-X)
*/
if ((filename.equals("ZUGFeRD-invoice.xml") || filename.equals("factur-x.xml"))) { //$NON-NLS-1$
if ((filename.equals("ZUGFeRD-invoice.xml") || (filename.equals("zugferd-invoice.xml")) || filename.equals("factur-x.xml"))) { //$NON-NLS-1$
containsMeta = true;
PDComplexFileSpecification fileSpec = names.get(filename);
PDEmbeddedFile embeddedFile = fileSpec.getEmbeddedFile();
// String embeddedFilename = filePath + filename;
// File file = new File(filePath + filename);
@@ -139,18 +151,14 @@ public class ZUGFeRDImporter {
// ByteArrayOutputStream();
// FileOutputStream fos = new FileOutputStream(file);
rawXML = embeddedFile.toByteArray();
setMeta(new String(rawXML));
setRawXML(embeddedFile.toByteArray());
// fos.write(embeddedFile.getByteArray());
// fos.close();
}
if (filename.startsWith("additional_data")) {
PDComplexFileSpecification fileSpec = names.get(filename);
PDEmbeddedFile embeddedFile = fileSpec.getEmbeddedFile();
additionalXMLs.put(filename, embeddedFile.toByteArray());
}
}
}
@@ -161,7 +169,7 @@ public class ZUGFeRDImporter {
try {
transformer = tf.newTransformer();
} catch (TransformerConfigurationException e) {
e.printStackTrace();
Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e);
}
transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
StringWriter writer = new StringWriter();
@@ -170,13 +178,52 @@ public class ZUGFeRDImporter {
System.err.println(output);
}
private Document getDocument() throws ParserConfigurationException, IOException, SAXException, TransformerException {
private Document getDocument() { return document; }
private void setDocument() throws ParserConfigurationException, IOException, SAXException {
DocumentBuilderFactory xmlFact = DocumentBuilderFactory.newInstance();
xmlFact.setNamespaceAware(false);
DocumentBuilder builder = xmlFact.newDocumentBuilder();
Document doc = builder.parse(new ByteArrayInputStream(rawXML));
//prettyPrint(doc);
return doc;
ByteArrayInputStream is = new ByteArrayInputStream(rawXML);
is.skip(guessBOMSize(is));
document = builder.parse(is);
}
public void setRawXML(byte[] rawXML) throws IOException {
this.rawXML = rawXML;
try {
setDocument();
} catch (ParserConfigurationException | SAXException e) {
Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e);
throw new ZUGFeRDExportException(e);
}
}
/**
* Skips over a BOM at the beginning of the given ByteArrayInputStream, if one exists.
* @param is the ByteArrayInputStream used
* @throws IOException
* @see <a href="https://www.w3.org/TR/xml/#sec-guessing">Autodetection of Character Encodings</a>
*/
private int guessBOMSize(ByteArrayInputStream is) throws IOException {
byte[] pad = new byte[4];
is.read(pad);
is.reset();
int test2 = ((pad[0] & 0xFF) << 8) | (pad[1] & 0xFF);
int test3 = ((test2 & 0xFFFF) << 8) | (pad[2] & 0xFF);
int test4 = ((test3 & 0xFFFFFF) << 8) | (pad[3] & 0xFF);
//
if (test4 == 0x0000FEFF || test4 == 0xFFFE0000 || test4 == 0x0000FFFE || test4 == 0xFEFF0000) {
// UCS-4: BOM takes 4 bytes
return 4;
} else if (test3 == 0xEFBBFF) {
// UTF-8: BOM takes 3 bytes
return 3;
} else if (test2 == 0xFEFF || test2 == 0xFFFE) {
// UTF-16: BOM takes 2 bytes
return 2;
}
return 0;
}
private String extractString(String xpathStr) {
@@ -189,11 +236,8 @@ public class ZUGFeRDImporter {
XPathFactory xpathFact = XPathFactory.newInstance();
XPath xpath = xpathFact.newXPath();
result = xpath.evaluate(xpathStr, document);
} catch (ParserConfigurationException e) {
e.printStackTrace();
throw new ZUGFeRDExportException(e);
} catch (IOException | SAXException | TransformerException | XPathExpressionException e) {
e.printStackTrace();
} catch (XPathExpressionException e) {
Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e);
throw new ZUGFeRDExportException(e);
}
return result;
@@ -217,12 +261,30 @@ public class ZUGFeRDImporter {
}
/**
* @return the sender's bank's BLZ code
* @return the referred document
*/
public String getReference() {
return extractString("//ApplicableHeaderTradeAgreement/BuyerReference");
}
/**
* @return the sender's bank's BLZ code
* @deprecated use BIC and IBAN instead of BLZ and KTO
*/
@Deprecated
public String getBLZ() {
return extractString("//PayeeSpecifiedCreditorFinancialInstitution/GermanBankleitzahlID");
}
/**
* @return the sender's account number
* @deprecated use BIC and IBAN instead of BLZ and KTO
*/
@Deprecated
public String getKTO() {
return extractString("//PayeePartyCreditorFinancialAccount/ProprietaryID");
}
/**
* @return the sender's bank's BIC code
*/
@@ -230,21 +292,21 @@ public class ZUGFeRDImporter {
return extractString("//PayeeSpecifiedCreditorFinancialInstitution/BICID");
}
/**
* @return the sender's bankname
* @return the sender's bank name
*/
public String getBankName() {
return extractString("/CrossIndustryInvoice/SupplyChainTradeTransaction/ApplicableHeaderTradeSettlement/SpecifiedTradeSettlementPaymentMeans/PayeeSpecifiedCreditorFinancialInstitution/Name");
return extractString("//PayeeSpecifiedCreditorFinancialInstitution/Name");
}
/**
* @return the sender's account IBAN code
*/
public String getIBAN() {
return extractString("//PayeePartyCreditorFinancialAccount/IBANID");
}
public String getKTO() {
return extractString("//PayeePartyCreditorFinancialAccount/ProprietaryID");
}
public String getHolder() {
return extractString("//SellerTradeParty/Name");
}
@@ -290,8 +352,8 @@ public class ZUGFeRDImporter {
/**
* @param meta raw XML to be set
*/
public void setMeta(String meta) {
this.rawXML = meta.getBytes();
public void setMeta(String meta) throws IOException {
setRawXML(meta.getBytes());
}
/**
@@ -336,6 +398,7 @@ public class ZUGFeRDImporter {
/**
* Returns the raw XML data as extracted from the ZUGFeRD PDF file.
* @return the raw ZUGFeRD XML data
*/
public byte[] getRawXML() {
return rawXML;
@@ -359,7 +422,7 @@ public class ZUGFeRDImporter {
static String convertStreamToString(java.io.InputStream is) {
// source https://stackoverflow.com/questions/309424/how-do-i-read-convert-an-inputstream-into-a-string-in-java referring to
// https://community.oracle.com/blogs/pat/2004/10/23/stupid-scanner-tricks
Scanner s = new Scanner(is).useDelimiter("\\A");
Scanner s = new Scanner(is, "UTF-8").useDelimiter("\\A");
return s.hasNext() ? s.next() : "";
}

View File

@@ -63,8 +63,22 @@ public class ZUGFeRDMigrator {
*/
ByteArrayOutputStream baos = new ByteArrayOutputStream();
applySchematronXsl(new FileInputStream(xmlFilename), baos);
String res = null;
res = baos.toString("UTF-8");
//migrate the profiles
res=res.replace("urn:ferd:CrossIndustryDocument:invoice:1p0:basic", "urn:cen.eu:en16931:2017#compliant#urn:zugferd.de:2p0:basic");
res=res.replace("urn:ferd:CrossIndustryDocument:invoice:1p0:comfort", "urn:cen.eu:en16931:2017");
res=res.replace("urn:ferd:CrossIndustryDocument:invoice:1p0:extended", "urn:cen.eu:en16931:2017#conformant#urn:zugferd.de:2p0:extended");
//somehow the XML parser seems to insert erreneous XML namespaces, depending on which one it is, saxon seems to be cleaner.
//nevertheless, remove them manually
res=res.replace("<rsm:ExchangedDocument xmlns:qdt=\"urn:un:unece:uncefact:data:standard:QualifiedDataType:100\">", "<rsm:ExchangedDocument>");
res=res.replace("<rsm:SupplyChainTradeTransaction xmlns:qdt=\"urn:un:unece:uncefact:data:standard:QualifiedDataType:100\">", "<rsm:SupplyChainTradeTransaction>");
return res;
}

View File

@@ -19,6 +19,7 @@
package org.mustangproject.ZUGFeRD;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.SimpleDateFormat;
@@ -29,53 +30,7 @@ import java.util.HashMap;
import java.util.List;
import javax.xml.bind.JAXBElement;
import org.mustangproject.ZUGFeRD.model.AmountType;
import org.mustangproject.ZUGFeRD.model.CodeType;
import org.mustangproject.ZUGFeRD.model.CountryIDType;
import org.mustangproject.ZUGFeRD.model.CreditorFinancialAccountType;
import org.mustangproject.ZUGFeRD.model.CreditorFinancialInstitutionType;
import org.mustangproject.ZUGFeRD.model.CrossIndustryDocumentType;
import org.mustangproject.ZUGFeRD.model.DateTimeType;
import org.mustangproject.ZUGFeRD.model.DateTimeTypeConstants;
import org.mustangproject.ZUGFeRD.model.DocumentCodeType;
import org.mustangproject.ZUGFeRD.model.DocumentContextParameterType;
import org.mustangproject.ZUGFeRD.model.DocumentContextParameterTypeConstants;
import org.mustangproject.ZUGFeRD.model.DocumentLineDocumentType;
import org.mustangproject.ZUGFeRD.model.ExchangedDocumentContextType;
import org.mustangproject.ZUGFeRD.model.ExchangedDocumentType;
import org.mustangproject.ZUGFeRD.model.IDType;
import org.mustangproject.ZUGFeRD.model.IndicatorType;
import org.mustangproject.ZUGFeRD.model.LogisticsServiceChargeType;
import org.mustangproject.ZUGFeRD.model.NoteType;
import org.mustangproject.ZUGFeRD.model.NoteTypeConstants;
import org.mustangproject.ZUGFeRD.model.ObjectFactory;
import org.mustangproject.ZUGFeRD.model.PaymentMeansCodeType;
import org.mustangproject.ZUGFeRD.model.PaymentMeansCodeTypeConstants;
import org.mustangproject.ZUGFeRD.model.PercentType;
import org.mustangproject.ZUGFeRD.model.QuantityType;
import org.mustangproject.ZUGFeRD.model.ReferencedDocumentType;
import org.mustangproject.ZUGFeRD.model.SupplyChainEventType;
import org.mustangproject.ZUGFeRD.model.SupplyChainTradeAgreementType;
import org.mustangproject.ZUGFeRD.model.SupplyChainTradeDeliveryType;
import org.mustangproject.ZUGFeRD.model.SupplyChainTradeLineItemType;
import org.mustangproject.ZUGFeRD.model.SupplyChainTradeSettlementType;
import org.mustangproject.ZUGFeRD.model.SupplyChainTradeTransactionType;
import org.mustangproject.ZUGFeRD.model.TaxCategoryCodeType;
import org.mustangproject.ZUGFeRD.model.TaxRegistrationType;
import org.mustangproject.ZUGFeRD.model.TaxRegistrationTypeConstants;
import org.mustangproject.ZUGFeRD.model.TaxTypeCodeType;
import org.mustangproject.ZUGFeRD.model.TaxTypeCodeTypeConstants;
import org.mustangproject.ZUGFeRD.model.TextType;
import org.mustangproject.ZUGFeRD.model.TradeAddressType;
import org.mustangproject.ZUGFeRD.model.TradeAllowanceChargeType;
import org.mustangproject.ZUGFeRD.model.TradePartyType;
import org.mustangproject.ZUGFeRD.model.TradePaymentTermsType;
import org.mustangproject.ZUGFeRD.model.TradePriceType;
import org.mustangproject.ZUGFeRD.model.TradeProductType;
import org.mustangproject.ZUGFeRD.model.TradeSettlementMonetarySummationType;
import org.mustangproject.ZUGFeRD.model.TradeSettlementPaymentMeansType;
import org.mustangproject.ZUGFeRD.model.TradeTaxType;
import org.mustangproject.ZUGFeRD.model.*;
class ZUGFeRDTransactionModelConverter {
private static final SimpleDateFormat zugferdDateFormat = new SimpleDateFormat("yyyyMMdd");
@@ -85,6 +40,7 @@ class ZUGFeRDTransactionModelConverter {
private final Totals totals;
private boolean isTest;
private String currency = "EUR";
private String profile;
ZUGFeRDTransactionModelConverter(IZUGFeRDExportableTransaction trans) {
@@ -114,7 +70,7 @@ class ZUGFeRDTransactionModelConverter {
DocumentContextParameterType contextParameter = xmlFactory
.createDocumentContextParameterType();
IDType idType = xmlFactory.createIDType();
idType.setValue(DocumentContextParameterTypeConstants.EXTENDED);
idType.setValue(profile);
contextParameter.setID(idType);
context.getGuidelineSpecifiedDocumentContextParameter().add(
contextParameter);
@@ -150,7 +106,7 @@ class ZUGFeRDTransactionModelConverter {
document.setTypeCode(documentCodeType);
TextType name = xmlFactory.createTextType();
name.setValue("RECHNUNG");
name.setValue(trans.getDocumentName());
document.getName().add(name);
if (trans.getOwnOrganisationFullPlaintextInfo() != null) {
@@ -168,7 +124,7 @@ class ZUGFeRDTransactionModelConverter {
if (trans.getReferenceNumber() != null && !"".equals(trans.getReferenceNumber())) {
NoteType referenceInfo = xmlFactory.createNoteType();
TextType referenceInfoContent = xmlFactory.createTextType();
referenceInfoContent.setValue("Ursprungsbeleg: " + trans.getReferenceNumber());
referenceInfoContent.setValue(trans.getReferenceNumber());
referenceInfo.getContent().add(referenceInfoContent);
document.getIncludedNote().add(referenceInfo);
}
@@ -200,8 +156,13 @@ class ZUGFeRDTransactionModelConverter {
tradeAgreement.setBuyerTradeParty(getBuyer());
tradeAgreement.setSellerTradeParty(getSeller());
if (getBuyerOrderReferencedDocument() != null) {
tradeAgreement.getBuyerOrderReferencedDocument().add(getBuyerOrderReferencedDocument());
if (trans.getBuyerOrderReferencedDocumentID() != null) {
ReferencedDocumentType refdoc = xmlFactory.createReferencedDocumentType();
IDType id = xmlFactory.createIDType();
id.setValue(trans.getBuyerOrderReferencedDocumentID());
refdoc.getID().add(id);
refdoc.setIssueDateTime(trans.getBuyerOrderReferencedDocumentIssueDateTime());
tradeAgreement.getBuyerOrderReferencedDocument().add(refdoc);
}
return tradeAgreement;
@@ -232,6 +193,12 @@ class ZUGFeRDTransactionModelConverter {
buyerID.setValue(trans.getRecipient().getID());
buyerTradeParty.getID().add(buyerID);
}
if (trans.getRecipient().getGlobalID() != null) {
IDType globalID = xmlFactory.createIDType();
globalID.setValue(trans.getRecipient().getGlobalID());
globalID.setSchemeID(trans.getRecipient().getGlobalIDScheme());
buyerTradeParty.getGlobalID().add(globalID);
}
TextType buyerName = xmlFactory.createTextType();
buyerName.setValue(trans.getRecipient().getName());
@@ -410,7 +377,7 @@ class ZUGFeRDTransactionModelConverter {
currencyCode.setValue(currency);
tradeSettlement.setInvoiceCurrencyCode(currencyCode);
tradeSettlement.getSpecifiedTradeSettlementPaymentMeans().add(
tradeSettlement.getSpecifiedTradeSettlementPaymentMeans().addAll(
getPaymentData());
tradeSettlement.getApplicableTradeTax().addAll(getTradeTax());
tradeSettlement.getSpecifiedTradePaymentTerms().addAll(
@@ -434,46 +401,50 @@ class ZUGFeRDTransactionModelConverter {
}
private TradeSettlementPaymentMeansType getPaymentData() {
TradeSettlementPaymentMeansType paymentData = xmlFactory
.createTradeSettlementPaymentMeansType();
PaymentMeansCodeType paymentDataType = xmlFactory
.createPaymentMeansCodeType();
paymentDataType.setValue(PaymentMeansCodeTypeConstants.BANKACCOUNT);
paymentData.setTypeCode(paymentDataType);
private List<TradeSettlementPaymentMeansType> getPaymentData() {
List<TradeSettlementPaymentMeansType> result = new ArrayList<>();
for (IZUGFeRDTradeSettlementPayment settlementPayment : trans.getTradeSettlementPayment()) {
TradeSettlementPaymentMeansType paymentData = xmlFactory
.createTradeSettlementPaymentMeansType();
PaymentMeansCodeType paymentDataType = xmlFactory
.createPaymentMeansCodeType();
paymentDataType.setValue(PaymentMeansCodeTypeConstants.BANKACCOUNT);
paymentData.setTypeCode(paymentDataType);
TextType paymentInfo = xmlFactory.createTextType();
String paymentInfoText = trans.getOwnPaymentInfoText();
if (paymentInfoText == null) {
paymentInfoText = "";
TextType paymentInfo = xmlFactory.createTextType();
String paymentInfoText = settlementPayment.getOwnPaymentInfoText();
if (paymentInfoText == null) {
paymentInfoText = "";
}
paymentInfo.setValue(paymentInfoText);
paymentData.getInformation().add(paymentInfo);
CreditorFinancialAccountType bankAccount = xmlFactory
.createCreditorFinancialAccountType();
IDType iban = xmlFactory.createIDType();
iban.setValue(settlementPayment.getOwnIBAN());
bankAccount.setIBANID(iban);
IDType kto = xmlFactory.createIDType();
kto.setValue(settlementPayment.getOwnKto());
bankAccount.setProprietaryID(kto);
paymentData.setPayeePartyCreditorFinancialAccount(bankAccount);
CreditorFinancialInstitutionType bankData = xmlFactory
.createCreditorFinancialInstitutionType();
IDType bicId = xmlFactory.createIDType();
bicId.setValue(settlementPayment.getOwnBIC());
bankData.setBICID(bicId);
TextType bankName = xmlFactory.createTextType();
bankName.setValue(settlementPayment.getOwnBankName());
bankData.setName(bankName);
IDType blz = xmlFactory.createIDType();
blz.setValue(settlementPayment.getOwnBLZ());
bankData.setGermanBankleitzahlID(blz);
paymentData.setPayeeSpecifiedCreditorFinancialInstitution(bankData);
result.add(paymentData);
}
paymentInfo.setValue(paymentInfoText);
paymentData.getInformation().add(paymentInfo);
CreditorFinancialAccountType bankAccount = xmlFactory
.createCreditorFinancialAccountType();
IDType iban = xmlFactory.createIDType();
iban.setValue(trans.getOwnIBAN());
bankAccount.setIBANID(iban);
IDType kto = xmlFactory.createIDType();
kto.setValue(trans.getOwnKto());
bankAccount.setProprietaryID(kto);
paymentData.setPayeePartyCreditorFinancialAccount(bankAccount);
CreditorFinancialInstitutionType bankData = xmlFactory
.createCreditorFinancialInstitutionType();
IDType bicId = xmlFactory.createIDType();
bicId.setValue(trans.getOwnBIC());
bankData.setBICID(bicId);
TextType bankName = xmlFactory.createTextType();
bankName.setValue(trans.getOwnBankName());
bankData.setName(bankName);
IDType blz = xmlFactory.createIDType();
blz.setValue(trans.getOwnBLZ());
bankData.setGermanBankleitzahlID(blz);
paymentData.setPayeeSpecifiedCreditorFinancialInstitution(bankData);
return paymentData;
return result;
}
@@ -490,7 +461,7 @@ class ZUGFeRDTransactionModelConverter {
TaxCategoryCodeType taxCategoryCode = xmlFactory.createTaxCategoryCodeType();
VATAmount vatAmount = VATPercentAmountMap.get(currentTaxPercent);
taxCategoryCode.setValue(vatAmount.getDocumentCode());
taxCategoryCode.setValue(vatAmount.getCategoryCode());
tradeTax.setCategoryCode(taxCategoryCode);
VATAmount amount = VATPercentAmountMap.get(currentTaxPercent);
@@ -754,9 +725,14 @@ class ZUGFeRDTransactionModelConverter {
grandTotalAmount.setValue(currencyFormat(totals.getTotalGross()));
monetarySummation.getGrandTotalAmount().add(grandTotalAmount);
AmountType totalPrepaidAmount = xmlFactory.createAmountType();
totalPrepaidAmount.setCurrencyID(currency);
totalPrepaidAmount.setValue(currencyFormat(trans.getTotalPrepaidAmount()));
monetarySummation.getTotalPrepaidAmount().add(totalPrepaidAmount);
AmountType duePayableAmount = xmlFactory.createAmountType();
duePayableAmount.setCurrencyID(currency);
duePayableAmount.setValue(currencyFormat(totals.getTotalGross()));
duePayableAmount.setValue(currencyFormat(totals.getTotalGross().subtract(trans.getTotalPrepaidAmount())));
monetarySummation.getDuePayableAmount().add(duePayableAmount);
return monetarySummation;
@@ -911,70 +887,26 @@ class ZUGFeRDTransactionModelConverter {
private BigDecimal vatFormat(BigDecimal value) {
return nDigitFormat(value, 2);
}
return value.setScale(2, RoundingMode.HALF_UP);
}
private BigDecimal currencyFormat(BigDecimal value) {
return nDigitFormat(value, 2);
}
return value.setScale(2, RoundingMode.HALF_UP);
}
private BigDecimal priceFormat(BigDecimal value) {
return nDigitFormat(value, 4);
}
return value.setScale(4, RoundingMode.HALF_UP);
}
private BigDecimal quantityFormat(BigDecimal value) {
return nDigitFormat(value, 4);
}
private BigDecimal 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
*
* This function will cut off, i.e. floor() subcent values Tests:
* System.err.println(utils.currencyFormat(new BigDecimal(0),
* ".")+"\n"+utils.currencyFormat(new BigDecimal("-1.10"),
* ",")+"\n"+utils.currencyFormat(new BigDecimal("-1.1"),
* ",")+"\n"+utils.currencyFormat(new BigDecimal("-1.01"),
* ",")+"\n"+utils.currencyFormat(new BigDecimal("20000123.3489"),
* ",")+"\n"+utils.currencyFormat(new BigDecimal("20000123.3419"),
* ",")+"\n"+utils.currencyFormat(new BigDecimal("12"), ","));
*
* results 0.00 -1,10 -1,10 -1,01 20000123,34 20000123,34 12,00
*/
value = value.setScale(scale, BigDecimal.ROUND_HALF_UP); // first, round
// so that
// e.g.
// 1.189999999999999946709294817992486059665679931640625
// becomes
// 1.19
char[] repeat = new char[scale];
Arrays.fill(repeat, '0');
DecimalFormatSymbols otherSymbols = new DecimalFormatSymbols();
otherSymbols.setDecimalSeparator('.');
DecimalFormat dec = new DecimalFormat("0." + new String(repeat),
otherSymbols);
return new BigDecimal(dec.format(value));
}
return value.setScale(4, RoundingMode.HALF_UP);
}
/**
* which taxes have been used with which amounts in this transaction, empty for no taxes, or e.g. 19=>190 and 7=>14 if 1000 Eur were applicable to 19% VAT
* (=>190 EUR VAT) and 200 EUR were applicable to 7% (=>14 EUR VAT) 190 Eur
@@ -992,7 +924,7 @@ class ZUGFeRDTransactionModelConverter {
for (IZUGFeRDExportableItem currentItem : trans.getZFItems()) {
BigDecimal percent = currentItem.getProduct().getVATPercent();
LineCalc lc = new LineCalc(currentItem);
VATAmount itemVATAmount = new VATAmount(lc.getItemTotalNetAmount(), lc.getItemTotalVATAmount(), trans.getDocumentCode());
VATAmount itemVATAmount = new VATAmount(lc.getItemTotalNetAmount(), lc.getItemTotalVATAmount(), lc.getCategoryCode());
VATAmount current = hm.get(percent);
if (current == null) {
hm.put(percent, itemVATAmount);
@@ -1027,8 +959,7 @@ class ZUGFeRDTransactionModelConverter {
VATAmount itemVATAmount = new VATAmount(
logisticsServiceCharge.getTotalAmount(),
logisticsServiceCharge.getTotalAmount()
.multiply(percent).divide(new BigDecimal(100)),
trans.getDocumentCode());
.multiply(percent).divide(new BigDecimal(100)), logisticsServiceCharge.getCategoryCode());
VATAmount current = hm.get(percent);
if (current == null) {
hm.put(percent, itemVATAmount);
@@ -1043,8 +974,7 @@ class ZUGFeRDTransactionModelConverter {
BigDecimal percent = charge.getTaxPercent();
VATAmount itemVATAmount = new VATAmount(
charge.getTotalAmount(), charge.getTotalAmount()
.multiply(percent).divide(new BigDecimal(100)),
trans.getDocumentCode());
.multiply(percent).divide(new BigDecimal(100)), charge.getCategoryCode());
VATAmount current = hm.get(percent);
if (current == null) {
hm.put(percent, itemVATAmount);
@@ -1063,12 +993,18 @@ class ZUGFeRDTransactionModelConverter {
return this;
}
public ZUGFeRDTransactionModelConverter withProfile(String profile) {
this.profile = profile;
return this;
}
private class LineCalc {
private BigDecimal totalGross;
private BigDecimal itemTotalNetAmount;
private BigDecimal itemTotalVATAmount;
private BigDecimal itemNetAmount;
private String categoryCode;
public LineCalc(IZUGFeRDExportableItem currentItem) {
@@ -1111,6 +1047,7 @@ class ZUGFeRDTransactionModelConverter {
.add(totalCharge)
.divide(currentItem.getQuantity(), 4,
BigDecimal.ROUND_HALF_UP);
categoryCode = currentItem.getCategoryCode();
}
@@ -1128,6 +1065,8 @@ class ZUGFeRDTransactionModelConverter {
return itemNetAmount;
}
public String getCategoryCode() { return categoryCode; }
}
private class Totals {

View File

@@ -0,0 +1,165 @@
/** **********************************************************************
*
* Copyright 2018 Jochen Staerk
*
* Use is subject to license terms.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0.
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
* See the License for the specific language governing permissions and
* limitations under the License.
*
*********************************************************************** */
package org.mustangproject.ZUGFeRD;
import javax.xml.transform.*;
import javax.xml.transform.stream.StreamResult;
import javax.xml.transform.stream.StreamSource;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.logging.Level;
import java.util.logging.Logger;
public class ZUGFeRDVisualizer {
static final ClassLoader CLASS_LOADER = ZUGFeRDVisualizer.class.getClassLoader();
private static final String RESOURCE_PATH = ""; //$NON-NLS-1$
private static final Logger LOG = Logger.getLogger(ZUGFeRDVisualizer.class.getName());
// private static File createTempFileResult(final Transformer transformer, final
// StreamSource toTransform,
// final String suffix) throws TransformerException, IOException {
// File result = File.createTempFile("ZUV_", suffix); //$NON-NLS-1$
// result.deleteOnExit();
//
// try (FileOutputStream fos = new FileOutputStream(result)) {
// transformer.transform(toTransform, new StreamResult(fos));
// }
// return result;
// }
private TransformerFactory mFactory = null;
private Templates mXsltXRTemplate = null;
private Templates mXsltHTMLTemplate = null;
private Templates mXsltZF1HTMLTemplate = null;
public ZUGFeRDVisualizer() {
mFactory = new net.sf.saxon.TransformerFactoryImpl();
// fact = TransformerFactory.newInstance();
mFactory.setURIResolver(new ClasspathResourceURIResolver());
try {
mXsltXRTemplate = mFactory.newTemplates(
new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/cii-xr.xsl")));
mXsltHTMLTemplate = mFactory.newTemplates(new StreamSource(
CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/xrechnung-html.xsl")));
mXsltZF1HTMLTemplate = mFactory.newTemplates(new StreamSource(
CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/ZUGFeRD_1p0_c1p0_s1p0.xslt")));
} catch (TransformerConfigurationException ex) {
LOG.log(Level.SEVERE, null, ex);
}
}
public String visualize(String xmlFilename)
throws FileNotFoundException, TransformerException, UnsupportedEncodingException {
/**
* *
* http://www.unece.org/fileadmin/DAM/cefact/xml/XML-Naming-And-Design-Rules-V2_1.pdf
* http://www.ferd-net.de/upload/Dokumente/FACTUR-X_ZUGFeRD_2p0_Teil1_Profil_EN16931_1p03.pdf
* http://countwordsfree.com/xmlviewer
*/
FileInputStream fis=new FileInputStream(xmlFilename);
String fileContent="";
try {
fileContent = new String(Files.readAllBytes(Paths.get(xmlFilename)));
} catch (IOException e2) {
LOG.log(Level.SEVERE, null, e2);
}
ByteArrayOutputStream iaos = new ByteArrayOutputStream();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
String zf1Signature = "rsm:CrossIndustryDocument";
if (fileContent.contains(zf1Signature)) {
applyZF1SchematronXsl(fis, baos);
} else {
//zf2 or fx
applySchematronXsl(fis, iaos);
// take the copy of the stream and re-write it to an InputStream
PipedInputStream in = new PipedInputStream();
PipedOutputStream out;
try {
out = new PipedOutputStream(in);
new Thread(new Runnable() {
public void run() {
try {
// write the original OutputStream to the PipedOutputStream
// note that in order for the below method to work, you need
// to ensure that the data has finished writing to the
// ByteArrayOutputStream
iaos.writeTo(out);
} catch (IOException e) {
LOG.log(Level.SEVERE, null, e);
} finally {
// close the PipedOutputStream here because we're done writing data
// once this thread has completed its run
if (out != null) {
// close the PipedOutputStream cleanly
try {
out.close();
} catch (IOException e) {
// TODO Auto-generated catch block
LOG.log(Level.SEVERE, null, e);
}
}
}
}
}).start();
applySchematronXsl2(in, baos);
} catch (IOException e1) {
LOG.log(Level.SEVERE, null, e1);
}
}
return baos.toString("UTF-8");
}
public void applySchematronXsl(final InputStream xmlFile, final OutputStream HTMLOutstream)
throws TransformerException {
Transformer transformer = mXsltXRTemplate.newTransformer();
transformer.transform(new StreamSource(xmlFile), new StreamResult(HTMLOutstream));
}
public void applyZF1SchematronXsl(final InputStream xmlFile, final OutputStream HTMLOutstream)
throws TransformerException {
Transformer transformer = mXsltZF1HTMLTemplate.newTransformer();
transformer.transform(new StreamSource(xmlFile), new StreamResult(HTMLOutstream));
}
public void applySchematronXsl2(final InputStream xmlFile, final OutputStream HTMLOutstream)
throws TransformerException {
Transformer transformer = mXsltHTMLTemplate.newTransformer();
transformer.transform(new StreamSource(xmlFile), new StreamResult(HTMLOutstream));
}
private static class ClasspathResourceURIResolver implements URIResolver {
ClasspathResourceURIResolver() {
// Do nothing, just prevents synthetic access warning.
}
@Override
public Source resolve(String href, String base) throws TransformerException {
return new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + href));
}
}
}

View File

@@ -19,7 +19,7 @@
package org.mustangproject.ZUGFeRD.model;
public class DocumentContextParameterTypeConstants {
public static final String BASIC = "urn:ferd:CrossIndustryDocument:invoice:1p0:basic";
public static final String COMFORT = "urn:ferd:CrossIndustryDocument:invoice:1p0:comfort";
public static final String EXTENDED = "urn:ferd:CrossIndustryDocument:invoice:1p0:extended";
// this does not look complete :-/
}

View File

@@ -30,8 +30,14 @@ import org.mustangproject.ZUGFeRD.*;
import javax.xml.transform.TransformerException;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
@@ -69,8 +75,9 @@ public class Toecount {
+ " [--source <filename>]: set input PDF file\n"
+ " [--source-xml <filename>]: set input XML file\n"
+ " [--out <filename>]: set output PDF file\n"
+ " [--zugferd-version <1|2>]: set ZUGFeRD version\n"
+ " [--zugferd-profile <...>]: set ZUGFeRD profile\n"
+ " [--format <fx|zf>]: set ZUGFeRD or FacturX\n"
+ " [--version <1|2>]: set ZUGFeRD version\n"
+ " [--profile <...>]: set ZUGFeRD profile\n"
+ " For ZUGFeRD v1: <B>ASIC, <C>OMFORT or <E>XTENDED\n"
+ " For ZUGFeRD v2: <M>INIMUM, BASIC <W>L, <B>ASIC, <C>IUS, <E>N16931, E<X>TENDED ";
}
@@ -102,8 +109,8 @@ public class Toecount {
+ "\t\t[--source <filename>]: set input PDF file\r\n"
+ "\t\t[--source-xml <filename>]: set input XML file\r\n"
+ "\t\t[--out <filename>]: set output PDF file\r\n"
+ "\t\t[--zugferd-version <1|2>]: set ZUGFeRD version\r\n"
+ "\t\t[--zugferd-profile <...>]: set ZUGFeRD profile\r\n"
+ "\t\t[--format <fx|zf>]: enable factur-x or ZUGFeRD\r\n"
+ "\t\t[--version <1|2>]: set ZUGFeRD version\r\n" + "\t\t[--profile <...>]: set ZUGFeRD profile\r\n"
+ "\t\t\tFor ZUGFeRD v1: <B>ASIC, <C>OMFORT or <E>XTENDED\r\n"
+ "\t\t\tFor ZUGFeRD v2: <M>INIMUM, BASIC <W>L, <B>ASIC, <C>IUS, <E>N16931, E<X>TENDED\r\n");
}
@@ -112,11 +119,15 @@ public class Toecount {
* Asks the user (repeatedly, if neccessary) on the command line for a String
* (offering a defaultValue) conforming to a Regex pattern
*
* @param prompt the question to be asked to the user
* @param defaultValue the default return value if user hits enter
* @param pattern a regex of acceptable values
* @param prompt
* the question to be asked to the user
* @param defaultValue
* the default return value if user hits enter
* @param pattern
* a regex of acceptable values
* @return the user answer conforming to pattern
* @throws Exception if pattern not compielable or IOexception on input
* @throws Exception
* if pattern not compielable or IOexception on input
*/
protected static String getStringFromUser(String prompt, String defaultValue, String pattern) throws Exception {
String input = "";
@@ -137,8 +148,8 @@ public class Toecount {
try {
input = buffer.readLine();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Logger.getLogger(Toecount.class.getName()).log(Level.SEVERE, null, e);
}
if (input.isEmpty()) {
@@ -155,15 +166,15 @@ public class Toecount {
/**
* Prompts the user for a input or output filename
*
* @param the text the user is asked
* @param a default Filename
* @param expectedExtension will warn if filename does not match expected file extension
* @param ensureFileExists will warn if file does NOT exist (for input files)
* @param prompt the text the user is asked
* @param defaultFilename a default Filename
* @param expectedExtension will warn if filename does not match expected file extension
* @param ensureFileExists will warn if file does NOT exist (for input files)
* @param ensureFileNotExists will warn if file DOES exist (for output files)
* @return String
*/
protected static String getFilenameFromUser(String prompt, String defaultFilename, String expectedExtension,
boolean ensureFileExists, boolean ensureFileNotExists) {
boolean ensureFileExists, boolean ensureFileNotExists) {
boolean fileExistenceOK = false;
String selectedName = "";
do {
@@ -174,8 +185,8 @@ public class Toecount {
try {
selectedName = buffer.readLine();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Logger.getLogger(Toecount.class.getName()).log(Level.SEVERE, null, e);
}
if (selectedName.isEmpty()) {
@@ -191,8 +202,7 @@ public class Toecount {
try {
selectedAnswer = buffer.readLine();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
Logger.getLogger(Toecount.class.getName()).log(Level.SEVERE, null, e);
}
if (!selectedAnswer.equals("Y") && !selectedAnswer.equals("y")) {
System.err.println("Aborted by user");
@@ -234,6 +244,8 @@ public class Toecount {
// Option: Help
Option<Boolean> helpOption = parser.addBooleanOption('h', "help");
// Option: Action
Option<String> actionOption = parser.addStringOption('a', "action");
// Generic options available for multiple command
// --source: input file
@@ -264,12 +276,13 @@ public class Toecount {
// (--source: input PDF file)
// (--source-xml: input XML file)
// (--out: output PDF file)
// (--zugferd-version: ZUGFeRD version)
// (--zugferd-profile: ZUGFeRD profile)
// (--version: ZUGFeRD version)
// (--profile: ZUGFeRD profile)
Option<Boolean> combineOption = parser.addBooleanOption('c', "combine");
Option<String> sourceXmlOption = parser.addStringOption("source-xml");
Option<String> zugferdVersionOption = parser.addStringOption("zugferd-version");
Option<String> zugferdProfileOption = parser.addStringOption("zugferd-profile");
Option<String> formatOption = parser.addStringOption('f', "format");
Option<String> zugferdVersionOption = parser.addStringOption("version");
Option<String> zugferdProfileOption = parser.addStringOption("profile");
// Command: Show metrics in dir
// --directory
@@ -290,17 +303,19 @@ public class Toecount {
}
// Retrieve all options
String action = parser.getOptionValue(actionOption);
String directoryName = parser.getOptionValue(dirnameOption);
Boolean filesFromStdIn = parser.getOptionValue(filesFromStdInOption, Boolean.FALSE);
Boolean combineRequested = parser.getOptionValue(combineOption, Boolean.FALSE);
Boolean extractRequested = parser.getOptionValue(extractOption, Boolean.FALSE);
Boolean helpRequested = parser.getOptionValue(helpOption, Boolean.FALSE);
Boolean upgradeRequested = parser.getOptionValue(upgradeOption, Boolean.FALSE);
Boolean combineRequested = parser.getOptionValue(combineOption, Boolean.FALSE) || ((action!=null)&&(action.equals("combine")));
Boolean extractRequested = parser.getOptionValue(extractOption, Boolean.FALSE) || ((action!=null)&&(action.equals("extract")));
Boolean helpRequested = parser.getOptionValue(helpOption, Boolean.FALSE) || ((action!=null)&&(action.equals("help")));
Boolean upgradeRequested = parser.getOptionValue(upgradeOption, Boolean.FALSE) || ((action!=null)&&(action.equals("upgrade")));
Boolean ignoreFileExt = parser.getOptionValue(ignoreFileExtOption, Boolean.FALSE);
Boolean a3only = parser.getOptionValue(a3onlyOption, Boolean.FALSE);
Boolean a3only = parser.getOptionValue(a3onlyOption, Boolean.FALSE) || ((action!=null)&&(action.equals("a3")));
String sourceName = parser.getOptionValue(sourceOption);
String sourceXMLName = parser.getOptionValue(sourceXmlOption);
String outName = parser.getOptionValue(outOption);
String format = parser.getOptionValue(formatOption);
String zugferdVersion = parser.getOptionValue(zugferdVersionOption);
String zugferdProfile = parser.getOptionValue(zugferdProfileOption);
@@ -309,7 +324,7 @@ public class Toecount {
} else if (((directoryName != null) && (directoryName.length() > 0)) || filesFromStdIn.booleanValue()) {
performMetrics(directoryName, filesFromStdIn, ignoreFileExt);
} else if (combineRequested) {
performCombine(sourceName, sourceXMLName, outName, zugferdVersion, zugferdProfile);
performCombine(sourceName, sourceXMLName, outName, format, zugferdVersion, zugferdProfile);
} else if (extractRequested) {
performExtract(sourceName, outName);
} else if (a3only) {
@@ -322,7 +337,7 @@ public class Toecount {
System.exit(2);
}
} catch (Exception e) {
e.printStackTrace();
Logger.getLogger(Toecount.class.getName()).log(Level.SEVERE, null, e);
System.exit(-1);
}
@@ -338,7 +353,7 @@ public class Toecount {
System.out.println("ZUGFeRD 1.0 XML source set to " + xmlName);
}
if (outName == null) {
outName = getFilenameFromUser("ZUGFeRD 2.0 XML target", "factur-x.xml", "xml", false, true);
outName = getFilenameFromUser("ZUGFeRD 2.0 XML target", "zugferd-invoice.xml", "xml", false, true);
} else {
System.out.println("ZUGFeRD 1.0 XML source set to " + outName);
}
@@ -417,15 +432,15 @@ public class Toecount {
}
}
private static void performCombine(String pdfName, String xmlName, String outName, String zfVersion,
String zfProfile) throws Exception {
private static void performCombine(String pdfName, String xmlName, String outName, String format, String zfVersion,
String zfProfile) throws Exception {
/*
* ZUGFeRDExporter ze= new ZUGFeRDExporterFromA1Factory()
* .setProducer("toecount") .setCreator(System.getProperty("user.name"))
* .loadFromPDFA1("invoice.pdf");
*/
try {
int zfIntVersion = 1;
int zfIntVersion = ZUGFeRDExporter.DefaultZUGFeRDVersion;
ZUGFeRDConformanceLevel zfConformanceLevelProfile = ZUGFeRDConformanceLevel.EXTENDED;
if (pdfName == null) {
@@ -446,35 +461,42 @@ public class Toecount {
System.out.println("Ouput PDF set to " + outName);
}
if (zfVersion == null) {
if (format == null) {
try {
zfVersion = getStringFromUser("ZUGFeRD version (1 or 2)", "1", "1|2");
format = getStringFromUser("Format (fx=Factur-X, zf=ZUGFeRD,)", "zf", "fx|zf");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
Logger.getLogger(Toecount.class.getName()).log(Level.SEVERE, null, e);
}
} else {
System.out.println("ZUGFeRD version set to " + zfVersion);
System.out.println("Format set to " + format);
}
if (zfVersion == null) {
try {
zfVersion = getStringFromUser("Version (1 or 2)", "1", "1|2");
} catch (Exception e) {
Logger.getLogger(Toecount.class.getName()).log(Level.SEVERE, null, e);
}
} else {
System.out.println("Version set to " + zfVersion);
}
zfIntVersion = Integer.valueOf(zfVersion);
if (zfProfile == null) {
try {
if (zfIntVersion == 1) {
zfProfile = getStringFromUser("ZUGFeRD profile b)asic, c)omfort or e)xtended", "e",
"B|b|C|c|E|e");
if (format.equals("zf") && (zfIntVersion == 1)) {
zfProfile = getStringFromUser("Profile b)asic, c)omfort or e)xtended", "e", "B|b|C|c|E|e");
} else {
zfProfile = getStringFromUser(
"ZUGFeRD profile [M]INIMUM, BASIC [W]L, [B]ASIC,\n" + "[C]IUS, [E]N16931, E[X]TENDED",
"E", "M|m|W|w|B|b|C|c|E|e|X|x|");
"Profile [M]INIMUM, BASIC [W]L, [B]ASIC,\n" + "[C]IUS, [E]N16931, E[X]TENDED", "E",
"M|m|W|w|B|b|C|c|E|e|X|x|");
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
Logger.getLogger(Toecount.class.getName()).log(Level.SEVERE, null, e);
}
} else {
System.out.println("ZUGFeRD profile set to " + zfProfile);
System.out.println("Profile set to " + zfProfile);
}
zfProfile = zfProfile.toLowerCase();
@@ -483,7 +505,11 @@ public class Toecount {
ensureFileExists(xmlName);
ensureFileNotExists(outName);
if (zfIntVersion == 1) {
if ((format.equals("fx")) && (zfIntVersion > 1)) {
throw new Exception("Factur-X is only available in version 1 (roughly corresponding to ZF2)");
}
if ((format.equals("zf")) && (zfIntVersion == 1)) {
if (zfProfile.equals("b")) {
zfConformanceLevelProfile = ZUGFeRDConformanceLevel.BASIC;
} else if (zfProfile.equals("c")) {
@@ -493,7 +519,7 @@ public class Toecount {
} else {
throw new Exception(String.format("Unknown ZUGFeRD profile '%s'", zfProfile));
}
} else if (zfIntVersion == 2) {
} else if (((format.equals("zf")) && (zfIntVersion == 2)) || (format.equals("fx"))) {
if (zfProfile.equals("m")) {
zfConformanceLevelProfile = ZUGFeRDConformanceLevel.MINIMUM;
} else if (zfProfile.equals("w")) {
@@ -510,15 +536,18 @@ public class Toecount {
throw new Exception(String.format("Unknown ZUGFeRD profile '%s'", zfProfile));
}
} else {
throw new Exception(String.format("Unknown ZUGFeRD version '%i'", zfIntVersion));
throw new Exception(String.format("Unknown version '%i'", zfIntVersion));
}
// All params are good! continue...
ZUGFeRDExporter ze = new ZUGFeRDExporterFromA1Factory().setProducer("Toecount")
.setZUGFeRDVersion(zfIntVersion)
.setCreator(System.getProperty("user.name")).setZUGFeRDConformanceLevel(zfConformanceLevelProfile)
.load(pdfName);
ze.setZUGFeRDVersion(zfIntVersion);
if (format.equals("fx")) {
ze.setFacturX();
}
ze.setZUGFeRDXMLData(Files.readAllBytes(Paths.get(xmlName)));
@@ -527,9 +556,8 @@ public class Toecount {
System.out.println("Written to " + outName);
} catch (IOException e) {
e.printStackTrace();
// } catch (JAXBException e) {
// e.printStackTrace();
Logger.getLogger(Toecount.class.getName()).log(Level.SEVERE, null, e);
}
}

View File

@@ -63,7 +63,12 @@ Migrated by Mustangproject XSLT
<!-- xsl:template match="//*[local-name() = 'HeaderExchangedDocument']">
<xsl:copy> <xsl:apply-templates select="@*|node()" /> </xsl:copy> </xsl:template> -->
<!-- attribute rename -->
<!-- element remode -->
<xsl:template match="//*[local-name() = 'TestIndicator']">
<!-- Testindicator element has been removed -->
</xsl:template>
<!-- element rename -->
<xsl:template match="//*[local-name() = 'SpecifiedExchangedDocumentContext']">
<xsl:element name="rsm:ExchangedDocumentContext">
<xsl:apply-templates select="@*|node()" />

File diff suppressed because it is too large Load Diff