Reorganizing to a parent project, a light and a heavy (validating) library, a commandline application and the server
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
/** **********************************************************************
|
||||
*
|
||||
* 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 final class Version {
|
||||
public static final String VERSION = "${project.version}";
|
||||
}
|
||||
43
libraryBasic/src/main/java/org/mustangproject/XMLTools.java
Normal file
43
libraryBasic/src/main/java/org/mustangproject/XMLTools.java
Normal file
@@ -0,0 +1,43 @@
|
||||
package org.mustangproject;
|
||||
|
||||
public class XMLTools {
|
||||
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("�"); // Unicode replacement character
|
||||
} else {
|
||||
switch(c) {
|
||||
case '&': sb.append("&"); break;
|
||||
case '>': sb.append(">"); break;
|
||||
case '<': sb.append("<"); break;
|
||||
// Uncomment next two if encoding for an XML attribute
|
||||
// case '\'' sb.append("'"); break;
|
||||
// case '\"' sb.append("""); break;
|
||||
// Uncomment next three if you prefer, but not required
|
||||
// case '\n' sb.append(" "); break;
|
||||
// case '\r' sb.append(" "); break;
|
||||
// case '\t' sb.append("	"); 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("�"); // Unicode replacement character
|
||||
} else {
|
||||
sb.append("&#x");
|
||||
sb.append(Integer.toHexString(c));
|
||||
sb.append(';');
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/** **********************************************************************
|
||||
*
|
||||
* 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 class CustomXMLProvider implements IXMLProvider, IProfileProvider {
|
||||
|
||||
protected byte[] zugferdData;
|
||||
|
||||
@Override
|
||||
public byte[] getXML() {
|
||||
return zugferdData;
|
||||
}
|
||||
|
||||
public void setXML(byte[] newData) {
|
||||
String zf = new String(newData);
|
||||
if (!zf.contains("CrossIndustry")) {
|
||||
throw new RuntimeException("ZUGFeRD XML does not contain (<rsm:)CrossIndustry and can thus not be valid");
|
||||
}
|
||||
|
||||
zugferdData = newData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateXML(IZUGFeRDExportableTransaction trans) {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTest() {
|
||||
// TODO Auto-generated method stub
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProfile() {
|
||||
// TODO Auto-generated method stub
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProfile(ZUGFeRDConformanceLevel level) {
|
||||
// TODO Auto-generated method stub
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
/** **********************************************************************
|
||||
*
|
||||
* 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 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;
|
||||
|
||||
/**
|
||||
* 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 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;
|
||||
|
||||
/**
|
||||
* 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 pdfSource source to read a PDF/A1 compliant document from
|
||||
* @throws IOException if anything is wrong with inputstream
|
||||
* @return the generated ZUGFeRDExporter
|
||||
*/
|
||||
public ZUGFeRDExporter load(InputStream pdfSource) throws IOException;
|
||||
|
||||
public IExporterFactory setCreator(String creator);
|
||||
|
||||
public IExporterFactory setConformanceLevel(PDFAConformanceLevel newLevel);
|
||||
|
||||
public IExporterFactory setProducer(String producer);
|
||||
|
||||
public IExporterFactory setZUGFeRDVersion(int version);
|
||||
|
||||
public IExporterFactory ignorePDFAErrors();
|
||||
|
||||
public IExporterFactory setZUGFeRDConformanceLevel(ZUGFeRDConformanceLevel zugferdConformanceLevel);
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/** **********************************************************************
|
||||
*
|
||||
* 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 IXMLProvider {
|
||||
|
||||
public byte[] getXML();
|
||||
|
||||
public void setTest();
|
||||
|
||||
public void generateXML(IZUGFeRDExportableTransaction trans);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright 2015 AlexanderSchmidt.
|
||||
*
|
||||
* 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 org.mustangproject.ZUGFeRD.model.TaxCategoryCodeTypeConstants;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* @author AlexanderSchmidt
|
||||
*/
|
||||
public interface IZUGFeRDAllowanceCharge {
|
||||
|
||||
BigDecimal getTotalAmount();
|
||||
|
||||
String getReason();
|
||||
|
||||
BigDecimal getTaxPercent();
|
||||
|
||||
default String getCategoryCode() {
|
||||
return TaxCategoryCodeTypeConstants.STANDARDRATE;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package org.mustangproject.ZUGFeRD;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
public interface IZUGFeRDDate {
|
||||
|
||||
Date getDate();
|
||||
|
||||
default ZUGFeRDDateFormat getFormat() {
|
||||
return ZUGFeRDDateFormat.DATE;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,136 @@
|
||||
/** **********************************************************************
|
||||
*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Mustangproject's ZUGFeRD implementation neccessary interface for ZUGFeRD exporter Licensed under the APLv2
|
||||
*
|
||||
* @author jstaerk
|
||||
* @version 1.2.0
|
||||
* dated 2014-05-10
|
||||
*/
|
||||
|
||||
|
||||
public interface IZUGFeRDExportableContact {
|
||||
|
||||
/**
|
||||
* customer identification assigned by the seller
|
||||
*
|
||||
* @return customer identification
|
||||
*/
|
||||
default String getID() {
|
||||
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
|
||||
*
|
||||
* @return First and last name of the recipient
|
||||
*/
|
||||
default String getName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
default String getPhone() {
|
||||
return null;
|
||||
}
|
||||
|
||||
default String getEMail() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Postal code of the recipient
|
||||
*
|
||||
* @return Postal code of the recipient
|
||||
*/
|
||||
default String getZIP() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* VAT ID (Umsatzsteueridentifikationsnummer) of the contact
|
||||
*
|
||||
* @return VAT ID (Umsatzsteueridentifikationsnummer) of the contact
|
||||
*/
|
||||
default String getVATID() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* two-letter country code of the contact
|
||||
*
|
||||
* @return two-letter iso country code of the contact
|
||||
*/
|
||||
default String getCountry() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the city of the contact
|
||||
*
|
||||
* @return Returns the city of the recipient
|
||||
*/
|
||||
default String getLocation() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the street address (street+number) of the contact
|
||||
*
|
||||
* @return street address (street+number) of the contact
|
||||
*/
|
||||
default String getStreet() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns additional address information which is display in xml tag "LineTwo"
|
||||
*
|
||||
* @return additional address information
|
||||
*/
|
||||
default String getAdditionalAddress() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/** **********************************************************************
|
||||
*
|
||||
* 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;
|
||||
/**
|
||||
* Mustangproject's ZUGFeRD implementation
|
||||
* Neccessary interface for ZUGFeRD exporter
|
||||
* Licensed under the APLv2
|
||||
* @date 2014-05-10
|
||||
* @version 1.2.0
|
||||
* @author jstaerk
|
||||
* */
|
||||
|
||||
import org.mustangproject.ZUGFeRD.model.TaxCategoryCodeTypeConstants;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
public interface IZUGFeRDExportableItem {
|
||||
|
||||
IZUGFeRDExportableProduct getProduct();
|
||||
|
||||
IZUGFeRDAllowanceCharge[] getItemAllowances();
|
||||
|
||||
IZUGFeRDAllowanceCharge[] getItemCharges();
|
||||
|
||||
|
||||
/**
|
||||
* The price of one item excl. taxes
|
||||
*
|
||||
* @return The price of one item excl. taxes
|
||||
*/
|
||||
BigDecimal getPrice();
|
||||
|
||||
/**
|
||||
* how many
|
||||
*
|
||||
* @return the quantity of the item
|
||||
*/
|
||||
BigDecimal getQuantity();
|
||||
|
||||
default String getCategoryCode() {
|
||||
return TaxCategoryCodeTypeConstants.STANDARDRATE;
|
||||
}
|
||||
|
||||
default String getAdditionalReferencedDocumentID() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/** **********************************************************************
|
||||
*
|
||||
* 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 java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* Mustangproject's ZUGFeRD implementation
|
||||
* Necessary interface for ZUGFeRD exporter
|
||||
* Licensed under the APLv2
|
||||
*
|
||||
* @author jstaerk
|
||||
* @version 1.2.0
|
||||
* dated 2014-05-10
|
||||
*/
|
||||
|
||||
public interface IZUGFeRDExportableProduct {
|
||||
|
||||
/**
|
||||
* Unit code of the product
|
||||
* Most common ones are
|
||||
* C62 one (piece)
|
||||
* DAY day
|
||||
* HAR hectare
|
||||
* HUR hour
|
||||
* KGM kilogram
|
||||
* KTM kilometre
|
||||
* KWH kilowatt hour
|
||||
* LS lump sum
|
||||
* LTR litre
|
||||
* MIN minute
|
||||
* MMK square millimetre
|
||||
* MMT millimetre
|
||||
* MTK square metre
|
||||
* MTQ cubic metre
|
||||
* MTR metre
|
||||
* NAR number of articles
|
||||
* NPR number of pairs
|
||||
* P1 percent
|
||||
* SET set
|
||||
* TNE tonne (metric ton)
|
||||
* WEE week
|
||||
*
|
||||
* @return a UN/ECE rec 20 unit code see https://www.unece.org/fileadmin/DAM/cefact/recommendations/rec20/rec20_rev3_Annex2e.pdf
|
||||
*/
|
||||
String getUnit();
|
||||
|
||||
/**
|
||||
* Short name of the product
|
||||
*
|
||||
* @return Short name of the product
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* long description of the product
|
||||
*
|
||||
* @return long description of the product
|
||||
*/
|
||||
String getDescription();
|
||||
|
||||
/**
|
||||
* VAT percent of the product (e.g. 19, or 5.1 if you like)
|
||||
*
|
||||
* @return VAT percent of the product
|
||||
*/
|
||||
BigDecimal getVATPercent();
|
||||
|
||||
default boolean isIntraCommunitySupply() {
|
||||
return false;
|
||||
}
|
||||
|
||||
default String getTaxCategoryCode() {
|
||||
if (isIntraCommunitySupply()) {
|
||||
return "K";
|
||||
} else {
|
||||
return "S";
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,384 @@
|
||||
/** **********************************************************************
|
||||
*
|
||||
* 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;
|
||||
/**
|
||||
* Mustangproject's ZUGFeRD implementation
|
||||
* Neccessary interface for ZUGFeRD exporter
|
||||
* Licensed under the APLv2
|
||||
* @date 2014-05-10 to 2014-06-25
|
||||
* @version 1.2.0
|
||||
* @author jstaerk
|
||||
* */
|
||||
|
||||
|
||||
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";
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @return Code of Document
|
||||
*/
|
||||
default String getDocumentCode() {
|
||||
return DocumentCodeTypeConstants.INVOICE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Number, typically invoice number of the invoice
|
||||
*
|
||||
* @return invoice number
|
||||
*/
|
||||
default String getNumber() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* the date when the invoice was created
|
||||
*
|
||||
* @return when the invoice was created
|
||||
*/
|
||||
default Date getIssueDate() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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>
|
||||
* 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
|
||||
*/
|
||||
default String getOwnOrganisationFullPlaintextInfo() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* when the invoice is to be paid
|
||||
*
|
||||
* @return when the invoice is to be paid
|
||||
*/
|
||||
default Date getDueDate() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* who processed the order
|
||||
*
|
||||
* @return the contact person at the supplier side
|
||||
*/
|
||||
default IZUGFeRDExportableContact getOwnContact() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
IZUGFeRDAllowanceCharge[] getZFAllowances();
|
||||
|
||||
|
||||
IZUGFeRDAllowanceCharge[] getZFCharges();
|
||||
|
||||
|
||||
IZUGFeRDAllowanceCharge[] getZFLogisticsServiceCharges();
|
||||
|
||||
|
||||
IZUGFeRDExportableItem[] getZFItems();
|
||||
|
||||
|
||||
/**
|
||||
* the recipient
|
||||
*
|
||||
* @return the recipient of the invoice
|
||||
*/
|
||||
IZUGFeRDExportableContact getRecipient();
|
||||
|
||||
|
||||
/**
|
||||
* the creditors payment informations
|
||||
* @deprecated use getTradeSettlement
|
||||
* @return an array of IZUGFeRDTradeSettlementPayment
|
||||
*/
|
||||
@Deprecated
|
||||
default IZUGFeRDTradeSettlementPayment[] getTradeSettlementPayment() {
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* the payment information for any payment means
|
||||
*
|
||||
* @return an array of IZUGFeRDTradeSettlement
|
||||
*/
|
||||
default IZUGFeRDTradeSettlement[] getTradeSettlement() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Tax ID (not VAT ID) of the sender
|
||||
*
|
||||
* @return Tax ID (not VAT ID) of the sender
|
||||
*/
|
||||
default String getOwnTaxID() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* VAT ID (Umsatzsteueridentifikationsnummer) of the sender
|
||||
*
|
||||
* @return VAT ID (Umsatzsteueridentifikationsnummer) of the sender
|
||||
*/
|
||||
default String getOwnVATID() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* supplier identification assigned by the costumer
|
||||
*
|
||||
* @return the sender's identification
|
||||
*/
|
||||
default String getOwnForeignOrganisationID() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* own name
|
||||
*
|
||||
* @return the sender's organisation name
|
||||
*/
|
||||
default String getOwnOrganisationName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* own street address
|
||||
*
|
||||
* @return sender street address
|
||||
*/
|
||||
default String getOwnStreet() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* own street postal code
|
||||
*
|
||||
* @return sender postal code
|
||||
*/
|
||||
default String getOwnZIP() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* own city
|
||||
*
|
||||
* @return the invoice sender's city
|
||||
*/
|
||||
default String getOwnLocation() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* own two digit country code
|
||||
*
|
||||
* @return the invoice senders two character country iso code
|
||||
*/
|
||||
default String getOwnCountry() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* get delivery date
|
||||
*
|
||||
* @return the day the goods have been delivered
|
||||
*/
|
||||
Date getDeliveryDate();
|
||||
|
||||
/**
|
||||
* get delivery date in more specific form. If this and getDeliveryDate() are
|
||||
* specified, this value will be taken
|
||||
*
|
||||
* @return instance holding date and format
|
||||
*/
|
||||
default IZUGFeRDDate getZFDeliveryDate() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* get main invoice currency used on the invoice
|
||||
*
|
||||
* @return three character currency of this invoice
|
||||
*/
|
||||
default String getCurrency() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* get payment term descriptional text e.g. Bis zum 22.10.2015 ohne Abzug
|
||||
*
|
||||
* @return get payment terms
|
||||
*/
|
||||
default String getPaymentTermDescription() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* get payment terms. if set, getPaymentTermDescription() and getDueDate() are
|
||||
* ignored
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
default IZUGFeRDPaymentTerms getPaymentTerms() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* get reference document number typically used for Invoice Corrections Will be added as IncludedNote in comfort profile
|
||||
*
|
||||
* @return the ID of the document this document refers to
|
||||
*/
|
||||
default String getReferenceNumber() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* consignee identification (identification of the organisation the goods are shipped to [assigned by the costumer])
|
||||
*
|
||||
* @return the sender's identification
|
||||
*/
|
||||
default String getShipToOrganisationID() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* consignee name (name of the organisation the goods are shipped to)
|
||||
*
|
||||
* @return the consignee's organisation name
|
||||
*/
|
||||
default String getShipToOrganisationName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* consignee street address (street of the organisation the goods are shipped to)
|
||||
*
|
||||
* @return consignee street address
|
||||
*/
|
||||
default String getShipToStreet() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* consignee street postal code (postal code of the organisation the goods are shipped to)
|
||||
*
|
||||
* @return consignee postal code
|
||||
*/
|
||||
default String getShipToZIP() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* consignee city (city of the organisation the goods are shipped to)
|
||||
*
|
||||
* @return the consignee's city
|
||||
*/
|
||||
default String getShipToLocation() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* consignee two digit country code (country code of the organisation the goods are shipped to)
|
||||
*
|
||||
* @return the consignee's two character country iso code
|
||||
*/
|
||||
default String getShipToCountry() {
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
* delivery address, i.e. ram:ShipToTradeParty (only supported for zf2)
|
||||
* @return
|
||||
*/
|
||||
|
||||
default IZUGFeRDExportableContact getDeliveryAddress() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package org.mustangproject.ZUGFeRD;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
public interface IZUGFeRDPaymentDiscountTerms {
|
||||
|
||||
BigDecimal getCalculationPercentage();
|
||||
|
||||
IZUGFeRDDate getBaseDate();
|
||||
|
||||
int getBasePeriodMeasure();
|
||||
|
||||
String getBasePeriodUnitCode();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package org.mustangproject.ZUGFeRD;
|
||||
|
||||
public interface IZUGFeRDPaymentTerms {
|
||||
|
||||
String getDescription();
|
||||
|
||||
IZUGFeRDDate getDueDate();
|
||||
|
||||
IZUGFeRDPaymentDiscountTerms getDiscountTerms();
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/** **********************************************************************
|
||||
*
|
||||
* 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 IZUGFeRDTradeSettlement {
|
||||
|
||||
/***
|
||||
*
|
||||
* @return zf2 xml for applicableHeaderTradeSettlement
|
||||
*/
|
||||
String getSettlementXML();
|
||||
|
||||
|
||||
/***
|
||||
*
|
||||
* @return zf2 xml for applicableHeaderTradePayment
|
||||
*/
|
||||
default String getPaymentXML() {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/** **********************************************************************
|
||||
*
|
||||
* 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;
|
||||
|
||||
import org.mustangproject.XMLTools;
|
||||
|
||||
public interface IZUGFeRDTradeSettlementDebit extends IZUGFeRDTradeSettlement {
|
||||
|
||||
|
||||
|
||||
default String getSettlementXML() {
|
||||
|
||||
|
||||
|
||||
String xml = " <ram:SpecifiedTradeSettlementPaymentMeans>\n" //$NON-NLS-1$
|
||||
+ " <ram:TypeCode>59</ram:TypeCode>\n" //$NON-NLS-1$
|
||||
+ " <ram:PayerPartyDebtorFinancialAccount>\n" //$NON-NLS-1$
|
||||
+ " <ram:IBANID>"+XMLTools.encodeXML(getIBAN())+"</ram:IBANID>\n" //$NON-NLS-1$
|
||||
+ " </ram:PayerPartyDebtorFinancialAccount>\n"; //$NON-NLS-1$
|
||||
|
||||
xml = xml + " </ram:SpecifiedTradeSettlementPaymentMeans>\n"; //$NON-NLS-1$
|
||||
return xml;
|
||||
}
|
||||
|
||||
default String getPaymentXML() {
|
||||
return "<ram:DirectDebitMandateID>"+XMLTools.encodeXML(getMandate())+"</ram:DirectDebitMandateID>";
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
* @return IBAN of the debtor (optional)
|
||||
*/
|
||||
String getIBAN();
|
||||
|
||||
|
||||
/***
|
||||
* @return sepa direct debit mandate reference
|
||||
*/
|
||||
String getMandate();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
/** **********************************************************************
|
||||
*
|
||||
* 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;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
|
||||
import org.mustangproject.XMLTools;
|
||||
|
||||
public interface IZUGFeRDTradeSettlementPayment extends IZUGFeRDTradeSettlement {
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
default String getSettlementXML() {
|
||||
String 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>" + XMLTools.encodeXML(getOwnIBAN()) + "</ram:IBANID>\n"; //$NON-NLS-1$ //$NON-NLS-2$
|
||||
if (getOwnKto()!=null) {
|
||||
xml+= " <ram:ProprietaryID>" + XMLTools.encodeXML(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>" + XMLTools.encodeXML(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$
|
||||
return xml;
|
||||
}
|
||||
|
||||
|
||||
/* I'd love to implement getPaymentXML() and put <ram:DueDateDateTime> there because this is where it belongs
|
||||
* unfortunately, the due date is part of the transaction which is not accessible here :-(
|
||||
*/
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/** **********************************************************************
|
||||
*
|
||||
* 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 enum PDFAConformanceLevel {
|
||||
ACCESSIBLE("A"), BASIC("B"), UNICODE("U");
|
||||
|
||||
private final String letter;
|
||||
|
||||
PDFAConformanceLevel(String letter) {
|
||||
this.letter = letter;
|
||||
}
|
||||
|
||||
public String getLetter() {
|
||||
return letter;
|
||||
}
|
||||
|
||||
public static PDFAConformanceLevel findByLetter(String letter) {
|
||||
for (PDFAConformanceLevel candidate : values()) {
|
||||
if (candidate.letter.equals(letter)) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException("PDF conformance level <" + letter + "> is unknown.");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
/** **********************************************************************
|
||||
*
|
||||
* 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 java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* Mustangproject's ZUGFeRD implementation
|
||||
* ZUGFeRD exporter helper class
|
||||
* Licensed under the APLv2
|
||||
*
|
||||
* @author jstaerk
|
||||
* @version 1.2.0
|
||||
* dated 2015-10-29
|
||||
*/
|
||||
public class VATAmount {
|
||||
|
||||
public VATAmount(BigDecimal basis, BigDecimal calculated, String categoryCode) {
|
||||
super();
|
||||
this.basis = basis;
|
||||
this.calculated = calculated;
|
||||
this.categoryCode = categoryCode;
|
||||
}
|
||||
|
||||
BigDecimal basis, calculated;
|
||||
|
||||
String categoryCode;
|
||||
|
||||
public BigDecimal getBasis() {
|
||||
return basis;
|
||||
}
|
||||
|
||||
public void setBasis(BigDecimal basis) {
|
||||
this.basis = basis;
|
||||
}
|
||||
|
||||
public BigDecimal getCalculated() {
|
||||
return calculated;
|
||||
}
|
||||
|
||||
public void setCalculated(BigDecimal calculated) {
|
||||
this.calculated = calculated;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @deprecated Use {@link #getCategoryCode() instead}
|
||||
* @return String with category code
|
||||
*/
|
||||
@Deprecated
|
||||
public String getDocumentCode() {
|
||||
return categoryCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param documentCode as String
|
||||
* @deprecated Use {@link #setCategoryCode(String)} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void setDocumentCode(String 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.categoryCode);
|
||||
}
|
||||
|
||||
public VATAmount subtract(VATAmount v) {
|
||||
return new VATAmount(basis.subtract(v.getBasis()), calculated.subtract(v.getCalculated()), this.categoryCode);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,140 @@
|
||||
/** **********************************************************************
|
||||
*
|
||||
* 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;
|
||||
|
||||
/**
|
||||
* Mustangproject's ZUGFeRD implementation
|
||||
* ZUGFeRD exporter helper class
|
||||
* Licensed under the APLv2
|
||||
* @date 2014-05-10
|
||||
* @version 1.2.0
|
||||
* @author jstaerk
|
||||
* */
|
||||
|
||||
import org.apache.xmpbox.XMPMetadata;
|
||||
import org.apache.xmpbox.XmpConstants;
|
||||
import org.apache.xmpbox.schema.PDFAExtensionSchema;
|
||||
import org.apache.xmpbox.type.*;
|
||||
|
||||
/**
|
||||
* Additionally to adding a RDF namespace with a indication which file
|
||||
* attachment if Zugferd, this namespace has to be described in a PDFA Extension
|
||||
* Schema. I know there is a PDFAExtensionSchema in the context of PDFBox'
|
||||
* XMPBOX but I have been using PDFBox' JempBOX so far because I could not find
|
||||
* out how to write XMPBOX XMPMetadata to a PDF file. So this is my version of
|
||||
* PDFAExtensionSchema for PDFBox' jempbox XMPMetadata
|
||||
*
|
||||
* @author jstaerk
|
||||
*/
|
||||
|
||||
@StructuredType(preferedPrefix = "pdfaExtension", namespace = "http://www.aiim.org/pdfa/ns/extension/")
|
||||
public class XMPSchemaPDFAExtensions extends PDFAExtensionSchema {
|
||||
|
||||
public final String xmlns_pdfaSchema = "http://www.aiim.org/pdfa/ns/schema#";
|
||||
public final String prefix_pdfaSchema = "pdfaSchema";
|
||||
public final String xmlns_pdfaProperty = "http://www.aiim.org/pdfa/ns/property#";
|
||||
public final String prefix_pdfaProperty = "pdfaProperty";
|
||||
public String namespace = null;
|
||||
public String prefix = null;
|
||||
|
||||
protected ZUGFeRDExporter exporter;
|
||||
|
||||
|
||||
protected void setZUGFeRDVersion(int ver) {
|
||||
namespace = exporter.getNamespaceForVersion(ver);
|
||||
prefix = exporter.getPrefixForVersion(ver);
|
||||
}
|
||||
|
||||
|
||||
private DefinedStructuredType addProperty(ArrayProperty parent, String name, String type, String category,
|
||||
String description) {
|
||||
XMPMetadata metadata = getMetadata();
|
||||
|
||||
DefinedStructuredType li = new DefinedStructuredType(metadata, getNamespace(), getPrefix(),
|
||||
XmpConstants.LIST_NAME);
|
||||
li.setAttribute(new Attribute(getNamespace(), XmpConstants.PARSE_TYPE, XmpConstants.RESOURCE_NAME));
|
||||
|
||||
ChoiceType pdfa2 = new ChoiceType(metadata, xmlns_pdfaProperty, prefix_pdfaProperty, PDFAPropertyType.NAME,
|
||||
name);
|
||||
li.addProperty(pdfa2);
|
||||
|
||||
pdfa2 = new ChoiceType(metadata, xmlns_pdfaProperty, prefix_pdfaProperty, PDFAPropertyType.VALUETYPE, type);
|
||||
li.addProperty(pdfa2);
|
||||
|
||||
pdfa2 = new ChoiceType(metadata, xmlns_pdfaProperty, prefix_pdfaProperty, PDFAPropertyType.CATEGORY, category);
|
||||
li.addProperty(pdfa2);
|
||||
|
||||
pdfa2 = new ChoiceType(metadata, xmlns_pdfaProperty, prefix_pdfaProperty, PDFAPropertyType.DESCRIPTION,
|
||||
description);
|
||||
li.addProperty(pdfa2);
|
||||
|
||||
parent.addProperty(li);
|
||||
|
||||
return li;
|
||||
}
|
||||
|
||||
public XMPSchemaPDFAExtensions(ZUGFeRDExporter ze, XMPMetadata metadata, int ZFVersion) {
|
||||
super(metadata);
|
||||
exporter=ze;
|
||||
setZUGFeRDVersion(ZFVersion);
|
||||
attachExtensions(metadata, true);
|
||||
}
|
||||
|
||||
public XMPSchemaPDFAExtensions(ZUGFeRDExporter ze, XMPMetadata metadata, int ZFVersion, boolean withZF) {
|
||||
super(metadata);
|
||||
exporter=ze;
|
||||
setZUGFeRDVersion(ZFVersion);
|
||||
attachExtensions(metadata, withZF);
|
||||
}
|
||||
|
||||
public void attachExtensions(XMPMetadata metadata, boolean withZF) {
|
||||
|
||||
addNamespace(xmlns_pdfaSchema, prefix_pdfaSchema);
|
||||
addNamespace(xmlns_pdfaProperty, prefix_pdfaProperty);
|
||||
|
||||
ArrayProperty newBag = createArrayProperty(SCHEMAS, Cardinality.Bag);
|
||||
DefinedStructuredType li = new DefinedStructuredType(metadata, getNamespace(), getPrefix(),
|
||||
XmpConstants.LIST_NAME);
|
||||
li.setAttribute(new Attribute(getNamespace(), XmpConstants.PARSE_TYPE, XmpConstants.RESOURCE_NAME));
|
||||
newBag.addProperty(li);
|
||||
addProperty(newBag);
|
||||
if (withZF) {
|
||||
TextType pdfa1 = new TextType(metadata, xmlns_pdfaSchema, prefix_pdfaSchema, PDFASchemaType.SCHEMA,
|
||||
"ZUGFeRD PDFA Extension Schema");
|
||||
li.addProperty(pdfa1);
|
||||
|
||||
pdfa1 = new TextType(metadata, xmlns_pdfaSchema, prefix_pdfaSchema, PDFASchemaType.NAMESPACE_URI,
|
||||
namespace);
|
||||
li.addProperty(pdfa1);
|
||||
|
||||
pdfa1 = new TextType(metadata, xmlns_pdfaSchema, prefix_pdfaSchema, PDFASchemaType.PREFIX, prefix);
|
||||
li.addProperty(pdfa1);
|
||||
|
||||
ArrayProperty newSeq = new ArrayProperty(metadata, xmlns_pdfaSchema, prefix_pdfaSchema,
|
||||
PDFASchemaType.PROPERTY, Cardinality.Seq);
|
||||
li.addProperty(newSeq);
|
||||
|
||||
addProperty(newSeq, "DocumentFileName", "Text", "external", "name of the embedded XML invoice file");
|
||||
addProperty(newSeq, "DocumentType", "Text", "external", "INVOICE");
|
||||
addProperty(newSeq, "Version", "Text", "external", "The actual version of the ZUGFeRD XML schema");
|
||||
addProperty(newSeq, "ConformanceLevel", "Text", "external",
|
||||
"The selected ZUGFeRD profile completeness");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
/** **********************************************************************
|
||||
*
|
||||
* 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;
|
||||
/**
|
||||
* Mustangproject's ZUGFeRD implementation
|
||||
* ZUGFeRD exporter helper class
|
||||
* Licensed under the APLv2
|
||||
* @date 2014-05-10
|
||||
* @version 1.2.0s
|
||||
* @author jstaerk
|
||||
* */
|
||||
|
||||
import org.apache.xmpbox.XMPMetadata;
|
||||
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 zfVersion which ZF version to use (2 for FX)
|
||||
* @param isFacturX whether to export as Factur-X
|
||||
* @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, int zfVersion, boolean isFacturX, ZUGFeRDConformanceLevel conformanceLevel, String URN, String prefix, String filename) {
|
||||
super(metadata, URN, prefix, "ZUGFeRD Schema");
|
||||
|
||||
setAboutAsSimple("");
|
||||
|
||||
String conformanceLevelValue = conformanceLevel.name();
|
||||
if (conformanceLevelValue.equals("BASICWL")) {
|
||||
conformanceLevelValue = "BASIC WL";
|
||||
} else if (conformanceLevelValue.equals("EN16931")) {
|
||||
conformanceLevelValue = "EN 16931";
|
||||
}
|
||||
setTextPropertyValue("ConformanceLevel", conformanceLevelValue);
|
||||
setTextPropertyValue("DocumentType", "INVOICE");
|
||||
setTextPropertyValue("DocumentFileName", filename);
|
||||
String version="1.0";
|
||||
if ((zfVersion==2)&&(!isFacturX)) {
|
||||
version="2p0";
|
||||
}
|
||||
setTextPropertyValue("Version", version);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
/** **********************************************************************
|
||||
*
|
||||
* 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 org.mustangproject.ZUGFeRD.model.CrossIndustryDocumentType;
|
||||
import org.mustangproject.ZUGFeRD.model.DocumentContextParameterTypeConstants;
|
||||
import org.mustangproject.ZUGFeRD.model.ZFNamespacePrefixMapper;
|
||||
|
||||
import javax.xml.bind.JAXBContext;
|
||||
import javax.xml.bind.JAXBElement;
|
||||
import javax.xml.bind.JAXBException;
|
||||
import javax.xml.bind.Marshaller;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* enables the flag to indicate a test invoice in the XML structure
|
||||
*/
|
||||
public void setTest() {
|
||||
isTest = true;
|
||||
}
|
||||
|
||||
public ZUGFeRD1PullProvider() {
|
||||
// TODO Auto-generated constructor stub
|
||||
try {
|
||||
marshaller = JAXBContext.newInstance("org.mustangproject.ZUGFeRD.model").createMarshaller();
|
||||
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
|
||||
marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
|
||||
marshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper", new ZFNamespacePrefixMapper());
|
||||
} catch (JAXBException e) {
|
||||
throw new ZUGFeRDExportException("Could not initialize JAXB", e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private String createZugferdXMLForTransaction(IZUGFeRDExportableTransaction trans) {
|
||||
|
||||
JAXBElement<CrossIndustryDocumentType> jaxElement =
|
||||
new ZUGFeRDTransactionModelConverter(trans).withTest(isTest).withProfile(getProfile()).convertToModel();
|
||||
|
||||
try {
|
||||
return marshalJaxToXMLString(jaxElement);
|
||||
} catch (JAXBException e) {
|
||||
throw new ZUGFeRDExportException("Could not marshal ZUGFeRD transaction to XML", e);
|
||||
}
|
||||
}
|
||||
|
||||
private String marshalJaxToXMLString(Object jaxElement) throws JAXBException {
|
||||
ByteArrayOutputStream outputXml = new ByteArrayOutputStream();
|
||||
marshaller.marshal(jaxElement, outputXml);
|
||||
return outputXml.toString();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public byte[] getXML() {
|
||||
return zugferdData;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void generateXML(IZUGFeRDExportableTransaction trans) {
|
||||
// create a dummy file stream, this would probably normally be a
|
||||
// FileInputStream
|
||||
|
||||
byte[] zugferdRaw = createZugferdXMLForTransaction(trans).getBytes(); //$NON-NLS-1$
|
||||
|
||||
if ((zugferdRaw[0] == (byte) 0xEF)
|
||||
&& (zugferdRaw[1] == (byte) 0xBB)
|
||||
&& (zugferdRaw[2] == (byte) 0xBF)) {
|
||||
// I don't like BOMs, lets remove it
|
||||
zugferdData = new byte[zugferdRaw.length - 3];
|
||||
System.arraycopy(zugferdRaw, 3, zugferdData, 0,
|
||||
zugferdRaw.length - 3);
|
||||
} else {
|
||||
zugferdData = zugferdRaw;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,624 @@
|
||||
/** **********************************************************************
|
||||
*
|
||||
* 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 java.io.IOException;
|
||||
import java.io.StringWriter;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
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.XMLTools;
|
||||
import org.mustangproject.toecount.Toecount;
|
||||
|
||||
public class ZUGFeRD2PullProvider implements IXMLProvider, IProfileProvider {
|
||||
|
||||
private class LineCalc {
|
||||
private BigDecimal totalGross;
|
||||
private BigDecimal priceGross;
|
||||
private BigDecimal itemTotalNetAmount;
|
||||
private BigDecimal itemTotalVATAmount;
|
||||
|
||||
public LineCalc(IZUGFeRDExportableItem currentItem) {
|
||||
BigDecimal multiplicator = currentItem.getProduct().getVATPercent().divide(new BigDecimal(100))
|
||||
.add(new BigDecimal(1));
|
||||
priceGross = currentItem.getPrice().multiply(multiplicator);
|
||||
totalGross = currentItem.getPrice().multiply(multiplicator).multiply(currentItem.getQuantity());
|
||||
itemTotalNetAmount = currentItem.getQuantity().multiply(currentItem.getPrice()).setScale(2,
|
||||
BigDecimal.ROUND_HALF_UP);
|
||||
itemTotalVATAmount = totalGross.subtract(itemTotalNetAmount);
|
||||
}
|
||||
|
||||
public BigDecimal getItemTotalNetAmount() {
|
||||
return itemTotalNetAmount;
|
||||
}
|
||||
|
||||
public BigDecimal getItemTotalVATAmount() {
|
||||
return itemTotalVATAmount;
|
||||
}
|
||||
|
||||
public BigDecimal getItemTotalGrossAmount() {
|
||||
return itemTotalVATAmount;
|
||||
}
|
||||
|
||||
public BigDecimal getPriceGross() {
|
||||
return priceGross;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//// MAIN CLASS
|
||||
|
||||
protected byte[] zugferdData;
|
||||
private IZUGFeRDExportableTransaction trans;
|
||||
private ZUGFeRDConformanceLevel level;
|
||||
private String paymentTermsDescription;
|
||||
|
||||
@Override
|
||||
public void setProfile(ZUGFeRDConformanceLevel level) {
|
||||
this.level = level;
|
||||
}
|
||||
|
||||
/**
|
||||
* enables the flag to indicate a test invoice in the XML structure
|
||||
*/
|
||||
@Override
|
||||
public void setTest() {
|
||||
}
|
||||
|
||||
public static String nDigitFormat(BigDecimal value, int scale) {
|
||||
/*
|
||||
* I needed 123,45, locale independent.I tried
|
||||
* NumberFormat.getCurrencyInstance().format( 12345.6789 ); but that is locale
|
||||
* specific.I also tried DecimalFormat df = new DecimalFormat( "0,00" );
|
||||
* df.setDecimalSeparatorAlwaysShown(true); df.setGroupingUsed(false);
|
||||
* DecimalFormatSymbols symbols = new DecimalFormatSymbols();
|
||||
* symbols.setDecimalSeparator(','); symbols.setGroupingSeparator(' ');
|
||||
* df.setDecimalFormatSymbols(symbols);
|
||||
*
|
||||
* but that would not switch off grouping. Although I liked very much the
|
||||
* (incomplete) "BNF diagram" in
|
||||
* http://docs.oracle.com/javase/tutorial/i18n/format/decimalFormat.html in the
|
||||
* end I decided to calculate myself and take eur+sparator+cents
|
||||
*
|
||||
*/
|
||||
return value.setScale(scale, RoundingMode.HALF_UP).toPlainString();
|
||||
|
||||
}
|
||||
|
||||
private String vatFormat(BigDecimal value) {
|
||||
return ZUGFeRD2PullProvider.nDigitFormat(value, 2);
|
||||
}
|
||||
|
||||
private String currencyFormat(BigDecimal value) {
|
||||
return ZUGFeRD2PullProvider.nDigitFormat(value, 2);
|
||||
}
|
||||
|
||||
private String priceFormat(BigDecimal value) {
|
||||
return ZUGFeRD2PullProvider.nDigitFormat(value, 4);
|
||||
}
|
||||
|
||||
private String quantityFormat(BigDecimal value) {
|
||||
return ZUGFeRD2PullProvider.nDigitFormat(value, 4);
|
||||
}
|
||||
|
||||
@Override
|
||||
public byte[] getXML() {
|
||||
|
||||
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() {
|
||||
|
||||
BigDecimal res = getTotal();
|
||||
HashMap<BigDecimal, VATAmount> VATPercentAmountMap = getVATPercentAmountMap();
|
||||
for (BigDecimal currentTaxPercent : VATPercentAmountMap.keySet()) {
|
||||
VATAmount amount = VATPercentAmountMap.get(currentTaxPercent);
|
||||
res = res.add(amount.getCalculated());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
private BigDecimal getTotal() {
|
||||
BigDecimal res = new BigDecimal(0);
|
||||
for (IZUGFeRDExportableItem currentItem : trans.getZFItems()) {
|
||||
LineCalc lc = new LineCalc(currentItem);
|
||||
res = res.add(lc.getItemTotalNetAmount());
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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<>();
|
||||
|
||||
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 current = hm.get(percent);
|
||||
if (current == null) {
|
||||
hm.put(percent, itemVATAmount);
|
||||
} else {
|
||||
hm.put(percent, current.add(itemVATAmount));
|
||||
}
|
||||
}
|
||||
return hm;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getProfile() {
|
||||
// return "urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_1.2";
|
||||
return "urn:cen.eu:en16931:2017";
|
||||
}
|
||||
|
||||
protected String getContactAsXML(IZUGFeRDExportableContact contact) {
|
||||
String xml = " <ram:Name>" + XMLTools.encodeXML(contact.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>" + XMLTools.encodeXML(contact.getZIP()) //$NON-NLS-1$
|
||||
+ "</ram:PostcodeCode>\n" //$NON-NLS-1$
|
||||
+ " <ram:LineOne>" + XMLTools.encodeXML(contact.getStreet()) //$NON-NLS-1$
|
||||
+ "</ram:LineOne>\n"; //$NON-NLS-1$
|
||||
if (trans.getRecipient().getAdditionalAddress() != null) {
|
||||
xml += " <ram:LineTwo>" + XMLTools.encodeXML(contact.getAdditionalAddress()) //$NON-NLS-1$
|
||||
+ "</ram:LineTwo>\n"; //$NON-NLS-1$
|
||||
}
|
||||
xml += " <ram:CityName>" + XMLTools.encodeXML(contact.getLocation()) //$NON-NLS-1$
|
||||
+ "</ram:CityName>\n" //$NON-NLS-1$
|
||||
+ " <ram:CountryID>" + XMLTools.encodeXML(contact.getCountry()) //$NON-NLS-1$
|
||||
+ "</ram:CountryID>\n" //$NON-NLS-1$
|
||||
+ " </ram:PostalTradeAddress>\n"; //$NON-NLS-1$
|
||||
if (contact.getVATID() != null) {
|
||||
xml += " <ram:SpecifiedTaxRegistration>\n" //$NON-NLS-1$
|
||||
+ " <ram:ID schemeID=\"VA\">" + XMLTools.encodeXML(contact.getVATID()) //$NON-NLS-1$
|
||||
+ "</ram:ID>\n" //$NON-NLS-1$
|
||||
+ " </ram:SpecifiedTaxRegistration>\n"; //$NON-NLS-1$
|
||||
}
|
||||
return xml;
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateXML(IZUGFeRDExportableTransaction trans) {
|
||||
this.trans = trans;
|
||||
|
||||
boolean hasDueDate=false;
|
||||
String taxCategoryCode="";
|
||||
SimpleDateFormat germanDateFormat = new SimpleDateFormat("dd.MM.yyyy"); //$NON-NLS-1$
|
||||
SimpleDateFormat zugferdDateFormat = new SimpleDateFormat("yyyyMMdd"); //$NON-NLS-1$
|
||||
String exemptionReason="";
|
||||
|
||||
if (paymentTermsDescription==null) {
|
||||
paymentTermsDescription= "Zahlbar ohne Abzug bis " + germanDateFormat.format(trans.getDueDate());
|
||||
|
||||
}
|
||||
if (trans.getPaymentTermDescription()!=null) {
|
||||
paymentTermsDescription=trans.getPaymentTermDescription();
|
||||
}
|
||||
|
||||
String senderReg = "";
|
||||
if (trans.getOwnOrganisationFullPlaintextInfo() != null) {
|
||||
senderReg = "" + "<ram:IncludedNote>\n" + " <ram:Content>\n"
|
||||
+ XMLTools.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\""
|
||||
+ " 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:GuidelineSpecifiedDocumentContextParameter>\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>" + XMLTools.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\">" //$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"
|
||||
+ " </rsm:ExchangedDocument>\n" //$NON-NLS-1$
|
||||
+ " <rsm:SupplyChainTradeTransaction>\n"; //$NON-NLS-1$
|
||||
int lineID = 0;
|
||||
for (IZUGFeRDExportableItem currentItem : trans.getZFItems()) {
|
||||
lineID++;
|
||||
taxCategoryCode=currentItem.getProduct().getTaxCategoryCode();
|
||||
if (currentItem.getProduct().isIntraCommunitySupply()) {
|
||||
exemptionReason="<ram:ExemptionReason>Intra-community supply</ram:ExemptionReason>";
|
||||
}
|
||||
|
||||
LineCalc lc = new LineCalc(currentItem);
|
||||
xml = xml + " <ram:IncludedSupplyChainTradeLineItem>\n" + //$NON-NLS-1$
|
||||
" <ram:AssociatedDocumentLineDocument>\n" //$NON-NLS-1$
|
||||
+ " <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>" + XMLTools.encodeXML(currentItem.getProduct().getName()) + "</ram:Name>\n" //$NON-NLS-1$ //$NON-NLS-2$
|
||||
+ " <ram:Description>" + XMLTools.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(lc.getPriceGross()) //$NON-NLS-1$
|
||||
+ "</ram:ChargeAmount>\n" //$NON-NLS-1$ //currencyID=\"EUR\"
|
||||
+ " <ram:BasisQuantity unitCode=\"" + XMLTools.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()) //$NON-NLS-1$
|
||||
+ "</ram:ChargeAmount>\n" //$NON-NLS-1$ // currencyID=\"EUR\"
|
||||
+ " <ram:BasisQuantity unitCode=\"" + XMLTools.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=\"" + XMLTools.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$
|
||||
+ exemptionReason
|
||||
+ " <ram:CategoryCode>"+currentItem.getProduct().getTaxCategoryCode()+"</ram:CategoryCode>\n" //$NON-NLS-1$
|
||||
|
||||
+ " <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()) //$NON-NLS-1$
|
||||
+ "</ram:LineTotalAmount>\n" //$NON-NLS-1$ // currencyID=\"EUR\"
|
||||
+ " </ram:SpecifiedTradeSettlementLineMonetarySummation>\n"; //$NON-NLS-1$
|
||||
if (currentItem.getAdditionalReferencedDocumentID()!=null) {
|
||||
xml=xml + " <ram:AdditionalReferencedDocument><ram:IssuerAssignedID>"+currentItem.getAdditionalReferencedDocumentID()+"</ram:IssuerAssignedID><ram:TypeCode>130</ram:TypeCode></ram:AdditionalReferencedDocument>\n"; //$NON-NLS-1$
|
||||
|
||||
}
|
||||
xml=xml + " </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>" + XMLTools.encodeXML(trans.getReferenceNumber()) + "</ram:BuyerReference>\n";
|
||||
|
||||
}
|
||||
xml = xml + " <ram:SellerTradeParty>\n" //$NON-NLS-1$
|
||||
// + " <GlobalID schemeID=\"0088\">4000001123452</GlobalID>\n"
|
||||
+ " <ram:Name>" + XMLTools.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>"
|
||||
+ XMLTools.encodeXML(trans.getOwnVATID()) + "</ram:ID>\n" + " <ram:TradingBusinessName>"
|
||||
+ XMLTools.encodeXML(trans.getOwnOrganisationName()) + "</ram:TradingBusinessName>\n"
|
||||
+ " </ram:SpecifiedLegalOrganization>";
|
||||
}
|
||||
|
||||
if (trans.getOwnContact() != null) {
|
||||
xml = xml + "<ram:DefinedTradeContact>\n" + " <ram:PersonName>" + XMLTools.encodeXML(trans.getOwnContact().getName())
|
||||
+ "</ram:PersonName>\n";
|
||||
if (trans.getOwnContact().getPhone() != null) {
|
||||
|
||||
xml = xml + " <ram:TelephoneUniversalCommunication>\n" + " <ram:CompleteNumber>"
|
||||
+ XMLTools.encodeXML(trans.getOwnContact().getPhone()) + "</ram:CompleteNumber>\n"
|
||||
+ " </ram:TelephoneUniversalCommunication>\n";
|
||||
}
|
||||
if (trans.getOwnContact().getEMail() != null) {
|
||||
|
||||
xml = xml + " <ram:EmailURIUniversalCommunication>\n" + " <ram:URIID>"
|
||||
+ XMLTools.encodeXML(trans.getOwnContact().getEMail()) + "</ram:URIID>\n"
|
||||
+ " </ram:EmailURIUniversalCommunication>\n";
|
||||
}
|
||||
xml = xml + " </ram:DefinedTradeContact>";
|
||||
|
||||
}
|
||||
|
||||
xml = xml + " <ram:PostalTradeAddress>\n" + " <ram:PostcodeCode>"
|
||||
+ XMLTools.encodeXML(trans.getOwnZIP()) + "</ram:PostcodeCode>\n" + " <ram:LineOne>"
|
||||
+ XMLTools.encodeXML(trans.getOwnStreet()) + "</ram:LineOne>\n" + " <ram:CityName>" + XMLTools.encodeXML(trans.getOwnLocation())
|
||||
+ "</ram:CityName>\n" + " <ram:CountryID>" + XMLTools.encodeXML(trans.getOwnCountry())
|
||||
+ "</ram:CountryID>\n" + " </ram:PostalTradeAddress>\n"
|
||||
+ " <ram:SpecifiedTaxRegistration>\n" //$NON-NLS-1$
|
||||
+ " <ram:ID schemeID=\"FC\">" + XMLTools.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\">" + XMLTools.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"
|
||||
|
||||
xml+=getContactAsXML(trans.getRecipient());
|
||||
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" ;
|
||||
if (this.trans.getDeliveryAddress()!=null) {
|
||||
xml += "<ram:ShipToTradeParty>"+
|
||||
getContactAsXML(this.trans.getDeliveryAddress())+
|
||||
"</ram:ShipToTradeParty>";
|
||||
}
|
||||
|
||||
xml+= " <ram:ActualDeliverySupplyChainEvent>\n"
|
||||
+ " <ram:OccurrenceDateTime>";
|
||||
|
||||
if (trans.getZFDeliveryDate() != null) {
|
||||
ZUGFeRDDateFormat dateFormat = trans.getZFDeliveryDate().getFormat();
|
||||
Date date = trans.getZFDeliveryDate().getDate();
|
||||
xml += "<udt:DateTimeString format=\"" + dateFormat.getDateTimeType() + "\">"
|
||||
+ dateFormat.getFormatter().format(date) + "</udt:DateTimeString>";
|
||||
} else if (trans.getDeliveryDate() != null) {
|
||||
xml += "<udt:DateTimeString format=\"102\">" + zugferdDateFormat.format(trans.getDeliveryDate())
|
||||
+ "</udt:DateTimeString>";
|
||||
} else {
|
||||
throw new IllegalStateException("No delivery date provided");
|
||||
}
|
||||
xml += "</ram:OccurrenceDateTime>\n";
|
||||
xml += " </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-2$
|
||||
+ " <ram:PaymentReference>" + XMLTools.encodeXML(trans.getNumber()) + "</ram:PaymentReference>\n" //$NON-NLS-1$ //$NON-NLS-2$
|
||||
+ " <ram:InvoiceCurrencyCode>" + trans.getCurrency() + "</ram:InvoiceCurrencyCode>\n"; //$NON-NLS-1$
|
||||
|
||||
if (trans.getTradeSettlementPayment()!=null) {
|
||||
for (IZUGFeRDTradeSettlementPayment payment : trans.getTradeSettlementPayment()) {
|
||||
if(payment!=null) {
|
||||
hasDueDate=true;
|
||||
xml+=payment.getSettlementXML();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (trans.getTradeSettlement()!=null) {
|
||||
for (IZUGFeRDTradeSettlement payment : trans.getTradeSettlement()) {
|
||||
if(payment!=null) {
|
||||
if (payment instanceof IZUGFeRDTradeSettlementPayment) {
|
||||
hasDueDate=true;
|
||||
}
|
||||
xml+=payment.getSettlementXML();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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()) //$NON-NLS-1$
|
||||
+ "</ram:CalculatedAmount>\n" //$NON-NLS-1$ //currencyID=\"EUR\"
|
||||
+ " <ram:TypeCode>VAT</ram:TypeCode>\n" //$NON-NLS-1$
|
||||
+ exemptionReason
|
||||
+ " <ram:BasisAmount>" + currencyFormat(amount.getBasis()) + "</ram:BasisAmount>\n" // currencyID=\"EUR\"
|
||||
+ " <ram:CategoryCode>"+taxCategoryCode+"</ram:CategoryCode>\n" //$NON-NLS-1$
|
||||
+ " <ram:RateApplicablePercent>" + vatFormat(currentTaxPercent) //$NON-NLS-1$
|
||||
+ "</ram:RateApplicablePercent>\n" + " </ram:ApplicableTradeTax>\n"; //$NON-NLS-2$
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (trans.getPaymentTerms() == null) {
|
||||
xml = xml + " <ram:SpecifiedTradePaymentTerms>\n" //$NON-NLS-1$
|
||||
+ " <ram:Description>" + paymentTermsDescription + "</ram:Description>\n";
|
||||
|
||||
if (trans.getTradeSettlement() != null) {
|
||||
for (IZUGFeRDTradeSettlement payment : trans.getTradeSettlement()) {
|
||||
if (payment != null) {
|
||||
xml += payment.getPaymentXML();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hasDueDate) {
|
||||
xml = xml + " <ram:DueDateDateTime><udt:DateTimeString format=\"102\">" // $NON-NLS-2$
|
||||
+ zugferdDateFormat.format(trans.getDueDate())
|
||||
+ "</udt:DateTimeString></ram:DueDateDateTime>\n";// 20130704 //$NON-NLS-1$
|
||||
|
||||
}
|
||||
xml = xml + " </ram:SpecifiedTradePaymentTerms>\n"; //$NON-NLS-1$
|
||||
} else {
|
||||
xml = xml + buildPaymentTermsXml();
|
||||
}
|
||||
|
||||
xml = xml + " <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=\"" + trans.getCurrency() + "\">" //$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>" + 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";
|
||||
|
||||
xml = xml + " </rsm:SupplyChainTradeTransaction>\n" //$NON-NLS-1$
|
||||
+ "</rsm:CrossIndustryInvoice>"; //$NON-NLS-1$
|
||||
|
||||
byte[] zugferdRaw;
|
||||
try {
|
||||
zugferdRaw = xml.getBytes("UTF-8");
|
||||
|
||||
if ((zugferdRaw[0] == (byte) 0xEF) && (zugferdRaw[1] == (byte) 0xBB) && (zugferdRaw[2] == (byte) 0xBF)) {
|
||||
// I don't like BOMs, lets remove it
|
||||
zugferdData = new byte[zugferdRaw.length - 3];
|
||||
System.arraycopy(zugferdRaw, 3, zugferdData, 0, zugferdRaw.length - 3);
|
||||
} else {
|
||||
zugferdData = zugferdRaw;
|
||||
}
|
||||
} catch (UnsupportedEncodingException e) {
|
||||
Logger.getLogger(Toecount.class.getName()).log(Level.SEVERE, null, e);
|
||||
} // $NON-NLS-1$
|
||||
}
|
||||
|
||||
private String buildPaymentTermsXml() {
|
||||
String paymentTermsXml = "<ram:SpecifiedTradePaymentTerms>";
|
||||
|
||||
IZUGFeRDPaymentTerms paymentTerms = trans.getPaymentTerms();
|
||||
IZUGFeRDPaymentDiscountTerms discountTerms = paymentTerms.getDiscountTerms();
|
||||
IZUGFeRDDate dueDate = paymentTerms.getDueDate();
|
||||
if (dueDate != null && discountTerms != null && discountTerms.getBaseDate() != null) {
|
||||
throw new IllegalStateException(
|
||||
"if paymentTerms.dueDate is specified, paymentTerms.discountTerms.baseDate has not to be specified");
|
||||
}
|
||||
paymentTermsXml += "<ram:Description>" + paymentTerms.getDescription() + "</ram:Description>";
|
||||
if (dueDate != null) {
|
||||
paymentTermsXml += "<ram:DueDateDateTime>";
|
||||
paymentTermsXml += "<udt:DateTimeString format=\"" + dueDate.getFormat().getDateTimeType() + "\">"
|
||||
+ dueDate.getFormat().getFormatter().format(dueDate.getDate()) + "</udt:DateTimeString>";
|
||||
paymentTermsXml += "</ram:DueDateDateTime>";
|
||||
}
|
||||
|
||||
if (discountTerms != null) {
|
||||
paymentTermsXml += "<ram:ApplicableTradePaymentDiscountTerms>";
|
||||
String currency = trans.getCurrency();
|
||||
String basisAmount = currencyFormat(getTotalGross());
|
||||
paymentTermsXml += "<ram:BasisAmount currencyID=\"" + currency + "\">" + basisAmount + "</ram:BasisAmount>";
|
||||
paymentTermsXml += "<ram:CalculationPercent>" + discountTerms.getCalculationPercentage().toString()
|
||||
+ "</ram:CalculationPercent>";
|
||||
|
||||
if (discountTerms.getBaseDate() != null) {
|
||||
Date baseDate = discountTerms.getBaseDate().getDate();
|
||||
ZUGFeRDDateFormat baseDateFormat = discountTerms.getBaseDate().getFormat();
|
||||
paymentTermsXml += "<ram:BasisDateTime>";
|
||||
paymentTermsXml += "<udt:DateTimeString format=\"" + baseDateFormat.getDateTimeType() + "\">" + baseDateFormat.getFormatter().format(baseDate) + "</udt:DateTimeString>";
|
||||
paymentTermsXml += "</ram:BasisDateTime>";
|
||||
|
||||
paymentTermsXml += "<ram:BasisPeriodMeasure unitCode=\"" + discountTerms.getBasePeriodUnitCode() + "\">"
|
||||
+ discountTerms.getBasePeriodMeasure() + "</ram:BasisPeriodMeasure>";
|
||||
}
|
||||
|
||||
paymentTermsXml += "</ram:ApplicableTradePaymentDiscountTerms>";
|
||||
}
|
||||
|
||||
paymentTermsXml += "</ram:SpecifiedTradePaymentTerms>";
|
||||
return paymentTermsXml;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/** **********************************************************************
|
||||
*
|
||||
* 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 enum ZUGFeRDConformanceLevel {
|
||||
BASIC, COMFORT, EXTENDED, EN16931/*=Comfort*/, MINIMUM, BASICWL /*basic without lines, less than basic*/, CIUS
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package org.mustangproject.ZUGFeRD;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
|
||||
import org.mustangproject.ZUGFeRD.model.DateTimeTypeConstants;
|
||||
|
||||
public enum ZUGFeRDDateFormat {
|
||||
|
||||
MONTH_OF_YEAR(DateTimeTypeConstants.MONTH, new SimpleDateFormat("yyyyMM")),
|
||||
WEEK_OF_YEAR(DateTimeTypeConstants.WEEK, new SimpleDateFormat("yyyyww")),
|
||||
DATE(DateTimeTypeConstants.DATE, new SimpleDateFormat("yyyyMMdd"));
|
||||
|
||||
private String dateTimeType;
|
||||
private SimpleDateFormat formatter;
|
||||
|
||||
private ZUGFeRDDateFormat(String dateTimeType, SimpleDateFormat formatter) {
|
||||
this.dateTimeType = dateTimeType;
|
||||
this.formatter = formatter;
|
||||
}
|
||||
|
||||
public String getDateTimeType() {
|
||||
return dateTimeType;
|
||||
}
|
||||
|
||||
public SimpleDateFormat getFormatter() {
|
||||
return formatter;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/** **********************************************************************
|
||||
*
|
||||
* 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 class ZUGFeRDExportException extends RuntimeException {
|
||||
/**
|
||||
*
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public ZUGFeRDExportException() {
|
||||
}
|
||||
|
||||
public ZUGFeRDExportException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public ZUGFeRDExportException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public ZUGFeRDExportException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,746 @@
|
||||
|
||||
/** **********************************************************************
|
||||
*
|
||||
* 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;
|
||||
|
||||
/*
|
||||
* Mustangproject's ZUGFeRD implementation ZUGFeRD exporter Licensed under the
|
||||
* APLv2
|
||||
*
|
||||
* @date 2014-07-12
|
||||
* @version 1.2.0
|
||||
* @author jstaerk
|
||||
*
|
||||
*/
|
||||
|
||||
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;
|
||||
import org.apache.pdfbox.pdmodel.common.filespecification.PDEmbeddedFile;
|
||||
import org.apache.xmpbox.XMPMetadata;
|
||||
import org.apache.xmpbox.schema.AdobePDFSchema;
|
||||
import org.apache.xmpbox.schema.DublinCoreSchema;
|
||||
import org.apache.xmpbox.schema.PDFAIdentificationSchema;
|
||||
import org.apache.xmpbox.schema.XMPBasicSchema;
|
||||
import org.apache.xmpbox.type.BadFieldValueException;
|
||||
import org.apache.xmpbox.xml.XmpSerializer;
|
||||
|
||||
import javax.xml.transform.TransformerException;
|
||||
import java.io.*;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class ZUGFeRDExporter implements Closeable {
|
||||
|
||||
public static final int DefaultZUGFeRDVersion = 1;
|
||||
|
||||
private boolean isFacturX = false;
|
||||
|
||||
/**
|
||||
* To use the ZUGFeRD exporter, implement IZUGFeRDExportableTransaction in
|
||||
* yourTransaction (which will require you to implement Product, Item and
|
||||
* Contact) then call doc = PDDocument.load(PDFfilename); // automatically add
|
||||
* Zugferd to all outgoing invoices ZUGFeRDExporter ze = new ZUGFeRDExporter();
|
||||
* ze.PDFmakeA3compliant(doc, "Your application name",
|
||||
* System.getProperty("user.name"), true); ze.PDFattachZugferdFile(doc,
|
||||
* yourTransaction);
|
||||
* <p/>
|
||||
* doc.save(PDFfilename);
|
||||
*
|
||||
* @author jstaerk
|
||||
* @deprecated Use the factory methods {@link #createFromPDFA3(String)},
|
||||
* {@link #createFromPDFA3(InputStream)} or the
|
||||
* {@link ZUGFeRDExporterFromA1Factory} instead
|
||||
*/
|
||||
// // MAIN CLASS
|
||||
@Deprecated
|
||||
private PDFAConformanceLevel conformanceLevel = PDFAConformanceLevel.UNICODE;
|
||||
|
||||
// BASIC, COMFORT etc - may be set from outside.
|
||||
@Deprecated
|
||||
private ZUGFeRDConformanceLevel profile = ZUGFeRDConformanceLevel.EN16931;
|
||||
|
||||
/**
|
||||
* Data (XML invoice) to be added to the ZUGFeRD PDF. It may be externally set,
|
||||
* in which case passing a IZUGFeRDExportableTransaction is not necessary. By
|
||||
* default it is null meaning the caller needs to pass a
|
||||
* IZUGFeRDExportableTransaction for the XML to be populated.
|
||||
*/
|
||||
IXMLProvider xmlProvider;
|
||||
protected PDMetadata metadata = null;
|
||||
protected PDFAIdentificationSchema pdfaid = null;
|
||||
protected XMPMetadata xmp = null;
|
||||
/**
|
||||
* Producer attribute for PDF
|
||||
*/
|
||||
protected String producer = "mustangproject";
|
||||
/**
|
||||
* Author/Creator attribute for PDF
|
||||
*/
|
||||
protected String creator = "mustangproject";
|
||||
/**
|
||||
* CreatorTool
|
||||
*/
|
||||
protected String creatorTool = "mustangproject";
|
||||
|
||||
@Deprecated
|
||||
private boolean ignoreA1Errors;
|
||||
protected boolean ensurePDFisUpgraded = true;
|
||||
private PDDocument doc;
|
||||
int ZFVersion;
|
||||
|
||||
private HashMap<String, byte[]> additionalFiles = new HashMap<String, byte[]>();
|
||||
|
||||
|
||||
private boolean disableAutoClose;
|
||||
|
||||
private boolean fileAttached = false;
|
||||
protected boolean attachZUGFeRDHeaders = true;
|
||||
|
||||
private boolean documentPrepared = false;
|
||||
|
||||
public ZUGFeRDExporter() {
|
||||
init();
|
||||
}
|
||||
|
||||
public ZUGFeRDExporter(PDDocument doc2) {
|
||||
doc = doc2;
|
||||
init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds additional file attachments into the ZF
|
||||
* @param filename the name of the attachment
|
||||
* @param filecontent the bytearray with the file contents
|
||||
*/
|
||||
public void addAdditionalFile(String filename, byte[] filecontent) {
|
||||
additionalFiles.put(filename, filecontent);
|
||||
|
||||
}
|
||||
|
||||
/***
|
||||
* internal helper function: get namespace for given zugferd or factur-x version
|
||||
* @param ver the ZUGFeRD version
|
||||
* @return the URN of the namespace
|
||||
*/
|
||||
public String getNamespaceForVersion(int ver) {
|
||||
if (isFacturX) {
|
||||
return "urn:factur-x:pdfa:CrossIndustryDocument:invoice:1p0#";
|
||||
} else if (ver == 1) {
|
||||
return "urn:ferd:pdfa:CrossIndustryDocument:invoice:1p0#";
|
||||
} else if (ver == 2) {
|
||||
return "urn:zugferd:pdfa:CrossIndustryDocument:invoice:2p0#";
|
||||
|
||||
} else {
|
||||
throw new IllegalArgumentException("Version not supported");
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* internal helper: returns the namespace prefix for the given zf/fx version number
|
||||
* @param ver the zf/fx version
|
||||
* @return the namespace prefix as string, without colon
|
||||
*/
|
||||
public String getPrefixForVersion(int ver) {
|
||||
if (isFacturX) {
|
||||
return "fx";
|
||||
} else {
|
||||
return "zf";
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* internal helper: return the name of the file attachment for the given zf/fx version
|
||||
* @param ver the zf/fx version
|
||||
* @return the filename of the file to be embedded
|
||||
*/
|
||||
public String getFilenameForVersion(int ver) {
|
||||
if (isFacturX) {
|
||||
return "factur-x.xml";
|
||||
} else {
|
||||
if (ver==1) {
|
||||
return "ZUGFeRD-invoice.xml";
|
||||
} else {
|
||||
return "zugferd-invoice.xml";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void setZUGFeRDVersion(int ver) {
|
||||
if (ver == 1) {
|
||||
ZUGFeRD1PullProvider z1p = new ZUGFeRD1PullProvider();
|
||||
this.xmlProvider = z1p;
|
||||
} else if (ver == 2) {
|
||||
ZUGFeRD2PullProvider z2p = new ZUGFeRD2PullProvider();
|
||||
this.xmlProvider = z2p;
|
||||
} else {
|
||||
throw new IllegalArgumentException("Version not supported");
|
||||
}
|
||||
ZFVersion = ver;
|
||||
}
|
||||
|
||||
public IXMLProvider getProvider() {
|
||||
return xmlProvider;
|
||||
}
|
||||
|
||||
private void init() {
|
||||
setZUGFeRDVersion(DefaultZUGFeRDVersion);
|
||||
}
|
||||
|
||||
public void setFacturX() {
|
||||
setZUGFeRDVersion(2);
|
||||
isFacturX = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* All files are PDF/A-3, setConformance refers to the level conformance.
|
||||
*
|
||||
* PDF/A-3 has three conformance levels, called "A", "U" and "B".
|
||||
* <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>
|
||||
* 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
|
||||
*/
|
||||
@Deprecated
|
||||
public void setConformanceLevel(PDFAConformanceLevel newLevel) {
|
||||
if (newLevel == null) {
|
||||
throw new NullPointerException("pdf conformance level");
|
||||
}
|
||||
conformanceLevel = newLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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>
|
||||
* 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>
|
||||
* 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
|
||||
*/
|
||||
@Deprecated
|
||||
public void setConformanceLevel(String newLevel) {
|
||||
conformanceLevel = PDFAConformanceLevel.findByLetter(newLevel);
|
||||
}
|
||||
|
||||
/**
|
||||
* enables the flag to indicate a test invoice in the XML structure
|
||||
*/
|
||||
public void setTest() {
|
||||
xmlProvider.setTest();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link ZUGFeRDExporterFromA1Factory} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void ignoreA1Errors() {
|
||||
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)));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
public PDDocumentCatalog PDFmakeA3compliant(String filename, String producer, String creator,
|
||||
boolean attachZugferdHeaders) throws IOException, TransformerException {
|
||||
|
||||
doc = createPDFA1Factory().setProducer(producer).setCreator(creator).load(filename).doc;
|
||||
|
||||
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
|
||||
public PDDocumentCatalog PDFmakeA3compliant(InputStream file, String producer, String creator,
|
||||
boolean attachZugferdHeaders) throws IOException, TransformerException {
|
||||
|
||||
doc = createPDFA1Factory().setProducer(producer).setCreator(creator).load(file).doc;
|
||||
|
||||
return doc.getDocumentCatalog();
|
||||
}
|
||||
|
||||
|
||||
private IExporterFactory createPDFA1Factory() {
|
||||
ZUGFeRDExporterFromA1Factory factory = new ZUGFeRDExporterFromA1Factory();
|
||||
if (ignoreA1Errors) {
|
||||
factory.ignorePDFAErrors();
|
||||
}
|
||||
return factory.setZUGFeRDConformanceLevel(profile).setConformanceLevel(conformanceLevel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
if (doc != null) {
|
||||
doc.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Embeds the Zugferd XML structure in a file named ZUGFeRD-invoice.xml.
|
||||
*
|
||||
* @param trans a IZUGFeRDExportableTransaction that provides the data-model to
|
||||
* 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",
|
||||
"Invoice metadata conforming to ZUGFeRD standard (http://www.ferd-net.de/front_content.php?idcat=231&lang=4)",
|
||||
"text/xml", xmlProvider.getXML());
|
||||
for (String filenameAdditional : additionalFiles.keySet()) {
|
||||
PDFAttachGenericFile(doc, filenameAdditional, "Supplement", "ZUGFeRD extension/additional data", "text/xml", additionalFiles.get(filenameAdditional));
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* 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();
|
||||
}
|
||||
if ((!fileAttached) && (attachZUGFeRDHeaders)) {
|
||||
throw new IOException(
|
||||
"File must be attached (usually with PDFattachZugferdFile) before perfoming this operation");
|
||||
}
|
||||
doc.save(ZUGFeRDfilename);
|
||||
if (!disableAutoClose) {
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
* 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 (!documentPrepared) {
|
||||
prepareDocument();
|
||||
}
|
||||
if ((!fileAttached) && (attachZUGFeRDHeaders)) {
|
||||
throw new IOException(
|
||||
"File must be attached (usually with PDFattachZugferdFile) before perfoming this operation");
|
||||
}
|
||||
doc.save(output);
|
||||
if (!disableAutoClose) {
|
||||
close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Embeds an external file (generic - any type allowed) in the PDF.
|
||||
*
|
||||
* @param doc PDDocument to attach the file to.
|
||||
* @param filename name of the file that will become attachment name in the PDF
|
||||
* @param relationship how the file relates to the content, e.g. "Alternative"
|
||||
* @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 if anything is wrong with filename
|
||||
*/
|
||||
public void PDFAttachGenericFile(PDDocument doc, String filename, String relationship, String description,
|
||||
String subType, byte[] data) throws IOException {
|
||||
fileAttached = true;
|
||||
|
||||
PDComplexFileSpecification fs = new PDComplexFileSpecification();
|
||||
fs.setFile(filename);
|
||||
|
||||
COSDictionary dict = fs.getCOSObject();
|
||||
dict.setName("AFRelationship", relationship);
|
||||
dict.setString("UF", filename);
|
||||
dict.setString("Desc", description);
|
||||
|
||||
ByteArrayInputStream fakeFile = new ByteArrayInputStream(data);
|
||||
PDEmbeddedFile ef = new PDEmbeddedFile(doc, fakeFile);
|
||||
// ef.addCompression();
|
||||
ef.setSubtype(subType);
|
||||
ef.setSize(data.length);
|
||||
ef.setCreationDate(new GregorianCalendar());
|
||||
|
||||
ef.setModDate(GregorianCalendar.getInstance());
|
||||
|
||||
fs.setEmbeddedFile(ef);
|
||||
|
||||
// In addition make sure the embedded file is set under /UF
|
||||
dict = fs.getCOSObject();
|
||||
COSDictionary efDict = (COSDictionary) dict.getDictionaryObject(COSName.EF);
|
||||
COSBase lowerLevelFile = efDict.getItem(COSName.F);
|
||||
efDict.setItem(COSName.UF, lowerLevelFile);
|
||||
|
||||
// now add the entry to the embedded file tree and set in the document.
|
||||
PDDocumentNameDictionary names = new PDDocumentNameDictionary(doc.getDocumentCatalog());
|
||||
PDEmbeddedFilesNameTreeNode efTree = names.getEmbeddedFiles();
|
||||
if (efTree == null) {
|
||||
efTree = new PDEmbeddedFilesNameTreeNode();
|
||||
}
|
||||
|
||||
Map<String, PDComplexFileSpecification> namesMap = new HashMap<>();
|
||||
|
||||
Map<String, PDComplexFileSpecification> oldNamesMap = efTree.getNames();
|
||||
if (oldNamesMap != null) {
|
||||
for (String key : oldNamesMap.keySet()) {
|
||||
namesMap.put(key, oldNamesMap.get(key));
|
||||
}
|
||||
}
|
||||
namesMap.put(filename, fs);
|
||||
efTree.setNames(namesMap);
|
||||
|
||||
names.setEmbeddedFiles(efTree);
|
||||
doc.getDocumentCatalog().setNames(names);
|
||||
|
||||
// AF entry (Array) in catalog with the FileSpec
|
||||
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
|
||||
* useful for use-cases where the XML has already been produced by some external
|
||||
* 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();
|
||||
cus.setXML(zugferdData);
|
||||
this.xmlProvider = cus;
|
||||
PDFattachZugferdFile(null);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the ZUGFeRD profile.
|
||||
*
|
||||
* @param zUGFeRDConformanceLevel the new conformance level
|
||||
* @deprecated Use {@link ZUGFeRDExporterFromA1Factory} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void setZUGFeRDConformanceLevel(ZUGFeRDConformanceLevel zUGFeRDConformanceLevel) {
|
||||
if (zUGFeRDConformanceLevel == null) {
|
||||
throw new NullPointerException("ZUGFeRD conformance level");
|
||||
}
|
||||
this.profile = zUGFeRDConformanceLevel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the ZUGFeRD profile.
|
||||
*
|
||||
* @param zUGFeRDConformanceLevel the new conformance level
|
||||
* @deprecated Use {@link #setConformanceLevel(PDFAConformanceLevel)} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public void setZUGFeRDConformanceLevel(String zUGFeRDConformanceLevel) {
|
||||
this.profile = ZUGFeRDConformanceLevel.valueOf(zUGFeRDConformanceLevel);
|
||||
}
|
||||
|
||||
/**
|
||||
* *
|
||||
* Returns the PDFBox PDF Document
|
||||
*
|
||||
* @return PDDocument the PDFBox PDF
|
||||
*/
|
||||
public PDDocument getDoc() {
|
||||
return doc;
|
||||
}
|
||||
|
||||
/**
|
||||
* This will add both the RDF-indication which embedded file is Zugferd and the
|
||||
* neccessary PDF/A schema extension description to be able to add this
|
||||
* information to RDF
|
||||
*
|
||||
* @param metadata the PDFbox XMPMetadata object
|
||||
*/
|
||||
protected void addXMP(XMPMetadata metadata) {
|
||||
|
||||
if (attachZUGFeRDHeaders) {
|
||||
XMPSchemaZugferd zf = new XMPSchemaZugferd(metadata, ZFVersion, isFacturX, profile,
|
||||
getNamespaceForVersion(ZFVersion), getPrefixForVersion(ZFVersion),
|
||||
getFilenameForVersion(ZFVersion));
|
||||
|
||||
metadata.addSchema(zf);
|
||||
}
|
||||
|
||||
XMPSchemaPDFAExtensions pdfaex = new XMPSchemaPDFAExtensions(this, metadata, ZFVersion, attachZUGFeRDHeaders);
|
||||
pdfaex.setZUGFeRDVersion(ZFVersion);
|
||||
metadata.addSchema(pdfaex);
|
||||
}
|
||||
|
||||
protected byte[] serializeXmpMetadata(XMPMetadata xmpMetadata) throws TransformerException {
|
||||
XmpSerializer serializer = new XmpSerializer();
|
||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||
|
||||
String prefix = "<?xpacket begin=\"\uFEFF\" id=\"W5M0MpCehiHzreSzNTczkc9d\"?>";
|
||||
String suffix = "<?xpacket end=\"w\"?>";
|
||||
|
||||
try {
|
||||
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)
|
||||
{
|
||||
throw new TransformerException(e);
|
||||
} catch (IOException e)
|
||||
{
|
||||
throw new TransformerException(e);
|
||||
}
|
||||
return buffer.toByteArray();
|
||||
}
|
||||
|
||||
protected void prepareDocument() throws IOException {
|
||||
String fullProducer = producer + " (via mustangproject.org " + org.mustangproject.ZUGFeRD.Version.VERSION + ")";
|
||||
|
||||
PDDocumentCatalog cat = doc.getDocumentCatalog();
|
||||
metadata = new PDMetadata(doc);
|
||||
cat.setMetadata(metadata);
|
||||
|
||||
xmp = XMPMetadata.createXMPMetadata();
|
||||
|
||||
pdfaid = new PDFAIdentificationSchema(xmp);
|
||||
|
||||
xmp.addSchema(pdfaid);
|
||||
|
||||
DublinCoreSchema dc = xmp.createAndAddDublinCoreSchema();
|
||||
|
||||
dc.addCreator(creator);
|
||||
|
||||
XMPBasicSchema xsb = xmp.createAndAddXMPBasicSchema();
|
||||
|
||||
xsb.setCreatorTool(creatorTool);
|
||||
xsb.setCreateDate(GregorianCalendar.getInstance());
|
||||
// PDDocumentInformation pdi=doc.getDocumentInformation();
|
||||
PDDocumentInformation pdi = new PDDocumentInformation();
|
||||
pdi.setProducer(fullProducer);
|
||||
pdi.setAuthor(creator);
|
||||
doc.setDocumentInformation(pdi);
|
||||
|
||||
AdobePDFSchema pdf = xmp.createAndAddAdobePDFSchema();
|
||||
pdf.setProducer(fullProducer);
|
||||
if (ensurePDFisUpgraded) {
|
||||
try {
|
||||
pdfaid.setConformance(conformanceLevel.getLetter());// $NON-NLS-1$ //$NON-NLS-1$
|
||||
} catch (BadFieldValueException ex) {
|
||||
// This should be impossible, because it would occur only if an illegal
|
||||
// conformance level is supplied,
|
||||
// however the enum enforces that the conformance level is valid.
|
||||
throw new Error(ex);
|
||||
}
|
||||
|
||||
pdfaid.setPart(3);
|
||||
}
|
||||
addXMP(xmp); /*
|
||||
* this is the only line where we do something Zugferd-specific, i.e. add PDF
|
||||
* metadata specifically for Zugferd, not generically for a embedded file
|
||||
*/
|
||||
|
||||
|
||||
try {
|
||||
metadata.importXMPMetadata(serializeXmpMetadata(xmp));
|
||||
|
||||
} catch (TransformerException e) {
|
||||
throw new ZUGFeRDExportException("Could not export XmpMetadata", e);
|
||||
}
|
||||
documentPrepared = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return if pdf file will be automatically closed after adding ZF
|
||||
*/
|
||||
public boolean isAutoCloseDisabled() {
|
||||
return disableAutoClose;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param disableAutoClose prevent PDF file from being closed after adding ZF
|
||||
*/
|
||||
public void disableAutoClose(boolean disableAutoClose) {
|
||||
this.disableAutoClose = disableAutoClose;
|
||||
}
|
||||
|
||||
/**
|
||||
* the human author (use factory method instead)
|
||||
*
|
||||
* @param creator the (human) name who created the PDF
|
||||
*/
|
||||
@Deprecated
|
||||
public void setCreator(String creator) {
|
||||
this.creator = creator;
|
||||
}
|
||||
|
||||
/**
|
||||
* the CreatorTool attribute for the PDF
|
||||
*
|
||||
* @param creatorTool the application which created the PDF
|
||||
*/
|
||||
protected void setCreatorTool(String creatorTool) {
|
||||
this.creatorTool = creatorTool;
|
||||
}
|
||||
|
||||
/**
|
||||
* the authoring software (use factory method instead)
|
||||
*
|
||||
* @param producer the authoring software
|
||||
*/
|
||||
@Deprecated
|
||||
public void setProducer(String producer) {
|
||||
this.producer = producer;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ensurePDFisUpgraded if not set the PDF/A won't be relabelled A/3, e.g. if it already is one
|
||||
*/
|
||||
public void setPDFA3(boolean ensurePDFisUpgraded) {
|
||||
this.ensurePDFisUpgraded = ensurePDFisUpgraded;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param attachZUGFeRDHeaders if false the ZUGFeRD XMP metadata won't be added, e.g. if it's not the first file
|
||||
*/
|
||||
public void setAttachZUGFeRDHeaders(boolean attachZUGFeRDHeaders) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/** **********************************************************************
|
||||
*
|
||||
* 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 class ZUGFeRDExporterFromA1Factory extends ZUGFeRDExporterFromA3Factory implements IExporterFactory {
|
||||
public ZUGFeRDExporterFromA1Factory() {
|
||||
ensurePDFisUpgraded = true;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,208 @@
|
||||
/** **********************************************************************
|
||||
*
|
||||
* 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 org.apache.pdfbox.io.IOUtils;
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.apache.pdfbox.preflight.PreflightDocument;
|
||||
import org.apache.pdfbox.preflight.exception.ValidationException;
|
||||
import org.apache.pdfbox.preflight.parser.PreflightParser;
|
||||
import org.apache.pdfbox.preflight.utils.ByteArrayDataSource;
|
||||
|
||||
import javax.activation.DataSource;
|
||||
import javax.activation.FileDataSource;
|
||||
import java.io.*;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class ZUGFeRDExporterFromA3Factory implements IExporterFactory {
|
||||
protected boolean ignorePDFAErrors = false;
|
||||
protected ZUGFeRDConformanceLevel zugferdConformanceLevel = ZUGFeRDConformanceLevel.EXTENDED;
|
||||
protected PDFAConformanceLevel conformanceLevel = PDFAConformanceLevel.UNICODE;
|
||||
/**
|
||||
* Producer (attribute for PDF
|
||||
*/
|
||||
protected String producer = "mustangproject";
|
||||
/**
|
||||
* Human creator (attribute for PDF)
|
||||
*/
|
||||
protected String creator = "mustangproject";
|
||||
/**
|
||||
* Creator tool (attribute for PDF)
|
||||
*/
|
||||
protected String creatorTool = null;
|
||||
|
||||
private HashMap<String, byte[]> additionalXMLs = new HashMap<String, byte[]>();
|
||||
|
||||
|
||||
protected int ZFVersion = ZUGFeRDExporter.DefaultZUGFeRDVersion;
|
||||
protected boolean ensurePDFisUpgraded = false;
|
||||
private boolean attachZUGFeRDHeaders = true;
|
||||
|
||||
/**
|
||||
* 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 pdfFilename filename of an PDF/A1 compliant document
|
||||
*/
|
||||
public ZUGFeRDExporter load(String pdfFilename) throws IOException {
|
||||
|
||||
ensurePDFIsValidPDFA(new FileDataSource(pdfFilename));
|
||||
try (FileInputStream pdf = new FileInputStream(pdfFilename)) {
|
||||
return load(readAllBytes(pdf));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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 pdfBinary binary of a PDF/A1 compliant document
|
||||
*/
|
||||
public ZUGFeRDExporter load(byte[] pdfBinary) throws IOException {
|
||||
ensurePDFIsValidPDFA(new ByteArrayDataSource(new ByteArrayInputStream(pdfBinary)));
|
||||
PDDocument doc = PDDocument.load(pdfBinary);
|
||||
ZUGFeRDExporter zugFeRDExporter = new ZUGFeRDExporter(doc);
|
||||
zugFeRDExporter.configure(ZFVersion, zugferdConformanceLevel, creator, producer);
|
||||
zugFeRDExporter.setAttachZUGFeRDHeaders(attachZUGFeRDHeaders);
|
||||
zugFeRDExporter.setPDFA3(ensurePDFisUpgraded);
|
||||
|
||||
return zugFeRDExporter;
|
||||
}
|
||||
|
||||
public ZUGFeRDExporterFromA3Factory() {
|
||||
|
||||
ensurePDFisUpgraded = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 pdfSource source to read a PDF/A1 compliant document from
|
||||
*/
|
||||
public ZUGFeRDExporter load(InputStream pdfSource) throws IOException {
|
||||
return load(readAllBytes(pdfSource));
|
||||
}
|
||||
|
||||
private void ensurePDFIsValidPDFA(final DataSource dataSource) throws IOException {
|
||||
if (!ignorePDFAErrors && !isValidA1(dataSource)) {
|
||||
throw new IOException("File is not a valid PDF/A input file");
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] readAllBytes(InputStream in) throws IOException {
|
||||
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||
IOUtils.copy(in, buffer);
|
||||
return buffer.toByteArray();
|
||||
}
|
||||
|
||||
private static boolean isValidA1(DataSource dataSource) throws IOException {
|
||||
return getPDFAParserValidationResult(new PreflightParser(dataSource));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the ZUGFeRD conformance level (override).
|
||||
*
|
||||
* @param zugferdConformanceLevel the new conformance level
|
||||
*/
|
||||
public IExporterFactory setZUGFeRDConformanceLevel(ZUGFeRDConformanceLevel zugferdConformanceLevel) {
|
||||
this.zugferdConformanceLevel = zugferdConformanceLevel;
|
||||
return this;
|
||||
}
|
||||
|
||||
private static boolean getPDFAParserValidationResult(PreflightParser parser) throws IOException {
|
||||
/*
|
||||
* Parse the PDF file with PreflightParser that inherits from the
|
||||
* NonSequentialParser. Some additional controls are present to check a set of
|
||||
* PDF/A requirements. (Stream length consistency, EOL after some Keyword...)
|
||||
*/
|
||||
parser.parse();// might add a Format.PDF_A1A as parameter and iterate through A1 and A3
|
||||
|
||||
try (PreflightDocument document = parser.getPreflightDocument()) {
|
||||
/*
|
||||
* Once the syntax validation is done, the parser can provide a
|
||||
* PreflightDocument (that inherits from PDDocument) This document process the
|
||||
* end of PDF/A validation.
|
||||
*/
|
||||
|
||||
document.validate();
|
||||
|
||||
// Get validation result
|
||||
return document.getResult().isValid();
|
||||
} catch (ValidationException e) {
|
||||
/*
|
||||
* the parse method can throw a SyntaxValidationException if the PDF file can't
|
||||
* be parsed. In this case, the exception contains an instance of
|
||||
* ValidationResult
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* All files are PDF/A-3, setConformance refers to the level conformance.
|
||||
* <p>
|
||||
* PDF/A-3 has three coformance levels, called "A", "U" and "B".
|
||||
* <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>
|
||||
* Feel free to pass "A" as new level if you know what you are doing :-)
|
||||
*/
|
||||
public IExporterFactory setConformanceLevel(PDFAConformanceLevel newLevel) {
|
||||
conformanceLevel = newLevel;
|
||||
return this;
|
||||
}
|
||||
|
||||
public IExporterFactory ignorePDFAErrors() {
|
||||
this.ignorePDFAErrors = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
public IExporterFactory setCreator(String creator) {
|
||||
this.creator = creator;
|
||||
return this;
|
||||
}
|
||||
|
||||
public IExporterFactory setCreatorTool(String creatorTool) {
|
||||
this.creatorTool = creatorTool;
|
||||
return this;
|
||||
}
|
||||
|
||||
public IExporterFactory setProducer(String producer) {
|
||||
this.producer = producer;
|
||||
return this;
|
||||
}
|
||||
|
||||
public IExporterFactory setAttachZUGFeRDHeaders(boolean attachHeaders) {
|
||||
this.attachZUGFeRDHeaders = attachHeaders;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public IExporterFactory setZUGFeRDVersion(int version) {
|
||||
this.ZFVersion = version;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,452 @@
|
||||
/**
|
||||
* ********************************************************************** 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;
|
||||
/**
|
||||
* Mustangproject's ZUGFeRD implementation ZUGFeRD importer Licensed under the APLv2
|
||||
*
|
||||
* @date 2014-07-07
|
||||
* @version 1.1.0
|
||||
* @author jstaerk
|
||||
*/
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Scanner;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
import javax.xml.xpath.XPath;
|
||||
import javax.xml.xpath.XPathExpressionException;
|
||||
import javax.xml.xpath.XPathFactory;
|
||||
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.apache.pdfbox.pdmodel.PDDocumentNameDictionary;
|
||||
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.w3c.dom.Document;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
public class ZUGFeRDImporter {
|
||||
|
||||
/**
|
||||
* if metadata has been found
|
||||
*/
|
||||
private boolean containsMeta = false;
|
||||
/**
|
||||
* 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 (InputStream bis = Files.newInputStream(Paths.get(pdfFilename), StandardOpenOption.READ)) {
|
||||
extractLowLevel(bis);
|
||||
} catch (IOException e) {
|
||||
Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e);
|
||||
throw new ZUGFeRDExportException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public ZUGFeRDImporter(InputStream pdfStream) {
|
||||
try {
|
||||
extractLowLevel(pdfStream);
|
||||
} catch (IOException e) {
|
||||
Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e);
|
||||
throw new ZUGFeRDExportException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Extracts a ZUGFeRD invoice from a PDF document represented by an input stream. Errors are reported via exception handling.
|
||||
*
|
||||
* @param pdfStream a inputstream of a pdf file
|
||||
*/
|
||||
private void extractLowLevel(InputStream pdfStream) throws IOException {
|
||||
try (PDDocument doc = PDDocument.load(pdfStream)) {
|
||||
// PDDocumentInformation info = doc.getDocumentInformation();
|
||||
PDDocumentNameDictionary names = new PDDocumentNameDictionary(doc.getDocumentCatalog());
|
||||
//start
|
||||
|
||||
if (doc.getDocumentCatalog() == null || doc.getDocumentCatalog().getMetadata() == null) {
|
||||
Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.INFO, "no-xmlpart");
|
||||
return;
|
||||
}
|
||||
|
||||
InputStream XMP = doc.getDocumentCatalog().getMetadata().exportXMPMetadata();
|
||||
xmpString = convertStreamToString(XMP);
|
||||
|
||||
PDEmbeddedFilesNameTreeNode etn = names.getEmbeddedFiles();
|
||||
if (etn == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String, PDComplexFileSpecification> efMap = etn.getNames();
|
||||
// String filePath = "/tmp/";
|
||||
|
||||
if (efMap != null) {
|
||||
extractFiles(efMap); // see
|
||||
// https://memorynotfound.com/apache-pdfbox-extract-embedded-file-pdf-document/
|
||||
} else {
|
||||
|
||||
List<PDNameTreeNode<PDComplexFileSpecification>> kids = etn.getKids();
|
||||
for (PDNameTreeNode<PDComplexFileSpecification> node : kids) {
|
||||
Map<String, PDComplexFileSpecification> namesL = node.getNames();
|
||||
extractFiles(namesL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void extractFiles(Map<String, PDComplexFileSpecification> names) throws IOException {
|
||||
for (String alias : names.keySet()) {
|
||||
|
||||
PDComplexFileSpecification fileSpec = names.get(alias);
|
||||
String filename = fileSpec.getFilename();
|
||||
/**
|
||||
* filenames for invoice data (ZUGFeRD v1 and v2, Factur-X)
|
||||
*/
|
||||
if ((filename.equals("ZUGFeRD-invoice.xml") || (filename.equals("zugferd-invoice.xml")) || filename.equals("factur-x.xml"))) { //$NON-NLS-1$
|
||||
containsMeta = true;
|
||||
|
||||
PDEmbeddedFile embeddedFile = fileSpec.getEmbeddedFile();
|
||||
// String embeddedFilename = filePath + filename;
|
||||
// File file = new File(filePath + filename);
|
||||
// System.out.println("Writing " + embeddedFilename);
|
||||
// ByteArrayOutputStream fileBytes=new
|
||||
// ByteArrayOutputStream();
|
||||
// FileOutputStream fos = new FileOutputStream(file);
|
||||
|
||||
setRawXML(embeddedFile.toByteArray());
|
||||
|
||||
// fos.write(embeddedFile.getByteArray());
|
||||
// fos.close();
|
||||
}
|
||||
if (filename.startsWith("additional_data")) {
|
||||
PDEmbeddedFile embeddedFile = fileSpec.getEmbeddedFile();
|
||||
additionalXMLs.put(filename, embeddedFile.toByteArray());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private Document getDocument() {
|
||||
return document;
|
||||
}
|
||||
|
||||
|
||||
private void setDocument() throws ParserConfigurationException, IOException, SAXException {
|
||||
DocumentBuilderFactory xmlFact = DocumentBuilderFactory.newInstance();
|
||||
xmlFact.setNamespaceAware(false);
|
||||
DocumentBuilder builder = xmlFact.newDocumentBuilder();
|
||||
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 if can not be read from is
|
||||
* @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) {
|
||||
if (!containsMeta) {
|
||||
throw new ZUGFeRDExportException("No suitable data/ZUGFeRD file could be found.");
|
||||
}
|
||||
String result;
|
||||
try {
|
||||
Document document = getDocument();
|
||||
XPathFactory xpathFact = XPathFactory.newInstance();
|
||||
XPath xpath = xpathFact.newXPath();
|
||||
result = xpath.evaluate(xpathStr, document);
|
||||
} catch (XPathExpressionException e) {
|
||||
Logger.getLogger(ZUGFeRDImporter.class.getName()).log(Level.SEVERE, null, e);
|
||||
throw new ZUGFeRDExportException(e);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the reference (purpose) the sender specified for this invoice
|
||||
*/
|
||||
public String getForeignReference() {
|
||||
String result = extractString("//ApplicableHeaderTradeSettlement/PaymentReference");
|
||||
if (result == null || result.isEmpty()) {
|
||||
result = extractString("//ApplicableSupplyChainTradeSettlement/PaymentReference");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the document code
|
||||
*/
|
||||
public String getDocumentCode() {
|
||||
return extractString("//HeaderExchangedDocument/TypeCode");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @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
|
||||
*/
|
||||
public String getBIC() {
|
||||
return extractString("//PayeeSpecifiedCreditorFinancialInstitution/BICID");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the sender's bank name
|
||||
*/
|
||||
public String getBankName() {
|
||||
return extractString("//PayeeSpecifiedCreditorFinancialInstitution/Name");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the sender's account IBAN code
|
||||
*/
|
||||
public String getIBAN() {
|
||||
return extractString("//PayeePartyCreditorFinancialAccount/IBANID");
|
||||
}
|
||||
|
||||
|
||||
public String getHolder() {
|
||||
return extractString("//SellerTradeParty/Name");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return the total payable amount
|
||||
*/
|
||||
public String getAmount() {
|
||||
String result = extractString("//SpecifiedTradeSettlementHeaderMonetarySummation/DuePayableAmount");
|
||||
if (result == null || result.isEmpty()) {
|
||||
result = extractString("//SpecifiedTradeSettlementMonetarySummation/GrandTotalAmount");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return when the payment is due
|
||||
*/
|
||||
public String getDueDate() {
|
||||
return extractString("//SpecifiedTradePaymentTerms/DueDateDateTime/DateTimeString");
|
||||
}
|
||||
|
||||
|
||||
public HashMap<String, byte[]> getAdditionalData() {
|
||||
return additionalXMLs;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* get xmp metadata of the PDF, null if not available
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public String getXMP() {
|
||||
return xmpString;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return if export found parseable ZUGFeRD data
|
||||
*/
|
||||
public boolean containsMeta() {
|
||||
return containsMeta;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param meta raw XML to be set
|
||||
* @throws IOException if raw can not be set
|
||||
*/
|
||||
public void setMeta(String meta) throws IOException {
|
||||
setRawXML(meta.getBytes());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return raw XML of the invoice
|
||||
*/
|
||||
public String getMeta() {
|
||||
if (rawXML == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return new String(rawXML);
|
||||
}
|
||||
|
||||
|
||||
public int getVersion() throws Exception {
|
||||
if (!containsMeta) {
|
||||
throw new Exception("Not yet parsed");
|
||||
}
|
||||
if (getUTF8().contains("<rsm:CrossIndustryDocument")) {
|
||||
return 1;
|
||||
} else if (getUTF8().contains("<rsm:CrossIndustryInvoice")) {
|
||||
return 2;
|
||||
}
|
||||
throw new Exception("ZUGFeRD version could not be determined");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return return UTF8 XML (without BOM) of the invoice
|
||||
*/
|
||||
public String getUTF8() {
|
||||
if (rawXML == null) {
|
||||
return null;
|
||||
}
|
||||
if (rawXML.length < 3) {
|
||||
return new String(rawXML);
|
||||
}
|
||||
|
||||
|
||||
byte[] bomlessData;
|
||||
|
||||
if ((rawXML[0] == (byte) 0xEF)
|
||||
&& (rawXML[1] == (byte) 0xBB)
|
||||
&& (rawXML[2] == (byte) 0xBF)) {
|
||||
// I don't like BOMs, lets remove it
|
||||
bomlessData = new byte[rawXML.length - 3];
|
||||
System.arraycopy(rawXML, 3, bomlessData, 0,
|
||||
rawXML.length - 3);
|
||||
} else {
|
||||
bomlessData = rawXML;
|
||||
}
|
||||
|
||||
return new String(bomlessData);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the raw XML data as extracted from the ZUGFeRD PDF file.
|
||||
*
|
||||
* @return the raw ZUGFeRD XML data
|
||||
*/
|
||||
public byte[] getRawXML() {
|
||||
return rawXML;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* will return true if the metadata (just extract-ed or set with setMeta) contains ZUGFeRD XML
|
||||
*
|
||||
* @return true if the invoice contains ZUGFeRD XML
|
||||
*/
|
||||
public boolean canParse() {
|
||||
|
||||
// SpecifiedExchangedDocumentContext is in the schema, so a relatively good
|
||||
// indication if zugferd is present - better than just invoice
|
||||
String meta = getMeta();
|
||||
return (meta != null) && (meta.length() > 0) && ((meta.contains("SpecifiedExchangedDocumentContext") //$NON-NLS-1$
|
||||
/* ZF1 */ || meta.contains("ExchangedDocumentContext") /* ZF2 */));
|
||||
}
|
||||
|
||||
|
||||
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, "UTF-8").useDelimiter("\\A");
|
||||
return s.hasNext() ? s.next() : "";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/** **********************************************************************
|
||||
*
|
||||
* Copyright 2019 ak on 09.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 class ZUGFeRDImporterException extends RuntimeException {
|
||||
|
||||
}
|
||||
@@ -0,0 +1,101 @@
|
||||
/** **********************************************************************
|
||||
*
|
||||
* 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.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class ZUGFeRDMigrator {
|
||||
|
||||
static final ClassLoader CLASS_LOADER = ZUGFeRDMigrator.class.getClassLoader();
|
||||
private static final String RESOURCE_PATH = ""; //$NON-NLS-1$
|
||||
private static final Logger LOG = Logger.getLogger(ZUGFeRDMigrator.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 mXsltTemplate = null;
|
||||
|
||||
public ZUGFeRDMigrator() {
|
||||
mFactory = new net.sf.saxon.TransformerFactoryImpl();
|
||||
//fact = TransformerFactory.newInstance();
|
||||
mFactory.setURIResolver(new ClasspathResourceURIResolver());
|
||||
try {
|
||||
mXsltTemplate = mFactory.newTemplates(new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "COMFORTtoEN16931.xsl")));
|
||||
} catch (TransformerConfigurationException ex) {
|
||||
LOG.log(Level.SEVERE, null, ex);
|
||||
}
|
||||
}
|
||||
|
||||
public String migrateFromV1ToV2(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
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
public void applySchematronXsl(final InputStream xmlFile,
|
||||
final OutputStream EN16931Outstream) throws TransformerException {
|
||||
Transformer transformer = mXsltTemplate.newTransformer();
|
||||
transformer.transform(new StreamSource(xmlFile), new StreamResult(EN16931Outstream));
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/** **********************************************************************
|
||||
*
|
||||
* 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.model;
|
||||
|
||||
public class DateTimeTypeConstants {
|
||||
public static final String DATE = "102";
|
||||
public static final String MONTH = "610";
|
||||
public static final String WEEK = "616";
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/** **********************************************************************
|
||||
*
|
||||
* 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.model;
|
||||
|
||||
public class DocumentCodeTypeConstants {
|
||||
public static final String INVOICE = "380";
|
||||
public static final String DEBITNOTE = "84";
|
||||
public static final String CREDITNOTE = "389";
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/** **********************************************************************
|
||||
*
|
||||
* 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.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";
|
||||
}
|
||||
@@ -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.model;
|
||||
|
||||
public class NoteTypeConstants {
|
||||
public static final String GENERAL = "";
|
||||
public static final String REGULARINFO = "REG";
|
||||
public static final String PRICECONDITION = "AAK";
|
||||
public static final String CONDITIONS = "AAJ";
|
||||
public static final String PAYMENTINFO = "PMT";
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/** **********************************************************************
|
||||
*
|
||||
* 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.model;
|
||||
|
||||
public class PaymentMeansCodeTypeConstants {
|
||||
public static final String BANKACCOUNT = "42";
|
||||
public static final String NOTSPECIFIED = "1";
|
||||
public static final String AUTOMATICCLEARING = "3";
|
||||
public static final String CASH = "10";
|
||||
public static final String CHECK = "20";
|
||||
public static final String DEBITADVICE = "31";
|
||||
public static final String CREDITCARD = "48";
|
||||
public static final String DEBIT = "49";
|
||||
public static final String COMPENSATION = "97";
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/** **********************************************************************
|
||||
*
|
||||
* 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.model;
|
||||
|
||||
public class QuantityTypeConstants {
|
||||
public static final String PIECE = "C62";
|
||||
public static final String DAY = "DAY";
|
||||
public static final String HECTARE = "HAR";
|
||||
public static final String HOUR = "HUR";
|
||||
public static final String KILOGRAM = "KGM";
|
||||
public static final String KILOMETER = "KTM";
|
||||
public static final String KILOWATTHOUR = "KWH";
|
||||
public static final String FIXEDRATE = "LS";
|
||||
public static final String LITRE = "LTR";
|
||||
public static final String MINUTE = "MIN";
|
||||
public static final String SQUAREMILLIMETER = "MMK";
|
||||
public static final String MILLIMETER = "MMT";
|
||||
public static final String SQUAREMETER = "MTK";
|
||||
public static final String CUBICMETER = "MTQ";
|
||||
public static final String METER = "MTR";
|
||||
public static final String PRODUCTCOUNT = "NAR";
|
||||
public static final String PRODUCTPAIR = "NPR";
|
||||
public static final String PERCENT = "P1";
|
||||
public static final String SET = "SET";
|
||||
public static final String TON = "TNE";
|
||||
public static final String WEEK = "WEE";
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/** **********************************************************************
|
||||
*
|
||||
* 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.model;
|
||||
|
||||
public class TaxCategoryCodeTypeConstants {
|
||||
public static final String STANDARDRATE = "S";
|
||||
public static final String REVERSECHARGE = "AE";
|
||||
public static final String TAXEXEMPT = "E";
|
||||
public static final String ZEROTAXPRODUCTS = "Z";
|
||||
public static final String UNTAXEDSERVICE = "O";
|
||||
public static final String INTRACOMMUNITY = "IC";
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/** **********************************************************************
|
||||
*
|
||||
* 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.model;
|
||||
|
||||
public class TaxRegistrationTypeConstants {
|
||||
public static final String USTID = "VA";
|
||||
public static final String TAXID = "FC";
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/** **********************************************************************
|
||||
*
|
||||
* 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.model;
|
||||
|
||||
public class TaxTypeCodeTypeConstants {
|
||||
public static final String SALESTAX = "VAT";
|
||||
public static final String INSURANCETAX = "ZF_INSURANCE_TAX";
|
||||
public static final String OLDPART = "AAJ";
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/** **********************************************************************
|
||||
*
|
||||
* 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.model;
|
||||
|
||||
import com.sun.xml.bind.marshaller.NamespacePrefixMapper;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class ZFNamespacePrefixMapper extends NamespacePrefixMapper {
|
||||
|
||||
private Map<String, String> namespaceMap = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Create mappings.
|
||||
*/
|
||||
public ZFNamespacePrefixMapper() {
|
||||
|
||||
namespaceMap.put("urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:12", "ram");
|
||||
namespaceMap.put("urn:un:unece:uncefact:data:standard:UnqualifiedDataType:15", "udt");
|
||||
namespaceMap.put("urn:ferd:CrossIndustryDocument:invoice:1p0", "rsm");
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* Returning null when not found based on spec.
|
||||
* @see com.sun.xml.bind.marshaller.NamespacePrefixMapper#getPreferredPrefix(java.lang.String, java.lang.String, boolean)
|
||||
*/
|
||||
@Override
|
||||
public String getPreferredPrefix(String namespaceUri, String suggestion, boolean requirePrefix) {
|
||||
return namespaceMap.getOrDefault(namespaceUri, suggestion);
|
||||
}
|
||||
|
||||
}
|
||||
95
libraryBasic/src/main/java/org/mustangproject/toecount/FileChecker.java
Executable file
95
libraryBasic/src/main/java/org/mustangproject/toecount/FileChecker.java
Executable file
@@ -0,0 +1,95 @@
|
||||
/** **********************************************************************
|
||||
*
|
||||
* 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.toecount;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import org.mustangproject.ZUGFeRD.ZUGFeRDImporter;
|
||||
|
||||
public class FileChecker {
|
||||
String filename;
|
||||
StatRun thisRun;
|
||||
boolean isPDF = false;
|
||||
|
||||
public FileChecker(String filename, StatRun statistics) {
|
||||
this.filename = filename;
|
||||
thisRun = statistics;
|
||||
thisRun.incFileCount();
|
||||
String extension = "";
|
||||
if (!thisRun.shallIgnoreFileExt()) {
|
||||
int extIndex = filename.lastIndexOf(".");
|
||||
if (extIndex >= 0) {
|
||||
extension = filename.substring(extIndex).toLowerCase();
|
||||
isPDF = extension.equals(".pdf");// alternative check for PDF: File starts with %PDF-
|
||||
if (isPDF) {
|
||||
thisRun.incPDFCount();
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
thisRun.incPDFCount();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean checkForZUGFeRD() {
|
||||
if ((!isPDF) && (!thisRun.shallIgnoreFileExt())) {
|
||||
return false;
|
||||
}
|
||||
ZUGFeRDImporter zi = new ZUGFeRDImporter(filename);
|
||||
try {
|
||||
if (zi.canParse()) {
|
||||
thisRun.incZUGFeRDCount(zi.getVersion());
|
||||
thisRun.incTotal(new BigDecimal(zi.getAmount()));
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} catch (NullPointerException e) {
|
||||
// something really rare happened -- corrupted ZF?
|
||||
/***
|
||||
* e.g. Exception in thread "main" java.lang.NullPointerException
|
||||
at org.mustangproject.ZUGFeRD.ZUGFeRDImporter.extractLowLevel(ZUGFeRDImporter.java:90)
|
||||
at org.mustangproject.ZUGFeRD.ZUGFeRDImporter.extract(ZUGFeRDImporter.java:64)
|
||||
at toecount.FileChecker.checkForZUGFeRD(FileChecker.java:33)
|
||||
at toecount.Toecount.main(Toecount.java:111)
|
||||
*
|
||||
*/
|
||||
// Ignore nevertheless, most likely we're batch processing
|
||||
return false;
|
||||
} catch (Exception e2) {
|
||||
/**
|
||||
* probably thrown up from
|
||||
AM org.apache.pdfbox.pdfparser.PDFParser parse, most likely
|
||||
INFORMATION: Document is encrypted
|
||||
but also other internal PDF errors possible like
|
||||
..Okt 23, 2015 11:17:53 AM org.apache.pdfbox.pdfparser.XrefTrailerResolver setStartxref
|
||||
*/
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isPDF() {
|
||||
return isPDF;
|
||||
}
|
||||
|
||||
public String getOutputLine() {
|
||||
return thisRun.getOutputLine();
|
||||
}
|
||||
|
||||
}
|
||||
75
libraryBasic/src/main/java/org/mustangproject/toecount/FileTraverser.java
Executable file
75
libraryBasic/src/main/java/org/mustangproject/toecount/FileTraverser.java
Executable file
@@ -0,0 +1,75 @@
|
||||
/** **********************************************************************
|
||||
*
|
||||
* 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.toecount;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.FileVisitResult;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.SimpleFileVisitor;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
|
||||
import static java.nio.file.FileVisitResult.CONTINUE;
|
||||
|
||||
public class FileTraverser extends SimpleFileVisitor<Path> {
|
||||
|
||||
|
||||
private StatRun thisRun;
|
||||
|
||||
public FileTraverser(StatRun statistics) {
|
||||
this.thisRun = statistics;
|
||||
}
|
||||
|
||||
/**
|
||||
* check each file
|
||||
*/
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attr) {
|
||||
if (attr.isSymbolicLink()) {
|
||||
// Not yet handled
|
||||
} else if (attr.isRegularFile()) {
|
||||
String filename = file.toString();
|
||||
FileChecker fc = new FileChecker(filename, thisRun);
|
||||
fc.checkForZUGFeRD();
|
||||
System.out.print(fc.getOutputLine());
|
||||
|
||||
}
|
||||
return CONTINUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* for each directory
|
||||
*/
|
||||
@Override
|
||||
public FileVisitResult postVisitDirectory(Path dir, IOException exc) {
|
||||
// System.out.format("Directory: %s%n", dir);
|
||||
thisRun.incDirCount();
|
||||
return CONTINUE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* show errors like file permission stacktraces
|
||||
*/
|
||||
@Override
|
||||
public FileVisitResult visitFileFailed(Path file, IOException exc) {
|
||||
System.err.println(exc);
|
||||
return CONTINUE;
|
||||
}
|
||||
|
||||
}
|
||||
99
libraryBasic/src/main/java/org/mustangproject/toecount/StatRun.java
Executable file
99
libraryBasic/src/main/java/org/mustangproject/toecount/StatRun.java
Executable file
@@ -0,0 +1,99 @@
|
||||
/** **********************************************************************
|
||||
*
|
||||
* 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.toecount;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
public class StatRun {
|
||||
private int pdfCount = 0;
|
||||
private int horseCount = 0;
|
||||
private int fileCount = 0;
|
||||
private int dirCount = 0;
|
||||
private BigDecimal total = BigDecimal.ZERO;
|
||||
private boolean checkFileExt = true;
|
||||
|
||||
public void ignoreFileExtension() {
|
||||
checkFileExt = false;
|
||||
}
|
||||
|
||||
public boolean shallIgnoreFileExt() {
|
||||
return !checkFileExt;
|
||||
}
|
||||
|
||||
public void incFileCount() {
|
||||
fileCount++;
|
||||
}
|
||||
|
||||
public void incPDFCount() {
|
||||
pdfCount++;
|
||||
}
|
||||
|
||||
public void incZUGFeRDCount(int version) {
|
||||
horseCount++;
|
||||
}
|
||||
|
||||
public void incDirCount() {
|
||||
dirCount++;
|
||||
}
|
||||
|
||||
public int getFileCount() {
|
||||
return fileCount;
|
||||
}
|
||||
|
||||
public int getPDFCount() {
|
||||
return pdfCount;
|
||||
}
|
||||
|
||||
public int getZUGFeRDCount() {
|
||||
return horseCount;
|
||||
}
|
||||
|
||||
public int getDirCount() {
|
||||
return dirCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* returns final statistics
|
||||
*
|
||||
* @return english string with linefeeds detailling number of files, directories, number of pdfs and of zugferd files
|
||||
*/
|
||||
public String getSummaryLine() {
|
||||
|
||||
return "\r\n===================================================================\r\n" + String.format(
|
||||
"Files:\t%d\tDirs:\t%d\tPDF:\t%d\tZUGFeRD:\t%d\tTotal:\t%s\r\n",
|
||||
getFileCount(), getDirCount(), getPDFCount(), getZUGFeRDCount(), total.toString());
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* show that something is happening
|
||||
*
|
||||
* @return String, usually a dot
|
||||
*/
|
||||
public String getOutputLine() {
|
||||
return ".";
|
||||
}
|
||||
|
||||
public void incTotal(BigDecimal delta) {
|
||||
total=total.add(delta);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
621
libraryBasic/src/main/java/org/mustangproject/toecount/Toecount.java
Executable file
621
libraryBasic/src/main/java/org/mustangproject/toecount/Toecount.java
Executable file
@@ -0,0 +1,621 @@
|
||||
/** **********************************************************************
|
||||
*
|
||||
* 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.toecount;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import javax.xml.transform.TransformerException;
|
||||
|
||||
import org.mustangproject.ZUGFeRD.ZUGFeRDConformanceLevel;
|
||||
import org.mustangproject.ZUGFeRD.ZUGFeRDExporter;
|
||||
import org.mustangproject.ZUGFeRD.ZUGFeRDExporterFromA1Factory;
|
||||
import org.mustangproject.ZUGFeRD.ZUGFeRDImporter;
|
||||
import org.mustangproject.ZUGFeRD.ZUGFeRDMigrator;
|
||||
|
||||
/***
|
||||
* This is the command line interface to mustangproject
|
||||
*
|
||||
*/
|
||||
|
||||
import com.sanityinc.jargs.CmdLineParser;
|
||||
import com.sanityinc.jargs.CmdLineParser.Option;
|
||||
|
||||
public class Toecount {
|
||||
// build with: /opt/local/bin/mvn clean compile assembly:single
|
||||
private static void printUsage() {
|
||||
System.err.println(getUsage());
|
||||
}
|
||||
|
||||
private static String getUsage() {
|
||||
return "Usage: [-d,--directory] [-l,--listfromstdin] [-i,--ignorefileextension] | [-c,--combine] | [-e,--extract] | [-u,--upgrade] | [-a,--a3only] | [-h,--help] \r\n"
|
||||
+ "* Count operations\n" + " -d, --directory count ZUGFeRD files in directory to be scanned\n"
|
||||
+ " If it is a directory, it will recurse.\n"
|
||||
+ " -l, --listfromstdin count ZUGFeRD files from a list of linefeed separated files on runtime.\n"
|
||||
+ " It will start once a blank line has been entered.\n" + "\n"
|
||||
+ " Additional parameter for both count operations\n"
|
||||
+ " [-i, --ignorefileextension] Check for all files (*.*) instead of PDF files only (*.pdf)\n"
|
||||
+ "\n" + "* Merge operations\n" + " -e, --extract extract ZUGFeRD PDF to XML file\n"
|
||||
+ " Additional parameters (optional - user will be prompted if not defined)\n"
|
||||
+ " [--source <filename>]: set input PDF file\n"
|
||||
+ " [--out <filename>]: set output XML file\n"
|
||||
+ " -u, --upgrade upgrade ZUGFeRD XML to ZUGFeRD 2 XML\n"
|
||||
+ " Additional parameters (optional - user will be prompted if not defined)\n"
|
||||
+ " [--source <filename>]: set input XML ZUGFeRD 1 file\n"
|
||||
+ " [--out <filename>]: set output XML ZUGFeRD 2 file\n"
|
||||
+ " -a, --a3only upgrade from PDF/A1 to A3 only (no ZUGFeRD data attached)\n"
|
||||
+ " Additional parameters (optional - user will be prompted if not defined)\n"
|
||||
+ " [--source <filename>]: set input PDF file\n"
|
||||
+ " [--out <filename>]: set output PDF file\n"
|
||||
+ " -c, --combine combine XML and PDF file to ZUGFeRD PDF file\n"
|
||||
+ " Additional parameters (optional - user will be prompted if not defined)\n"
|
||||
+ " [--source <filename>]: set input PDF file\n"
|
||||
+ " [--source-xml <filename>]: set input XML file\n"
|
||||
+ " [--out <filename>]: set output PDF file\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 ";
|
||||
}
|
||||
|
||||
private static void printHelp() {
|
||||
System.out.println("Mustangproject.org " + org.mustangproject.ZUGFeRD.Version.VERSION + " \r\n"
|
||||
+ "A Apache Public License library and command line tool for statistics on PDF invoices with\r\n"
|
||||
+ "ZUGFeRD Metadata (http://www.zugferd.org)\r\n" + "\r\n" + getUsage() + "\r\n"
|
||||
+ "* Count operations\r\n" + "\t-d, --directory\tcount ZUGFeRD files in directory to be scanned\r\n"
|
||||
+ "\t\tIf it is a directory, it will recurse.\r\n"
|
||||
+ "\t-l, --listfromstdin\tcount ZUGFeRD files from a list of linefeed separated files on runtime.\r\n"
|
||||
+ "\t\tIt will start once a blank line has been entered.\r\n" + "\r\n"
|
||||
+ "\tAdditional parameter for both count operations\r\n"
|
||||
+ "\t[-i, --ignorefileextension]\tCheck for all files (*.*) instead of PDF files only (*.pdf)\r\n"
|
||||
+ "\r\n" + "* Merge operations\r\n" + "\t-e, --extract\textract ZUGFeRD PDF to XML file\r\n"
|
||||
+ "\t\tAdditional parameters (optional - user will be prompted if not defined)\r\n"
|
||||
+ "\t\t[--source <filename>]: set input PDF file\r\n"
|
||||
+ "\t\t[--out <filename>]: set output XML file\r\n"
|
||||
+ "\t-u, --upgrade\tupgrade ZUGFeRD XML to ZUGFeRD 2 XML\r\n"
|
||||
+ "\t\tAdditional parameters (optional - user will be prompted if not defined)\r\n"
|
||||
+ "\t\t[--source <filename>]: set input XML ZUGFeRD 1 file\r\n"
|
||||
+ "\t\t[--out <filename>]: set output XML ZUGFeRD 2 file\r\n"
|
||||
+ "\t-a, --a3only\tupgrade from PDF/A1 to A3 only (no ZUGFeRD data attached) \r\n"
|
||||
+ "\t\tAdditional parameters (optional - user will be prompted if not defined)\r\n"
|
||||
+ "\t\t[--source <filename>]: set input PDF file\r\n"
|
||||
+ "\t\t[--out <filename>]: set output PDF file\r\n"
|
||||
+ "\t-c, --combine\tcombine XML and PDF file to ZUGFeRD PDF file\r\n"
|
||||
+ "\t\tAdditional parameters (optional - user will be prompted if not defined)\r\n"
|
||||
+ "\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[--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");
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
* @return the user answer conforming to pattern
|
||||
* @throws Exception
|
||||
* if pattern not compielable or IOexception on input
|
||||
*/
|
||||
protected static String getStringFromUser(String prompt, String defaultValue, String pattern) throws Exception {
|
||||
String input = "";
|
||||
if (!defaultValue.matches(pattern)) {
|
||||
throw new Exception("Default value must match pattern");
|
||||
}
|
||||
boolean firstInput = true;
|
||||
do {
|
||||
// for a more sophisticated dialogue maybe https://github.com/mabe02/lanterna/
|
||||
// could be taken into account
|
||||
System.out.print(prompt + " (default: " + defaultValue + ")");
|
||||
if (!firstInput) {
|
||||
System.out.print("\n(allowed pattern: " + pattern + ")");
|
||||
|
||||
}
|
||||
System.out.print(":");
|
||||
BufferedReader buffer = new BufferedReader(new InputStreamReader(System.in));
|
||||
try {
|
||||
input = buffer.readLine();
|
||||
} catch (IOException e) {
|
||||
Logger.getLogger(Toecount.class.getName()).log(Level.SEVERE, null, e);
|
||||
|
||||
}
|
||||
|
||||
if (input.isEmpty()) {
|
||||
// pressed return without entering anything
|
||||
input = defaultValue;
|
||||
}
|
||||
|
||||
firstInput = false;
|
||||
} while (!input.matches(pattern));
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prompts the user for a input or output filename
|
||||
*
|
||||
* @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 fileExistenceOK = false;
|
||||
String selectedName = "";
|
||||
do {
|
||||
// for a more sophisticated dialogue maybe https://github.com/mabe02/lanterna/
|
||||
// could be taken into account
|
||||
System.out.print(prompt + " (default: " + defaultFilename + "):");
|
||||
BufferedReader buffer = new BufferedReader(new InputStreamReader(System.in));
|
||||
try {
|
||||
selectedName = buffer.readLine();
|
||||
} catch (IOException e) {
|
||||
Logger.getLogger(Toecount.class.getName()).log(Level.SEVERE, null, e);
|
||||
|
||||
}
|
||||
|
||||
if (selectedName.isEmpty()) {
|
||||
// pressed return without entering anything
|
||||
selectedName = defaultFilename;
|
||||
}
|
||||
|
||||
// error cases
|
||||
if (!selectedName.toLowerCase().endsWith(expectedExtension.toLowerCase())) {
|
||||
System.err.println("Expected " + expectedExtension
|
||||
+ " extension, this may corrupt your file. Do you still want to continue?(Y|N)");
|
||||
String selectedAnswer = "";
|
||||
try {
|
||||
selectedAnswer = buffer.readLine();
|
||||
} catch (IOException e) {
|
||||
Logger.getLogger(Toecount.class.getName()).log(Level.SEVERE, null, e);
|
||||
}
|
||||
if (!selectedAnswer.equals("Y") && !selectedAnswer.equals("y")) {
|
||||
System.err.println("Aborted by user");
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
} else if (ensureFileExists) {
|
||||
if (fileExists(selectedName)) {
|
||||
fileExistenceOK = true;
|
||||
} else {
|
||||
System.out.println("File does not exist, try again or CTRL+C to cancel");
|
||||
// discard the input, a scanner.reset is not sufficient
|
||||
fileExistenceOK = false;
|
||||
}
|
||||
} else {
|
||||
fileExistenceOK = true;
|
||||
|
||||
if (ensureFileNotExists) {
|
||||
if (fileExists(selectedName)) {
|
||||
fileExistenceOK = false;
|
||||
System.out.println("Output file already exists, try again or CTRL+C to cancel");
|
||||
// discard the input, a scanner.reset is not sufficient
|
||||
}
|
||||
} else {
|
||||
fileExistenceOK = true;
|
||||
}
|
||||
}
|
||||
|
||||
} while (!fileExistenceOK);
|
||||
|
||||
return selectedName;
|
||||
}
|
||||
|
||||
// /opt/local/bin/mvn clean compile assembly:single
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
|
||||
CmdLineParser parser = new CmdLineParser();
|
||||
|
||||
// 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
|
||||
Option<String> sourceOption = parser.addStringOption("source");
|
||||
// --out: output file
|
||||
Option<String> outOption = parser.addStringOption("out");
|
||||
|
||||
// Command: Extract XML
|
||||
// --extract
|
||||
// (--source: input PDF file)
|
||||
// (--out: output XML file)
|
||||
Option<Boolean> extractOption = parser.addBooleanOption('e', "extract");
|
||||
|
||||
// Command: Migrating ZUGFeRD 1 to 2
|
||||
// --upgrade
|
||||
// (--source: input XML ZUGFeRD 1 file)
|
||||
// (--out: output XML ZUGFeRD 2 file)
|
||||
Option<Boolean> upgradeOption = parser.addBooleanOption('u', "upgrade");
|
||||
|
||||
// Command: Convert PDF/A-1 to PDF/A-3
|
||||
// --a3only
|
||||
// (--source: input PDF file)
|
||||
// (--out: output PDF file)
|
||||
Option<Boolean> a3onlyOption = parser.addBooleanOption('a', "a3only");
|
||||
|
||||
// Command: Combining PDF and XML
|
||||
// --combine
|
||||
// (--source: input PDF file)
|
||||
// (--source-xml: input XML file)
|
||||
// (--out: output PDF file)
|
||||
// (--version: ZUGFeRD version)
|
||||
// (--profile: ZUGFeRD profile)
|
||||
Option<Boolean> combineOption = parser.addBooleanOption('c', "combine");
|
||||
Option<String> sourceXmlOption = parser.addStringOption("source-xml");
|
||||
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
|
||||
// (--ignorefileextension)
|
||||
Option<String> dirnameOption = parser.addStringOption('d', "directory");
|
||||
Option<Boolean> ignoreFileExtOption = parser.addBooleanOption('i', "ignorefileextension");
|
||||
|
||||
// Command: Show metrics from list from stdin
|
||||
// --listfromstdin
|
||||
Option<Boolean> filesFromStdInOption = parser.addBooleanOption('l', "listfromstdin");
|
||||
|
||||
try {
|
||||
parser.parse(args);
|
||||
} catch (CmdLineParser.OptionException e) {
|
||||
System.err.println(e.getMessage());
|
||||
printUsage();
|
||||
System.exit(2);
|
||||
}
|
||||
|
||||
// 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) || ((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) || ((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);
|
||||
|
||||
if (helpRequested) {
|
||||
printHelp();
|
||||
} else if (((directoryName != null) && (directoryName.length() > 0)) || filesFromStdIn.booleanValue()) {
|
||||
performMetrics(directoryName, filesFromStdIn, ignoreFileExt);
|
||||
} else if (combineRequested) {
|
||||
performCombine(sourceName, sourceXMLName, outName, format, zugferdVersion, zugferdProfile);
|
||||
} else if (extractRequested) {
|
||||
performExtract(sourceName, outName);
|
||||
} else if (a3only) {
|
||||
performConvert(sourceName, outName);
|
||||
} else if (upgradeRequested) {
|
||||
performUpgrade(sourceName, outName);
|
||||
} else {
|
||||
// no argument or argument unknown
|
||||
printUsage();
|
||||
System.exit(2);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
|
||||
Logger.getLogger(Toecount.class.getName()).log(Level.SEVERE, null, e);
|
||||
System.exit(-1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void performUpgrade(String xmlName, String outName) throws IOException, TransformerException {
|
||||
|
||||
// Get params from user if not already defined
|
||||
if (xmlName == null) {
|
||||
xmlName = getFilenameFromUser("ZUGFeRD 1.0 XML source", "ZUGFeRD-invoice.xml", "xml", true, false);
|
||||
} else {
|
||||
System.out.println("ZUGFeRD 1.0 XML source set to " + xmlName);
|
||||
}
|
||||
if (outName == null) {
|
||||
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);
|
||||
}
|
||||
|
||||
// Verify params
|
||||
ensureFileExists(xmlName);
|
||||
ensureFileNotExists(outName);
|
||||
|
||||
// All params are good! continue...
|
||||
ZUGFeRDMigrator zmi = new ZUGFeRDMigrator();
|
||||
String xml = null;
|
||||
xml = zmi.migrateFromV1ToV2(xmlName);
|
||||
Files.write(Paths.get(outName), xml.getBytes());
|
||||
System.out.println("Written to " + outName);
|
||||
/*
|
||||
* } catch (FileNotFoundException ex) {
|
||||
* Logger.getLogger(Toecount.class.getName()).log(Level.SEVERE, null, ex);
|
||||
*/
|
||||
}
|
||||
|
||||
private static void performConvert(String pdfName, String outName) throws IOException {
|
||||
/*
|
||||
* ZUGFeRDExporter ze= new ZUGFeRDExporterFromA1Factory()
|
||||
* .setProducer("toecount") .setCreator(System.getProperty("user.name"))
|
||||
* .loadFromPDFA1("invoice.pdf");
|
||||
*/
|
||||
// Get params from user if not already defined
|
||||
if (pdfName == null) {
|
||||
pdfName = getFilenameFromUser("Source PDF", "invoice.pdf", "pdf", true, false);
|
||||
} else {
|
||||
System.out.println("Source PDF set to " + pdfName);
|
||||
}
|
||||
if (outName == null) {
|
||||
outName = getFilenameFromUser("Target PDF", "invoice.a3.pdf", "pdf", false, true);
|
||||
} else {
|
||||
System.out.println("Target PDF set to " + outName);
|
||||
}
|
||||
|
||||
// Verify params
|
||||
ensureFileExists(pdfName);
|
||||
ensureFileNotExists(outName);
|
||||
|
||||
// All params are good! continue...
|
||||
ZUGFeRDExporter ze = new ZUGFeRDExporterFromA1Factory().setAttachZUGFeRDHeaders(false).load(pdfName);
|
||||
|
||||
ze.export(outName);
|
||||
System.out.println("Written to " + outName);
|
||||
}
|
||||
|
||||
private static void performExtract(String pdfName, String xmlName) throws IOException {
|
||||
// Get params from user if not already defined
|
||||
if (pdfName == null) {
|
||||
pdfName = getFilenameFromUser("Source PDF", "invoice.pdf", "pdf", true, false);
|
||||
} else {
|
||||
System.out.println("Source PDF set to " + pdfName);
|
||||
}
|
||||
if (xmlName == null) {
|
||||
xmlName = getFilenameFromUser("ZUGFeRD XML", "ZUGFeRD-invoice.xml", "xml", false, true);
|
||||
} else {
|
||||
System.out.println("ZUGFeRD XML set to " + pdfName);
|
||||
}
|
||||
|
||||
// Verify params
|
||||
ensureFileExists(pdfName);
|
||||
ensureFileNotExists(xmlName);
|
||||
|
||||
// All params are good! continue...
|
||||
ZUGFeRDImporter zi = new ZUGFeRDImporter(pdfName);
|
||||
byte[] XMLContent = zi.getRawXML();
|
||||
if (XMLContent == null) {
|
||||
System.err.println("No ZUGFeRD XML found in PDF file");
|
||||
|
||||
} else {
|
||||
Files.write(Paths.get(xmlName), XMLContent);
|
||||
System.out.println("Written to " + xmlName);
|
||||
}
|
||||
}
|
||||
|
||||
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 = ZUGFeRDExporter.DefaultZUGFeRDVersion;
|
||||
ZUGFeRDConformanceLevel zfConformanceLevelProfile = ZUGFeRDConformanceLevel.EXTENDED;
|
||||
|
||||
if (pdfName == null) {
|
||||
pdfName = getFilenameFromUser("Source PDF", "invoice.pdf", "pdf", true, false);
|
||||
} else {
|
||||
System.out.println("Source PDF set to " + pdfName);
|
||||
}
|
||||
|
||||
if (xmlName == null) {
|
||||
xmlName = getFilenameFromUser("ZUGFeRD XML", "ZUGFeRD-invoice.xml", "xml", true, false);
|
||||
} else {
|
||||
System.out.println("ZUGFeRD XML set to " + xmlName);
|
||||
}
|
||||
|
||||
if (outName == null) {
|
||||
outName = getFilenameFromUser("Ouput PDF", "invoice.ZUGFeRD.pdf", "pdf", false, true);
|
||||
} else {
|
||||
System.out.println("Ouput PDF set to " + outName);
|
||||
}
|
||||
|
||||
if (format == null) {
|
||||
try {
|
||||
format = getStringFromUser("Format (fx=Factur-X, zf=ZUGFeRD,)", "zf", "fx|zf");
|
||||
} catch (Exception e) {
|
||||
Logger.getLogger(Toecount.class.getName()).log(Level.SEVERE, null, e);
|
||||
}
|
||||
} else {
|
||||
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 (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(
|
||||
"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) {
|
||||
Logger.getLogger(Toecount.class.getName()).log(Level.SEVERE, null, e);
|
||||
|
||||
}
|
||||
} else {
|
||||
System.out.println("Profile set to " + zfProfile);
|
||||
}
|
||||
zfProfile = zfProfile.toLowerCase();
|
||||
|
||||
// Verify params
|
||||
ensureFileExists(pdfName);
|
||||
ensureFileExists(xmlName);
|
||||
ensureFileNotExists(outName);
|
||||
|
||||
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")) {
|
||||
zfConformanceLevelProfile = ZUGFeRDConformanceLevel.COMFORT;
|
||||
} else if (zfProfile.equals("e")) {
|
||||
zfConformanceLevelProfile = ZUGFeRDConformanceLevel.EXTENDED;
|
||||
} else {
|
||||
throw new Exception(String.format("Unknown ZUGFeRD profile '%s'", zfProfile));
|
||||
}
|
||||
} else if (((format.equals("zf")) && (zfIntVersion == 2)) || (format.equals("fx"))) {
|
||||
if (zfProfile.equals("m")) {
|
||||
zfConformanceLevelProfile = ZUGFeRDConformanceLevel.MINIMUM;
|
||||
} else if (zfProfile.equals("w")) {
|
||||
zfConformanceLevelProfile = ZUGFeRDConformanceLevel.BASICWL;
|
||||
} else if (zfProfile.equals("b")) {
|
||||
zfConformanceLevelProfile = ZUGFeRDConformanceLevel.BASIC;
|
||||
} else if (zfProfile.equals("c")) {
|
||||
zfConformanceLevelProfile = ZUGFeRDConformanceLevel.CIUS;
|
||||
} else if (zfProfile.equals("e")) {
|
||||
zfConformanceLevelProfile = ZUGFeRDConformanceLevel.EN16931;
|
||||
} else if (zfProfile.equals("x")) {
|
||||
zfConformanceLevelProfile = ZUGFeRDConformanceLevel.EXTENDED;
|
||||
} else {
|
||||
throw new Exception(String.format("Unknown ZUGFeRD profile '%s'", zfProfile));
|
||||
}
|
||||
} else {
|
||||
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);
|
||||
|
||||
if (format.equals("fx")) {
|
||||
ze.setFacturX();
|
||||
}
|
||||
|
||||
ze.setZUGFeRDXMLData(Files.readAllBytes(Paths.get(xmlName)));
|
||||
|
||||
ze.export(outName);
|
||||
|
||||
System.out.println("Written to " + outName);
|
||||
|
||||
} catch (IOException e) {
|
||||
Logger.getLogger(Toecount.class.getName()).log(Level.SEVERE, null, e);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private static void performMetrics(String directoryName, Boolean filesFromStdIn, Boolean ignoreFileExt)
|
||||
throws IOException {
|
||||
|
||||
StatRun sr = new StatRun();
|
||||
if (ignoreFileExt) {
|
||||
sr.ignoreFileExtension();
|
||||
}
|
||||
if (directoryName != null) {
|
||||
Path startingDir = Paths.get(directoryName);
|
||||
|
||||
if (Files.isRegularFile(startingDir)) {
|
||||
String filename = startingDir.toString();
|
||||
FileChecker fc = new FileChecker(filename, sr);
|
||||
|
||||
fc.checkForZUGFeRD();
|
||||
System.out.print(fc.getOutputLine());
|
||||
|
||||
} else if (Files.isDirectory(startingDir)) {
|
||||
FileTraverser pf = new FileTraverser(sr);
|
||||
Files.walkFileTree(startingDir, pf);
|
||||
}
|
||||
}
|
||||
|
||||
if (filesFromStdIn) {
|
||||
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
|
||||
String s;
|
||||
while ((s = in.readLine()) != null && s.length() != 0) {
|
||||
FileChecker fc = new FileChecker(s, sr);
|
||||
|
||||
fc.checkForZUGFeRD();
|
||||
System.out.print(fc.getOutputLine());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
System.out.println(sr.getSummaryLine());
|
||||
}
|
||||
|
||||
private static void ensureFileExists(String fileName) throws IOException {
|
||||
if (!fileExists(fileName)) {
|
||||
throw new IOException(String.format("File %s does not exists", fileName));
|
||||
}
|
||||
}
|
||||
|
||||
private static void ensureFileNotExists(String fileName) throws IOException {
|
||||
if (fileExists(fileName)) {
|
||||
throw new IOException(String.format("File %s does not exists", fileName));
|
||||
}
|
||||
}
|
||||
|
||||
private static Boolean fileExists(String fileName) {
|
||||
if (fileName == null)
|
||||
return false;
|
||||
File f = new File(fileName);
|
||||
return f.exists();
|
||||
}
|
||||
|
||||
}
|
||||
277
libraryBasic/src/main/resources/COMFORTtoEN16931.xsl
Normal file
277
libraryBasic/src/main/resources/COMFORTtoEN16931.xsl
Normal file
@@ -0,0 +1,277 @@
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<xsl:stylesheet version="1.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100"
|
||||
|
||||
xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100"
|
||||
xmlns:qdt="urn:un:unece:uncefact:data:standard:QualifiedDataType:100"
|
||||
xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100"
|
||||
>
|
||||
<!-- use saxon6 java -cp saxon.jar com.icl.saxon.StyleSheet -o target.xml
|
||||
ZUGFeRD-invoice.xml v1to2.xsl see also http://www.lenzconsulting.com/namespaces-in-xslt/
|
||||
extension-element-prefixes="exsl str datetime uw" -->
|
||||
<xsl:output encoding="UTF-8" indent="yes" method="xml" />
|
||||
|
||||
<!-- copy elements and all attributes but remove namespaces start
|
||||
Will otherwise add sth like xmlns:rsm="urn:ferd:CrossIndustryDocument:invoice:1p0" on elements.
|
||||
src: https://stackoverflow.com/questions/12465002/remove-namespace-declaration-from-xslt-stylesheet-with-xslt
|
||||
This only seems to work in saxon, in xalan namespaces are still created-->
|
||||
<!-- Copy elements -->
|
||||
<xsl:template match="*" priority="-1">
|
||||
<xsl:element name="{name()}">
|
||||
<xsl:apply-templates select="node()|@*"/>
|
||||
</xsl:element>
|
||||
</xsl:template>
|
||||
|
||||
<!-- Copy all other nodes -->
|
||||
<xsl:template match="node()|@*" priority="-2">
|
||||
<xsl:copy />
|
||||
</xsl:template>
|
||||
<!-- copy elements and all attributes but remove namespaces end -->
|
||||
|
||||
<xsl:template match="//*[local-name() = 'CrossIndustryDocument']">
|
||||
<!-- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100"
|
||||
xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100"
|
||||
xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100" -->
|
||||
<rsm:CrossIndustryInvoice xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100"
|
||||
xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100"
|
||||
xmlns:qdt="urn:un:unece:uncefact:data:Standard:QualifiedDataType:100"
|
||||
xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100">
|
||||
<xsl:text disable-output-escaping="yes"><!--</xsl:text>
|
||||
Migrated by Mustangproject XSLT
|
||||
<xsl:text disable-output-escaping="yes">--></xsl:text>
|
||||
|
||||
<xsl:apply-templates select="*" />
|
||||
</rsm:CrossIndustryInvoice>
|
||||
</xsl:template>
|
||||
|
||||
<!-- xsl:template match="//*[local-name() = 'HeaderExchangedDocument']">
|
||||
<xsl:copy> <xsl:apply-templates select="@*|node()" /> </xsl:copy> </xsl:template> -->
|
||||
|
||||
<!-- 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()" />
|
||||
</xsl:element>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="//*[local-name() = 'HeaderExchangedDocument']">
|
||||
<rsm:ExchangedDocument>
|
||||
<xsl:apply-templates select="@*|node()" />
|
||||
</rsm:ExchangedDocument>
|
||||
</xsl:template>
|
||||
|
||||
|
||||
<xsl:template match="//*[local-name() = 'ApplicablePercent']">
|
||||
<ram:RateApplicablePercent>
|
||||
<xsl:apply-templates select="@*|node()" />
|
||||
</ram:RateApplicablePercent>
|
||||
</xsl:template>
|
||||
|
||||
|
||||
<xsl:template match="//*[local-name() = 'SpecifiedSupplyChainTradeDelivery']">
|
||||
<ram:SpecifiedLineTradeDelivery>
|
||||
<xsl:apply-templates select="@*|node()" />
|
||||
</ram:SpecifiedLineTradeDelivery>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template match="//*[local-name() = 'SpecifiedLineTradeAgreement']">
|
||||
<ram:AssociatedDocumentLineDocument>
|
||||
<xsl:apply-templates select="@*|node()" />
|
||||
</ram:AssociatedDocumentLineDocument>
|
||||
</xsl:template>
|
||||
|
||||
|
||||
<xsl:template
|
||||
match="//*[local-name() = 'SpecifiedSupplyChainTradeAgreement']">
|
||||
<ram:SpecifiedLineTradeAgreement>
|
||||
<xsl:apply-templates select="@*|node()" />
|
||||
</ram:SpecifiedLineTradeAgreement>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template
|
||||
match="//*[local-name() = 'SpecifiedSupplyChainTradeSettlement']">
|
||||
<ram:SpecifiedLineTradeSettlement>
|
||||
<xsl:apply-templates select="@*|node()" />
|
||||
</ram:SpecifiedLineTradeSettlement>
|
||||
</xsl:template>
|
||||
|
||||
<!-- SpecifiedTradeSettlementMonetarySummation -> SpecifiedTradeSettlementLineMonetarySummation
|
||||
unterhalb SpecifiedLineTradeSettlement -> SpecifiedTradeSettlementHeaderMonetarySummation
|
||||
unterhalb ApplicableHeaderTradeSettlement -->
|
||||
|
||||
<xsl:template
|
||||
match="//*[local-name()='SpecifiedSupplyChainTradeSettlement']/*[local-name()='SpecifiedTradeSettlementMonetarySummation']">
|
||||
<ram:SpecifiedTradeSettlementLineMonetarySummation>
|
||||
<xsl:apply-templates select="@*|node()" />
|
||||
</ram:SpecifiedTradeSettlementLineMonetarySummation>
|
||||
</xsl:template>
|
||||
|
||||
<!-- ApplicableSupplyChainTradeSettlement -->
|
||||
<xsl:template
|
||||
match="//*[local-name() = 'ApplicableSupplyChainTradeSettlement']/*[local-name() = 'SpecifiedTradeSettlementMonetarySummation']">
|
||||
<ram:SpecifiedTradeSettlementHeaderMonetarySummation>
|
||||
<xsl:apply-templates select="@*|node()" />
|
||||
</ram:SpecifiedTradeSettlementHeaderMonetarySummation>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template
|
||||
match="//*[local-name() = 'ApplicableSupplyChainTradeAgreement']">
|
||||
<ram:ApplicableHeaderTradeAgreement>
|
||||
<xsl:apply-templates select="@*|node()" />
|
||||
</ram:ApplicableHeaderTradeAgreement>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template
|
||||
match="//*[local-name() = 'ApplicableSupplyChainTradeDelivery']">
|
||||
<ram:ApplicableHeaderTradeDelivery>
|
||||
<xsl:apply-templates select="@*|node()" />
|
||||
</ram:ApplicableHeaderTradeDelivery>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template
|
||||
match="//*[local-name() = 'ApplicableSupplyChainTradeSettlement']">
|
||||
<ram:ApplicableHeaderTradeSettlement>
|
||||
<xsl:apply-templates select="@*|node()" />
|
||||
</ram:ApplicableHeaderTradeSettlement>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template
|
||||
match="//*[local-name() = 'SpecifiedTradeAccountingAccount']">
|
||||
<ram:ReceivableSpecifiedTradeAccountingAccount>
|
||||
<xsl:apply-templates select="@*|node()" />
|
||||
</ram:ReceivableSpecifiedTradeAccountingAccount>
|
||||
</xsl:template>
|
||||
<!-- rename hierarchical -->
|
||||
|
||||
|
||||
|
||||
<xsl:template
|
||||
match="//*[local-name() = 'BuyerOrderReferencedDocument' or local-name() = 'DeliveryNoteReferencedDocument' or local-name() = 'AdditionalReferencedDocument' or local-name() = 'ContractReferencedDocument']/*[local-name() = 'ID']">
|
||||
<ram:IssuerAssignedID>
|
||||
<xsl:apply-templates select="@*|node()" />
|
||||
</ram:IssuerAssignedID>
|
||||
</xsl:template>
|
||||
|
||||
|
||||
|
||||
<xsl:template
|
||||
match="//*[local-name() = 'ContractReferencedDocument']/*[local-name() = 'TypeCode']">
|
||||
<ram:ReferenceTypeCode>
|
||||
<xsl:apply-templates select="@*|node()" />
|
||||
</ram:ReferenceTypeCode>
|
||||
</xsl:template>
|
||||
|
||||
<!-- rename and add -->
|
||||
|
||||
<xsl:template match="//*[local-name() != 'HeaderExchangedDocument']/*[local-name() = 'IssueDateTime']">
|
||||
<ram:FormattedIssueDateTime>
|
||||
<qdt:DateTimeString>
|
||||
<xsl:apply-templates select="@*|node()" />
|
||||
</qdt:DateTimeString>
|
||||
</ram:FormattedIssueDateTime>
|
||||
</xsl:template>
|
||||
|
||||
|
||||
<!-- rename and reorder -->
|
||||
<xsl:template
|
||||
match="//*[local-name() = 'SpecifiedSupplyChainTradeTransaction']">
|
||||
<rsm:SupplyChainTradeTransaction><!-- surplus namespaces -->
|
||||
<xsl:apply-templates
|
||||
select="./*[local-name() = 'IncludedSupplyChainTradeLineItem']" />
|
||||
<!-- now copy any other children that we haven't explicitly reordered;
|
||||
again, possibly this is not what you want -->
|
||||
<xsl:apply-templates
|
||||
select="./*[not(local-name() = 'IncludedSupplyChainTradeLineItem')]" />
|
||||
|
||||
</rsm:SupplyChainTradeTransaction>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template
|
||||
match="//*[local-name() = 'BuyerOrderReferencedDocument' or local-name() = 'DeliveryNoteReferencedDocument' or local-name() = 'AdditionalReferencedDocument' or local-name() = 'ContractReferencedDocument']">
|
||||
<xsl:element name="{name()}">
|
||||
|
||||
<xsl:apply-templates
|
||||
select="./*[local-name() = 'ID']" />
|
||||
<xsl:apply-templates
|
||||
select="./*[local-name() = 'TypeCode']" />
|
||||
<xsl:apply-templates
|
||||
select="./*[not(local-name() = 'ID' or local-name() = 'TypeCode')]" />
|
||||
</xsl:element>
|
||||
</xsl:template>
|
||||
|
||||
<!-- innerhalb IncludedSupplyChainTradeLineItem zuerst AssociatedDocumentLineDocument
|
||||
dann SpecifiedTradeProduct -->
|
||||
<xsl:template match="//*[local-name() = 'IncludedSupplyChainTradeLineItem']">
|
||||
<ram:IncludedSupplyChainTradeLineItem>
|
||||
<xsl:apply-templates
|
||||
select="./*[local-name() = 'AssociatedDocumentLineDocument']" />
|
||||
<xsl:apply-templates select="./*[local-name() = 'SpecifiedTradeProduct']" />
|
||||
<!-- now copy any other children that we haven't explicitly reordered;
|
||||
again, possibly this is not what you want -->
|
||||
|
||||
<xsl:apply-templates
|
||||
select="./*[not(local-name() = 'AssociatedDocumentLineDocument' or local-name() = 'SpecifiedTradeProduct')]" />
|
||||
|
||||
</ram:IncludedSupplyChainTradeLineItem>
|
||||
</xsl:template>
|
||||
|
||||
<xsl:template
|
||||
match="//*[local-name() = 'SpecifiedLineTradeSettlement']">
|
||||
<ram:SpecifiedLineTradeSettlement>
|
||||
|
||||
<xsl:apply-templates
|
||||
select="./*[not(local-name() = 'SpecifiedTradeSettlementHeaderMonetarySummation' or local-name() = 'SpecifiedTradeSettlementLineMonetarySummation' or local-name() = 'SpecifiedTradeAccountingAccount')]" />
|
||||
<xsl:apply-templates
|
||||
select="./*[local-name() = 'SpecifiedTradeSettlementHeaderMonetarySummation']" />
|
||||
<xsl:apply-templates
|
||||
select="./*[local-name() = 'SpecifiedTradeSettlementLineMonetarySummation']" />
|
||||
<xsl:apply-templates
|
||||
select="./*[local-name() = 'SpecifiedTradeAccountingAccount']" />
|
||||
|
||||
</ram:SpecifiedLineTradeSettlement>
|
||||
</xsl:template>
|
||||
<xsl:template
|
||||
match="//*[local-name() = 'ApplicableHeaderTradeSettlement' or local-name() = 'SpecifiedLineTradeSettlement']">
|
||||
<xsl:element name="{name()}">
|
||||
|
||||
<xsl:apply-templates
|
||||
select="./*[not(local-name() = 'SpecifiedTradeSettlementHeaderMonetarySummation' or local-name() = 'SpecifiedTradeSettlementMonetarySummation' or local-name() = 'SpecifiedTradeAccountingAccount')]" />
|
||||
<!-- xsl:apply-templates
|
||||
select="./*[local-name() = 'SpecifiedTradeSettlementHeaderMonetarySummation']" /-->
|
||||
<xsl:apply-templates
|
||||
select="./*[local-name() = 'SpecifiedTradeSettlementMonetarySummation']" />
|
||||
<xsl:apply-templates
|
||||
select="./*[local-name() = 'SpecifiedTradeAccountingAccount']" />
|
||||
|
||||
</xsl:element>
|
||||
</xsl:template>
|
||||
|
||||
|
||||
<!-- unterhalb von SupplyChainTradeTransaction muss zuerst die IncludedSupplyChainTradeLineItem
|
||||
kommen -->
|
||||
<!-- rest -->
|
||||
<!-- this is the identity transform: it copies everything that isn't matched
|
||||
by a more specific template -->
|
||||
|
||||
</xsl:stylesheet>
|
||||
23
libraryBasic/src/main/resources/schema/ZUGFeRD1p0.xsd
Normal file
23
libraryBasic/src/main/resources/schema/ZUGFeRD1p0.xsd
Normal file
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xs:schema xmlns:rsm="urn:ferd:CrossIndustryDocument:invoice:1p0"
|
||||
xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:qdt="urn:un:unece:uncefact:data:standard:QualifiedDataType:12"
|
||||
xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:12"
|
||||
xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:15"
|
||||
targetNamespace="urn:ferd:CrossIndustryDocument:invoice:1p0"
|
||||
elementFormDefault="qualified">
|
||||
<xs:import namespace="urn:un:unece:uncefact:data:standard:QualifiedDataType:12"
|
||||
schemaLocation="ZUGFeRD1p0_urn_un_unece_uncefact_data_standard_QualifiedDataType_12.xsd"/>
|
||||
<xs:import namespace="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:12"
|
||||
schemaLocation="ZUGFeRD1p0_urn_un_unece_uncefact_data_standard_ReusableAggregateBusinessInformationEntity_12.xsd"/>
|
||||
<xs:import namespace="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:15"
|
||||
schemaLocation="ZUGFeRD1p0_urn_un_unece_uncefact_data_standard_UnqualifiedDataType_15.xsd"/>
|
||||
<xs:element name="CrossIndustryDocument" type="rsm:CrossIndustryDocumentType"/>
|
||||
<xs:complexType name="CrossIndustryDocumentType">
|
||||
<xs:sequence>
|
||||
<xs:element name="SpecifiedExchangedDocumentContext" type="ram:ExchangedDocumentContextType"/>
|
||||
<xs:element name="HeaderExchangedDocument" type="ram:ExchangedDocumentType"/>
|
||||
<xs:element name="SpecifiedSupplyChainTradeTransaction" type="ram:SupplyChainTradeTransactionType"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:schema>
|
||||
@@ -0,0 +1,77 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xs:schema xmlns:qdt="urn:un:unece:uncefact:data:standard:QualifiedDataType:12"
|
||||
xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:15"
|
||||
targetNamespace="urn:un:unece:uncefact:data:standard:QualifiedDataType:12"
|
||||
elementFormDefault="qualified"
|
||||
version="12.0">
|
||||
<xs:import namespace="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:15"
|
||||
schemaLocation="ZUGFeRD1p0_urn_un_unece_uncefact_data_standard_UnqualifiedDataType_15.xsd"/>
|
||||
<xs:simpleType name="AllowanceChargeReasonCodeContentType">
|
||||
<xs:restriction base="xs:token"/>
|
||||
</xs:simpleType>
|
||||
<xs:complexType name="AllowanceChargeReasonCodeType">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="qdt:AllowanceChargeReasonCodeContentType"/>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
<xs:simpleType name="CountryIDContentType">
|
||||
<xs:restriction base="xs:token"/>
|
||||
</xs:simpleType>
|
||||
<xs:complexType name="CountryIDType">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="qdt:CountryIDContentType"/>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
<xs:simpleType name="DateMandatoryDateTimeType">
|
||||
<xs:union memberTypes="xs:dateTime xs:date"/>
|
||||
</xs:simpleType>
|
||||
<xs:simpleType name="DeliveryTermsCodeContentType">
|
||||
<xs:restriction base="xs:token"/>
|
||||
</xs:simpleType>
|
||||
<xs:complexType name="DeliveryTermsCodeType">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="qdt:DeliveryTermsCodeContentType"/>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
<xs:simpleType name="DocumentCodeContentType">
|
||||
<xs:restriction base="xs:token"/>
|
||||
</xs:simpleType>
|
||||
<xs:complexType name="DocumentCodeType">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="qdt:DocumentCodeContentType"/>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
<xs:simpleType name="PaymentMeansCodeContentType">
|
||||
<xs:restriction base="xs:token"/>
|
||||
</xs:simpleType>
|
||||
<xs:complexType name="PaymentMeansCodeType">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="qdt:PaymentMeansCodeContentType"/>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
<xs:simpleType name="ReferenceCodeContentType">
|
||||
<xs:restriction base="xs:token"/>
|
||||
</xs:simpleType>
|
||||
<xs:complexType name="ReferenceCodeType">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="qdt:ReferenceCodeContentType"/>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
<xs:simpleType name="TaxCategoryCodeContentType">
|
||||
<xs:restriction base="xs:token"/>
|
||||
</xs:simpleType>
|
||||
<xs:complexType name="TaxCategoryCodeType">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="qdt:TaxCategoryCodeContentType"/>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
<xs:simpleType name="TaxTypeCodeContentType">
|
||||
<xs:restriction base="xs:token"/>
|
||||
</xs:simpleType>
|
||||
<xs:complexType name="TaxTypeCodeType">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="qdt:TaxTypeCodeContentType"/>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
</xs:schema>
|
||||
@@ -0,0 +1,391 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xs:schema xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:12"
|
||||
xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
xmlns:qdt="urn:un:unece:uncefact:data:standard:QualifiedDataType:12"
|
||||
xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:15"
|
||||
targetNamespace="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:12"
|
||||
elementFormDefault="qualified"
|
||||
version="12.0">
|
||||
<xs:import namespace="urn:un:unece:uncefact:data:standard:QualifiedDataType:12"
|
||||
schemaLocation="ZUGFeRD1p0_urn_un_unece_uncefact_data_standard_QualifiedDataType_12.xsd"/>
|
||||
<xs:import namespace="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:15"
|
||||
schemaLocation="ZUGFeRD1p0_urn_un_unece_uncefact_data_standard_UnqualifiedDataType_15.xsd"/>
|
||||
<xs:complexType name="CreditorFinancialAccountType">
|
||||
<xs:sequence>
|
||||
<xs:element name="IBANID" type="udt:IDType" minOccurs="0"/>
|
||||
<xs:element name="AccountName" type="udt:TextType" minOccurs="0"/>
|
||||
<xs:element name="ProprietaryID" type="udt:IDType" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="CreditorFinancialInstitutionType">
|
||||
<xs:sequence>
|
||||
<xs:element name="BICID" type="udt:IDType" minOccurs="0"/>
|
||||
<xs:element name="GermanBankleitzahlID" type="udt:IDType" minOccurs="0"/>
|
||||
<xs:element name="Name" type="udt:TextType" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="DebtorFinancialAccountType">
|
||||
<xs:sequence>
|
||||
<xs:element name="IBANID" type="udt:IDType" minOccurs="0"/>
|
||||
<xs:element name="ProprietaryID" type="udt:IDType" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="DebtorFinancialInstitutionType">
|
||||
<xs:sequence>
|
||||
<xs:element name="BICID" type="udt:IDType" minOccurs="0"/>
|
||||
<xs:element name="GermanBankleitzahlID" type="udt:IDType" minOccurs="0"/>
|
||||
<xs:element name="Name" type="udt:TextType" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="DocumentContextParameterType">
|
||||
<xs:sequence>
|
||||
<xs:element name="ID" type="udt:IDType" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="DocumentLineDocumentType">
|
||||
<xs:sequence>
|
||||
<xs:element name="LineID" type="udt:IDType" minOccurs="0"/>
|
||||
<xs:element name="IncludedNote" type="ram:NoteType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="ExchangedDocumentContextType">
|
||||
<xs:sequence>
|
||||
<xs:element name="TestIndicator" type="udt:IndicatorType" minOccurs="0"/>
|
||||
<xs:element name="BusinessProcessSpecifiedDocumentContextParameter" type="ram:DocumentContextParameterType"
|
||||
minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="GuidelineSpecifiedDocumentContextParameter" type="ram:DocumentContextParameterType"
|
||||
minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="ExchangedDocumentType">
|
||||
<xs:sequence>
|
||||
<xs:element name="ID" type="udt:IDType" minOccurs="0"/>
|
||||
<xs:element name="Name" type="udt:TextType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="TypeCode" type="qdt:DocumentCodeType" minOccurs="0"/>
|
||||
<xs:element name="IssueDateTime" type="udt:DateTimeType" minOccurs="0"/>
|
||||
<xs:element name="CopyIndicator" type="udt:IndicatorType" minOccurs="0"/>
|
||||
<xs:element name="LanguageID" type="udt:IDType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="IncludedNote" type="ram:NoteType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="EffectiveSpecifiedPeriod" type="ram:SpecifiedPeriodType" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="LogisticsServiceChargeType">
|
||||
<xs:sequence>
|
||||
<xs:element name="Description" type="udt:TextType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="AppliedAmount" type="udt:AmountType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="AppliedTradeTax" type="ram:TradeTaxType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="LogisticsTransportMovementType">
|
||||
<xs:sequence>
|
||||
<xs:element name="ModeCode" type="udt:CodeType" minOccurs="0"/>
|
||||
<xs:element name="ID" type="udt:IDType" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="NoteType">
|
||||
<xs:sequence>
|
||||
<xs:element name="ContentCode" type="udt:CodeType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="Content" type="udt:TextType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="SubjectCode" type="udt:CodeType" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="ProductCharacteristicType">
|
||||
<xs:sequence>
|
||||
<xs:element name="TypeCode" type="udt:CodeType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="Description" type="udt:TextType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="ValueMeasure" type="udt:MeasureType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="Value" type="udt:TextType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="ProductClassificationType">
|
||||
<xs:sequence>
|
||||
<xs:element name="ClassCode" type="udt:CodeType" minOccurs="0"/>
|
||||
<xs:element name="ClassName" type="udt:TextType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="ReferencedDocumentType">
|
||||
<xs:sequence>
|
||||
<xs:element name="IssueDateTime" type="qdt:DateMandatoryDateTimeType" minOccurs="0"/>
|
||||
<xs:element name="LineID" type="udt:IDType" minOccurs="0"/>
|
||||
<xs:element name="TypeCode" type="qdt:DocumentCodeType" minOccurs="0"/>
|
||||
<xs:element name="ID" type="udt:IDType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="ReferenceTypeCode" type="qdt:ReferenceCodeType" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="ReferencedProductType">
|
||||
<xs:sequence>
|
||||
<xs:element name="GlobalID" type="udt:IDType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="SellerAssignedID" type="udt:IDType" minOccurs="0"/>
|
||||
<xs:element name="BuyerAssignedID" type="udt:IDType" minOccurs="0"/>
|
||||
<xs:element name="Name" type="udt:TextType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="Description" type="udt:TextType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="UnitQuantity" type="udt:QuantityType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="SpecifiedPeriodType">
|
||||
<xs:sequence>
|
||||
<xs:element name="StartDateTime" type="udt:DateTimeType" minOccurs="0"/>
|
||||
<xs:element name="EndDateTime" type="udt:DateTimeType" minOccurs="0"/>
|
||||
<xs:element name="CompleteDateTime" type="udt:DateTimeType" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="SupplyChainConsignmentType">
|
||||
<xs:sequence>
|
||||
<xs:element name="SpecifiedLogisticsTransportMovement" type="ram:LogisticsTransportMovementType"
|
||||
minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="SupplyChainEventType">
|
||||
<xs:sequence>
|
||||
<xs:element name="OccurrenceDateTime" type="udt:DateTimeType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="SupplyChainTradeAgreementType">
|
||||
<xs:sequence>
|
||||
<xs:element name="BuyerReference" type="udt:TextType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="SellerTradeParty" type="ram:TradePartyType" minOccurs="0"/>
|
||||
<xs:element name="BuyerTradeParty" type="ram:TradePartyType" minOccurs="0"/>
|
||||
<xs:element name="ProductEndUserTradeParty" type="ram:TradePartyType" minOccurs="0"/>
|
||||
<xs:element name="ApplicableTradeDeliveryTerms" type="ram:TradeDeliveryTermsType" minOccurs="0"/>
|
||||
<xs:element name="BuyerOrderReferencedDocument" type="ram:ReferencedDocumentType" minOccurs="0"
|
||||
maxOccurs="unbounded"/>
|
||||
<xs:element name="ContractReferencedDocument" type="ram:ReferencedDocumentType" minOccurs="0"
|
||||
maxOccurs="unbounded"/>
|
||||
<xs:element name="AdditionalReferencedDocument" type="ram:ReferencedDocumentType" minOccurs="0"
|
||||
maxOccurs="unbounded"/>
|
||||
<xs:element name="GrossPriceProductTradePrice" type="ram:TradePriceType" minOccurs="0"
|
||||
maxOccurs="unbounded"/>
|
||||
<xs:element name="NetPriceProductTradePrice" type="ram:TradePriceType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="CustomerOrderReferencedDocument" type="ram:ReferencedDocumentType" minOccurs="0"
|
||||
maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="SupplyChainTradeDeliveryType">
|
||||
<xs:sequence>
|
||||
<xs:element name="BilledQuantity" type="udt:QuantityType" minOccurs="0"/>
|
||||
<xs:element name="ChargeFreeQuantity" type="udt:QuantityType" minOccurs="0"/>
|
||||
<xs:element name="PackageQuantity" type="udt:QuantityType" minOccurs="0"/>
|
||||
<xs:element name="RelatedSupplyChainConsignment" type="ram:SupplyChainConsignmentType" minOccurs="0"
|
||||
maxOccurs="unbounded"/>
|
||||
<xs:element name="ShipToTradeParty" type="ram:TradePartyType" minOccurs="0"/>
|
||||
<xs:element name="UltimateShipToTradeParty" type="ram:TradePartyType" minOccurs="0"/>
|
||||
<xs:element name="ShipFromTradeParty" type="ram:TradePartyType" minOccurs="0"/>
|
||||
<xs:element name="ActualDeliverySupplyChainEvent" type="ram:SupplyChainEventType" minOccurs="0"
|
||||
maxOccurs="unbounded"/>
|
||||
<xs:element name="DespatchAdviceReferencedDocument" type="ram:ReferencedDocumentType" minOccurs="0"/>
|
||||
<xs:element name="ReceivingAdviceReferencedDocument" type="ram:ReferencedDocumentType" minOccurs="0"
|
||||
maxOccurs="unbounded"/>
|
||||
<xs:element name="DeliveryNoteReferencedDocument" type="ram:ReferencedDocumentType" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="SupplyChainTradeLineItemType">
|
||||
<xs:sequence>
|
||||
<xs:element name="AssociatedDocumentLineDocument" type="ram:DocumentLineDocumentType" minOccurs="0"/>
|
||||
<xs:element name="SpecifiedSupplyChainTradeAgreement" type="ram:SupplyChainTradeAgreementType"
|
||||
minOccurs="0"/>
|
||||
<xs:element name="SpecifiedSupplyChainTradeDelivery" type="ram:SupplyChainTradeDeliveryType" minOccurs="0"/>
|
||||
<xs:element name="SpecifiedSupplyChainTradeSettlement" type="ram:SupplyChainTradeSettlementType"
|
||||
minOccurs="0"/>
|
||||
<xs:element name="SpecifiedTradeProduct" type="ram:TradeProductType" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="SupplyChainTradeSettlementType">
|
||||
<xs:sequence>
|
||||
<xs:element name="PaymentReference" type="udt:TextType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="InvoiceCurrencyCode" type="udt:CodeType" minOccurs="0"/>
|
||||
<xs:element name="InvoiceeTradeParty" type="ram:TradePartyType" minOccurs="0"/>
|
||||
<xs:element name="PayeeTradeParty" type="ram:TradePartyType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="SpecifiedTradeSettlementPaymentMeans" type="ram:TradeSettlementPaymentMeansType"
|
||||
minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="ApplicableTradeTax" type="ram:TradeTaxType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="BillingSpecifiedPeriod" type="ram:SpecifiedPeriodType" minOccurs="0"
|
||||
maxOccurs="unbounded"/>
|
||||
<xs:element name="SpecifiedTradeAllowanceCharge" type="ram:TradeAllowanceChargeType" minOccurs="0"
|
||||
maxOccurs="unbounded"/>
|
||||
<xs:element name="SpecifiedLogisticsServiceCharge" type="ram:LogisticsServiceChargeType" minOccurs="0"
|
||||
maxOccurs="unbounded"/>
|
||||
<xs:element name="SpecifiedTradePaymentTerms" type="ram:TradePaymentTermsType" minOccurs="0"
|
||||
maxOccurs="unbounded"/>
|
||||
<xs:element name="SpecifiedTradeAccountingAccount" type="ram:TradeAccountingAccountType" minOccurs="0"
|
||||
maxOccurs="unbounded"/>
|
||||
<xs:element name="SpecifiedTradeSettlementMonetarySummation" type="ram:TradeSettlementMonetarySummationType"
|
||||
minOccurs="0"/>
|
||||
<xs:element name="ReceivableSpecifiedTradeAccountingAccount" type="ram:TradeAccountingAccountType"
|
||||
minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="SupplyChainTradeTransactionType">
|
||||
<xs:sequence>
|
||||
<xs:element name="ApplicableSupplyChainTradeAgreement" type="ram:SupplyChainTradeAgreementType"
|
||||
minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="ApplicableSupplyChainTradeDelivery" type="ram:SupplyChainTradeDeliveryType"
|
||||
minOccurs="0"/>
|
||||
<xs:element name="ApplicableSupplyChainTradeSettlement" type="ram:SupplyChainTradeSettlementType"
|
||||
minOccurs="0"/>
|
||||
<xs:element name="IncludedSupplyChainTradeLineItem" type="ram:SupplyChainTradeLineItemType" minOccurs="0"
|
||||
maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="TaxRegistrationType">
|
||||
<xs:sequence>
|
||||
<xs:element name="ID" type="udt:IDType" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="TradeAccountingAccountType">
|
||||
<xs:sequence>
|
||||
<xs:element name="ID" type="udt:IDType" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="TradeAddressType">
|
||||
<xs:sequence>
|
||||
<xs:element name="PostcodeCode" type="udt:CodeType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="LineOne" type="udt:TextType" minOccurs="0"/>
|
||||
<xs:element name="LineTwo" type="udt:TextType" minOccurs="0"/>
|
||||
<xs:element name="CityName" type="udt:TextType" minOccurs="0"/>
|
||||
<xs:element name="CountryID" type="qdt:CountryIDType" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="TradeAllowanceChargeType">
|
||||
<xs:sequence>
|
||||
<xs:element name="ChargeIndicator" type="udt:IndicatorType" minOccurs="0"/>
|
||||
<xs:element name="SequenceNumeric" type="udt:NumericType" minOccurs="0"/>
|
||||
<xs:element name="CalculationPercent" type="udt:PercentType" minOccurs="0"/>
|
||||
<xs:element name="BasisAmount" type="udt:AmountType" minOccurs="0"/>
|
||||
<xs:element name="BasisQuantity" type="udt:QuantityType" minOccurs="0"/>
|
||||
<xs:element name="ActualAmount" type="udt:AmountType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="ReasonCode" type="qdt:AllowanceChargeReasonCodeType" minOccurs="0"/>
|
||||
<xs:element name="Reason" type="udt:TextType" minOccurs="0"/>
|
||||
<xs:element name="CategoryTradeTax" type="ram:TradeTaxType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="TradeContactType">
|
||||
<xs:sequence>
|
||||
<xs:element name="PersonName" type="udt:TextType" minOccurs="0"/>
|
||||
<xs:element name="DepartmentName" type="udt:TextType" minOccurs="0"/>
|
||||
<xs:element name="TelephoneUniversalCommunication" type="ram:UniversalCommunicationType" minOccurs="0"
|
||||
maxOccurs="unbounded"/>
|
||||
<xs:element name="FaxUniversalCommunication" type="ram:UniversalCommunicationType" minOccurs="0"
|
||||
maxOccurs="unbounded"/>
|
||||
<xs:element name="EmailURIUniversalCommunication" type="ram:UniversalCommunicationType" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="TradeCountryType">
|
||||
<xs:sequence>
|
||||
<xs:element name="ID" type="qdt:CountryIDType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="TradeDeliveryTermsType">
|
||||
<xs:sequence>
|
||||
<xs:element name="DeliveryTypeCode" type="qdt:DeliveryTermsCodeType" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="TradePartyType">
|
||||
<xs:sequence>
|
||||
<xs:element name="ID" type="udt:IDType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="GlobalID" type="udt:IDType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="Name" type="udt:TextType" minOccurs="0"/>
|
||||
<xs:element name="DefinedTradeContact" type="ram:TradeContactType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="PostalTradeAddress" type="ram:TradeAddressType" minOccurs="0"/>
|
||||
<xs:element name="SpecifiedTaxRegistration" type="ram:TaxRegistrationType" minOccurs="0"
|
||||
maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="TradePaymentDiscountTermsType">
|
||||
<xs:sequence>
|
||||
<xs:element name="BasisDateTime" type="udt:DateTimeType" minOccurs="0"/>
|
||||
<xs:element name="BasisPeriodMeasure" type="udt:MeasureType" minOccurs="0"/>
|
||||
<xs:element name="BasisAmount" type="udt:AmountType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="CalculationPercent" type="udt:PercentType" minOccurs="0"/>
|
||||
<xs:element name="ActualDiscountAmount" type="udt:AmountType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="TradePaymentPenaltyTermsType">
|
||||
<xs:sequence>
|
||||
<xs:element name="BasisDateTime" type="udt:DateTimeType" minOccurs="0"/>
|
||||
<xs:element name="BasisPeriodMeasure" type="udt:MeasureType" minOccurs="0"/>
|
||||
<xs:element name="BasisAmount" type="udt:AmountType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="CalculationPercent" type="udt:PercentType" minOccurs="0"/>
|
||||
<xs:element name="ActualPenaltyAmount" type="udt:AmountType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="TradePaymentTermsType">
|
||||
<xs:sequence>
|
||||
<xs:element name="Description" type="udt:TextType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="DueDateDateTime" type="udt:DateTimeType" minOccurs="0"/>
|
||||
<xs:element name="PartialPaymentAmount" type="udt:AmountType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="ApplicableTradePaymentPenaltyTerms" type="ram:TradePaymentPenaltyTermsType" minOccurs="0"
|
||||
maxOccurs="unbounded"/>
|
||||
<xs:element name="ApplicableTradePaymentDiscountTerms" type="ram:TradePaymentDiscountTermsType"
|
||||
minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="TradePriceType">
|
||||
<xs:sequence>
|
||||
<xs:element name="ChargeAmount" type="udt:AmountType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="BasisQuantity" type="udt:QuantityType" minOccurs="0"/>
|
||||
<xs:element name="AppliedTradeAllowanceCharge" type="ram:TradeAllowanceChargeType" minOccurs="0"
|
||||
maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="TradeProductType">
|
||||
<xs:sequence>
|
||||
<xs:element name="GlobalID" type="udt:IDType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="SellerAssignedID" type="udt:IDType" minOccurs="0"/>
|
||||
<xs:element name="BuyerAssignedID" type="udt:IDType" minOccurs="0"/>
|
||||
<xs:element name="Name" type="udt:TextType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="Description" type="udt:TextType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="ApplicableProductCharacteristic" type="ram:ProductCharacteristicType" minOccurs="0"
|
||||
maxOccurs="unbounded"/>
|
||||
<xs:element name="DesignatedProductClassification" type="ram:ProductClassificationType" minOccurs="0"
|
||||
maxOccurs="unbounded"/>
|
||||
<xs:element name="OriginTradeCountry" type="ram:TradeCountryType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="IncludedReferencedProduct" type="ram:ReferencedProductType" minOccurs="0"
|
||||
maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="TradeSettlementMonetarySummationType">
|
||||
<xs:sequence>
|
||||
<xs:element name="LineTotalAmount" type="udt:AmountType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="ChargeTotalAmount" type="udt:AmountType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="AllowanceTotalAmount" type="udt:AmountType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="TaxBasisTotalAmount" type="udt:AmountType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="TaxTotalAmount" type="udt:AmountType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="GrandTotalAmount" type="udt:AmountType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="TotalPrepaidAmount" type="udt:AmountType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="TotalAllowanceChargeAmount" type="udt:AmountType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="DuePayableAmount" type="udt:AmountType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="TradeSettlementPaymentMeansType">
|
||||
<xs:sequence>
|
||||
<xs:element name="TypeCode" type="qdt:PaymentMeansCodeType" minOccurs="0"/>
|
||||
<xs:element name="Information" type="udt:TextType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="ID" type="udt:IDType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="PayerPartyDebtorFinancialAccount" type="ram:DebtorFinancialAccountType" minOccurs="0"/>
|
||||
<xs:element name="PayeePartyCreditorFinancialAccount" type="ram:CreditorFinancialAccountType"
|
||||
minOccurs="0"/>
|
||||
<xs:element name="PayerSpecifiedDebtorFinancialInstitution" type="ram:DebtorFinancialInstitutionType"
|
||||
minOccurs="0"/>
|
||||
<xs:element name="PayeeSpecifiedCreditorFinancialInstitution" type="ram:CreditorFinancialInstitutionType"
|
||||
minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="TradeTaxType">
|
||||
<xs:sequence>
|
||||
<xs:element name="CalculatedAmount" type="udt:AmountType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="TypeCode" type="qdt:TaxTypeCodeType" minOccurs="0"/>
|
||||
<xs:element name="ExemptionReason" type="udt:TextType" minOccurs="0"/>
|
||||
<xs:element name="BasisAmount" type="udt:AmountType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="LineTotalBasisAmount" type="udt:AmountType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="AllowanceChargeBasisAmount" type="udt:AmountType" minOccurs="0" maxOccurs="unbounded"/>
|
||||
<xs:element name="CategoryCode" type="qdt:TaxCategoryCodeType" minOccurs="0"/>
|
||||
<xs:element name="ApplicablePercent" type="udt:PercentType" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="UniversalCommunicationType">
|
||||
<xs:sequence>
|
||||
<xs:element name="URIID" type="udt:IDType" minOccurs="0"/>
|
||||
<xs:element name="CompleteNumber" type="udt:TextType" minOccurs="0"/>
|
||||
</xs:sequence>
|
||||
</xs:complexType>
|
||||
</xs:schema>
|
||||
@@ -0,0 +1,95 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<xs:schema xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:15"
|
||||
xmlns:xs="http://www.w3.org/2001/XMLSchema"
|
||||
targetNamespace="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:15"
|
||||
elementFormDefault="qualified"
|
||||
version="15.0">
|
||||
<xs:complexType name="AmountType">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:decimal">
|
||||
<xs:attribute name="currencyID" type="udt:AmountTypeCurrencyIDContentType"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
<xs:simpleType name="AmountTypeCurrencyIDContentType">
|
||||
<xs:restriction base="xs:token"/>
|
||||
</xs:simpleType>
|
||||
<xs:complexType name="CodeType">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:token">
|
||||
<xs:attribute name="listID" type="xs:token"/>
|
||||
<xs:attribute name="listVersionID" type="xs:token"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="DateTimeType">
|
||||
<xs:choice>
|
||||
<xs:element name="DateTimeString">
|
||||
<xs:complexType>
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:string">
|
||||
<xs:attribute name="format" type="xs:string"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:choice>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="IDType">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:token">
|
||||
<xs:attribute name="schemeID" type="xs:token"/>
|
||||
<xs:attribute name="schemeAgencyID" type="udt:IDTypeSchemeAgencyIDContentType"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
<xs:simpleType name="IDTypeSchemeAgencyIDContentType">
|
||||
<xs:restriction base="xs:token"/>
|
||||
</xs:simpleType>
|
||||
<xs:complexType name="IndicatorType">
|
||||
<xs:choice>
|
||||
<xs:element name="Indicator" type="xs:boolean"/>
|
||||
</xs:choice>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="MeasureType">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:decimal">
|
||||
<xs:attribute name="unitCode" type="udt:MeasureTypeUnitCodeContentType"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
<xs:simpleType name="MeasureTypeUnitCodeContentType">
|
||||
<xs:restriction base="xs:token">
|
||||
<xs:minLength value="1"/>
|
||||
<xs:maxLength value="3"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:complexType name="NumericType">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:decimal"/>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="PercentType">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:decimal"/>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
<xs:complexType name="QuantityType">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:decimal">
|
||||
<xs:attribute name="unitCode" type="udt:QuantityTypeUnitCodeContentType"/>
|
||||
</xs:extension>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
<xs:simpleType name="QuantityTypeUnitCodeContentType">
|
||||
<xs:restriction base="xs:token">
|
||||
<xs:minLength value="1"/>
|
||||
<xs:maxLength value="3"/>
|
||||
</xs:restriction>
|
||||
</xs:simpleType>
|
||||
<xs:complexType name="TextType">
|
||||
<xs:simpleContent>
|
||||
<xs:extension base="xs:string"/>
|
||||
</xs:simpleContent>
|
||||
</xs:complexType>
|
||||
</xs:schema>
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user