Reactiate improved migration feature, this time in the library
This commit is contained in:
@@ -7,6 +7,7 @@
|
||||
- fluent setter api/pushprovider #40
|
||||
- new xrechnung profile
|
||||
- visualization? zugferdvisualizer?
|
||||
- migration feature (XSLT upgrade of ZF1 to ZF2) has been improved and moved from the commandline into the library
|
||||
- german bank account numbers can no longer be specified (dropped in favor of IBAN and BIC)
|
||||
- factory for xrechnung #86
|
||||
- moved to Maven central
|
||||
@@ -17,7 +18,6 @@
|
||||
- getSellerTradePartyAddress (PR #157 ) thanks to aberndt-hub
|
||||
- switched from eclipse to IntelliJ
|
||||
- added ph-schematron-maven-plugin so that xrechnung xslt can be generated
|
||||
- removed migration feature (XSLT upgrade of ZF1)
|
||||
- be able to recursively validate directories
|
||||
- be able to ignore input pdf errors with -i
|
||||
- be able to recursively scan directories using validateExpectValid/validateExpectInvalid
|
||||
@@ -58,6 +58,9 @@ switch
|
||||
- *from A3 does not seem tow ork see mustangreaderwriteredgetest:testedgeexport
|
||||
- xmp errors may not show correctly in log
|
||||
- confirm correct generation from pdf/a3 files zf2edgetest
|
||||
- visualization tests
|
||||
- migration tests
|
||||
- migration documentation
|
||||
- *correctiontest exports zf1+zf2?
|
||||
- *USt 0% wird aus invoice-klasse noch nicht sauber abgefangen
|
||||
- finalize invoiceimporter
|
||||
|
||||
@@ -71,6 +71,10 @@ public class Main {
|
||||
+ " [--profile <...>]: set ZUGFeRD profile\n"
|
||||
+ " For ZUGFeRD v1: <B>ASIC, <C>OMFORT or EX<T>ENDED\n"
|
||||
+ " For ZUGFeRD v2: <M>INIMUM, BASIC <W>L, <B>ASIC, <C>IUS, <E>N16931, <X>Rechnung, EX<T>ENDED "
|
||||
+ " 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"
|
||||
+ " validate validate XML or PDF file \n"
|
||||
+ " [--no-notices]: refrain from reporting notices\n"
|
||||
+ " [--logAppend=<text>]: text to be added to log line\n"
|
||||
@@ -221,8 +225,35 @@ public class Main {
|
||||
|
||||
return selectedName;
|
||||
}
|
||||
private static void performUpgrade(String xmlName, String outName) throws IOException, TransformerException {
|
||||
|
||||
// /opt/local/bin/mvn clean compile assembly:single
|
||||
// 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", "factur-x.xml", "xml", false, true);
|
||||
} else {
|
||||
System.out.println("ZUGFeRD 2 XML target to " + outName);
|
||||
}
|
||||
|
||||
// Verify params
|
||||
ensureFileExists(xmlName);
|
||||
ensureFileNotExists(outName);
|
||||
|
||||
// All params are good! continue...
|
||||
XMLUpgrader zmi = new XMLUpgrader();
|
||||
String xml = zmi.migrateFromV1ToV2(xmlName);
|
||||
Files.write(Paths.get(outName), xml.getBytes());
|
||||
System.out.println("Written to " + outName);
|
||||
|
||||
}
|
||||
/***
|
||||
* the main function of the commandline tool...
|
||||
* @param args
|
||||
*/
|
||||
public static void main(String[] args) {
|
||||
try {
|
||||
|
||||
@@ -303,6 +334,9 @@ public class Main {
|
||||
} else if ((action!=null)&&(action.equals("visualize"))) {
|
||||
performVisualization(sourceName, outName);
|
||||
optionsRecognized=true;
|
||||
} else if ((action!=null)&&(action.equals("upgrade"))) {
|
||||
performUpgrade(sourceName, outName);
|
||||
optionsRecognized=true;
|
||||
} else if ((action!=null)&&(action.equals("validate"))) {
|
||||
optionsRecognized=performValidate(sourceName, noNotices!=null&&noNotices, parser.getOptionValue(logAppendOption));
|
||||
} else if ((action!=null)&&(action.equals("validateExpectValid"))) {
|
||||
|
||||
@@ -1,205 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<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"><!--
|
||||
Migrated by Mustangproject XSLT
|
||||
-->
|
||||
<rsm:ExchangedDocumentContext>
|
||||
<ram:TestIndicator>
|
||||
<udt:Indicator>false</udt:Indicator>
|
||||
</ram:TestIndicator>
|
||||
<ram:GuidelineSpecifiedDocumentContextParameter>
|
||||
<ram:ID>urn:ferd:CrossIndustryDocument:invoice:1p0:extended</ram:ID>
|
||||
</ram:GuidelineSpecifiedDocumentContextParameter>
|
||||
</rsm:ExchangedDocumentContext>
|
||||
<rsm:ExchangedDocument xmlns:qdt="urn:un:unece:uncefact:data:standard:QualifiedDataType:100">
|
||||
<ram:ID>RE-20170509/505</ram:ID>
|
||||
<ram:Name>RECHNUNG</ram:Name>
|
||||
<ram:TypeCode>380</ram:TypeCode>
|
||||
<ram:IssueDateTime>
|
||||
<udt:DateTimeString format="102">20170509</udt:DateTimeString>
|
||||
</ram:IssueDateTime>
|
||||
</rsm:ExchangedDocument>
|
||||
<rsm:SupplyChainTradeTransaction xmlns:qdt="urn:un:unece:uncefact:data:standard:QualifiedDataType:100">
|
||||
<ram:IncludedSupplyChainTradeLineItem>
|
||||
<ram:AssociatedDocumentLineDocument>
|
||||
<ram:LineID>1</ram:LineID>
|
||||
</ram:AssociatedDocumentLineDocument>
|
||||
<ram:SpecifiedTradeProduct>
|
||||
<ram:Name>Künstlerische Gestaltung (Stunde): Einer Beispielrechnung</ram:Name>
|
||||
<ram:Description/>
|
||||
</ram:SpecifiedTradeProduct>
|
||||
<ram:SpecifiedLineTradeAgreement>
|
||||
<ram:GrossPriceProductTradePrice>
|
||||
<ram:ChargeAmount currencyID="EUR">160.0000</ram:ChargeAmount>
|
||||
<ram:BasisQuantity unitCode="HUR">1.0000</ram:BasisQuantity>
|
||||
</ram:GrossPriceProductTradePrice>
|
||||
<ram:NetPriceProductTradePrice>
|
||||
<ram:ChargeAmount currencyID="EUR">160.0000</ram:ChargeAmount>
|
||||
<ram:BasisQuantity unitCode="HUR">1.0000</ram:BasisQuantity>
|
||||
</ram:NetPriceProductTradePrice>
|
||||
</ram:SpecifiedLineTradeAgreement>
|
||||
<ram:SpecifiedLineTradeDelivery>
|
||||
<ram:BilledQuantity unitCode="HUR">1.0000</ram:BilledQuantity>
|
||||
</ram:SpecifiedLineTradeDelivery>
|
||||
<ram:SpecifiedLineTradeSettlement>
|
||||
<ram:ApplicableTradeTax>
|
||||
<ram:TypeCode>VAT</ram:TypeCode>
|
||||
<ram:CategoryCode>S</ram:CategoryCode>
|
||||
<ram:RateApplicablePercent>7.00</ram:RateApplicablePercent>
|
||||
</ram:ApplicableTradeTax>
|
||||
<ram:SpecifiedTradeSettlementLineMonetarySummation>
|
||||
<ram:LineTotalAmount currencyID="EUR">160.00</ram:LineTotalAmount>
|
||||
</ram:SpecifiedTradeSettlementLineMonetarySummation>
|
||||
</ram:SpecifiedLineTradeSettlement>
|
||||
</ram:IncludedSupplyChainTradeLineItem>
|
||||
<ram:IncludedSupplyChainTradeLineItem>
|
||||
<ram:AssociatedDocumentLineDocument>
|
||||
<ram:LineID>2</ram:LineID>
|
||||
</ram:AssociatedDocumentLineDocument>
|
||||
<ram:SpecifiedTradeProduct>
|
||||
<ram:Name>Luftballon: Bunt, ca. 500ml</ram:Name>
|
||||
<ram:Description/>
|
||||
</ram:SpecifiedTradeProduct>
|
||||
<ram:SpecifiedLineTradeAgreement>
|
||||
<ram:GrossPriceProductTradePrice>
|
||||
<ram:ChargeAmount currencyID="EUR">0.7900</ram:ChargeAmount>
|
||||
<ram:BasisQuantity unitCode="C62">1.0000</ram:BasisQuantity>
|
||||
</ram:GrossPriceProductTradePrice>
|
||||
<ram:NetPriceProductTradePrice>
|
||||
<ram:ChargeAmount currencyID="EUR">0.7900</ram:ChargeAmount>
|
||||
<ram:BasisQuantity unitCode="C62">1.0000</ram:BasisQuantity>
|
||||
</ram:NetPriceProductTradePrice>
|
||||
</ram:SpecifiedLineTradeAgreement>
|
||||
<ram:SpecifiedLineTradeDelivery>
|
||||
<ram:BilledQuantity unitCode="C62">400.0000</ram:BilledQuantity>
|
||||
</ram:SpecifiedLineTradeDelivery>
|
||||
<ram:SpecifiedLineTradeSettlement>
|
||||
<ram:ApplicableTradeTax>
|
||||
<ram:TypeCode>VAT</ram:TypeCode>
|
||||
<ram:CategoryCode>S</ram:CategoryCode>
|
||||
<ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>
|
||||
</ram:ApplicableTradeTax>
|
||||
<ram:SpecifiedTradeSettlementLineMonetarySummation>
|
||||
<ram:LineTotalAmount currencyID="EUR">316.00</ram:LineTotalAmount>
|
||||
</ram:SpecifiedTradeSettlementLineMonetarySummation>
|
||||
</ram:SpecifiedLineTradeSettlement>
|
||||
</ram:IncludedSupplyChainTradeLineItem>
|
||||
<ram:IncludedSupplyChainTradeLineItem>
|
||||
<ram:AssociatedDocumentLineDocument>
|
||||
<ram:LineID>3</ram:LineID>
|
||||
</ram:AssociatedDocumentLineDocument>
|
||||
<ram:SpecifiedTradeProduct>
|
||||
<ram:Name>Heiße Luft pro Liter</ram:Name>
|
||||
<ram:Description/>
|
||||
</ram:SpecifiedTradeProduct>
|
||||
<ram:SpecifiedLineTradeAgreement>
|
||||
<ram:GrossPriceProductTradePrice>
|
||||
<ram:ChargeAmount currencyID="EUR">0.1000</ram:ChargeAmount>
|
||||
<ram:BasisQuantity unitCode="LTR">1.0000</ram:BasisQuantity>
|
||||
</ram:GrossPriceProductTradePrice>
|
||||
<ram:NetPriceProductTradePrice>
|
||||
<ram:ChargeAmount currencyID="EUR">0.1000</ram:ChargeAmount>
|
||||
<ram:BasisQuantity unitCode="LTR">1.0000</ram:BasisQuantity>
|
||||
</ram:NetPriceProductTradePrice>
|
||||
</ram:SpecifiedLineTradeAgreement>
|
||||
<ram:SpecifiedLineTradeDelivery>
|
||||
<ram:BilledQuantity unitCode="LTR">200.0000</ram:BilledQuantity>
|
||||
</ram:SpecifiedLineTradeDelivery>
|
||||
<ram:SpecifiedLineTradeSettlement>
|
||||
<ram:ApplicableTradeTax>
|
||||
<ram:TypeCode>VAT</ram:TypeCode>
|
||||
<ram:CategoryCode>S</ram:CategoryCode>
|
||||
<ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>
|
||||
</ram:ApplicableTradeTax>
|
||||
<ram:SpecifiedTradeSettlementLineMonetarySummation>
|
||||
<ram:LineTotalAmount currencyID="EUR">20.00</ram:LineTotalAmount>
|
||||
</ram:SpecifiedTradeSettlementLineMonetarySummation>
|
||||
</ram:SpecifiedLineTradeSettlement>
|
||||
</ram:IncludedSupplyChainTradeLineItem>
|
||||
<ram:ApplicableHeaderTradeAgreement>
|
||||
<ram:SellerTradeParty>
|
||||
<ram:Name>Bei Spiel GmbH</ram:Name>
|
||||
<ram:PostalTradeAddress>
|
||||
<ram:PostcodeCode>12345</ram:PostcodeCode>
|
||||
<ram:LineOne>Ecke 12</ram:LineOne>
|
||||
<ram:CityName>Stadthausen</ram:CityName>
|
||||
<ram:CountryID>DE</ram:CountryID>
|
||||
</ram:PostalTradeAddress>
|
||||
<ram:SpecifiedTaxRegistration>
|
||||
<ram:ID schemeID="FC">22/815/0815/4</ram:ID>
|
||||
</ram:SpecifiedTaxRegistration>
|
||||
<ram:SpecifiedTaxRegistration>
|
||||
<ram:ID schemeID="VA">DE136695976</ram:ID>
|
||||
</ram:SpecifiedTaxRegistration>
|
||||
</ram:SellerTradeParty>
|
||||
<ram:BuyerTradeParty>
|
||||
<ram:Name>Theodor Est</ram:Name>
|
||||
<ram:PostalTradeAddress>
|
||||
<ram:PostcodeCode>88802</ram:PostcodeCode>
|
||||
<ram:LineOne>Bahnstr. 42</ram:LineOne>
|
||||
<ram:CityName>Spielkreis</ram:CityName>
|
||||
<ram:CountryID>DE</ram:CountryID>
|
||||
</ram:PostalTradeAddress>
|
||||
<ram:SpecifiedTaxRegistration>
|
||||
<ram:ID schemeID="VA">DE999999999</ram:ID>
|
||||
</ram:SpecifiedTaxRegistration>
|
||||
</ram:BuyerTradeParty>
|
||||
</ram:ApplicableHeaderTradeAgreement>
|
||||
<ram:ApplicableHeaderTradeDelivery>
|
||||
<ram:ActualDeliverySupplyChainEvent>
|
||||
<ram:OccurrenceDateTime>
|
||||
<udt:DateTimeString format="102">20170507</udt:DateTimeString>
|
||||
</ram:OccurrenceDateTime>
|
||||
</ram:ActualDeliverySupplyChainEvent>
|
||||
</ram:ApplicableHeaderTradeDelivery>
|
||||
<ram:ApplicableHeaderTradeSettlement>
|
||||
<ram:PaymentReference>RE-20170509/505</ram:PaymentReference>
|
||||
<ram:InvoiceCurrencyCode>EUR</ram:InvoiceCurrencyCode>
|
||||
<ram:SpecifiedTradeSettlementPaymentMeans>
|
||||
<ram:TypeCode>42</ram:TypeCode>
|
||||
<ram:Information>Überweisung</ram:Information>
|
||||
<ram:PayeePartyCreditorFinancialAccount>
|
||||
<ram:IBANID>DE88 2008 0000 0970 3757 00</ram:IBANID>
|
||||
<ram:ProprietaryID>44421800</ram:ProprietaryID>
|
||||
</ram:PayeePartyCreditorFinancialAccount>
|
||||
<ram:PayeeSpecifiedCreditorFinancialInstitution>
|
||||
<ram:BICID>COBADEFFXXX</ram:BICID>
|
||||
<ram:GermanBankleitzahlID>41441604</ram:GermanBankleitzahlID>
|
||||
<ram:Name>Commerzbank</ram:Name>
|
||||
</ram:PayeeSpecifiedCreditorFinancialInstitution>
|
||||
</ram:SpecifiedTradeSettlementPaymentMeans>
|
||||
<ram:ApplicableTradeTax>
|
||||
<ram:CalculatedAmount currencyID="EUR">11.20</ram:CalculatedAmount>
|
||||
<ram:TypeCode>VAT</ram:TypeCode>
|
||||
<ram:BasisAmount currencyID="EUR">160.00</ram:BasisAmount>
|
||||
<ram:CategoryCode>S</ram:CategoryCode>
|
||||
<ram:RateApplicablePercent>7.00</ram:RateApplicablePercent>
|
||||
</ram:ApplicableTradeTax>
|
||||
<ram:ApplicableTradeTax>
|
||||
<ram:CalculatedAmount currencyID="EUR">63.84</ram:CalculatedAmount>
|
||||
<ram:TypeCode>VAT</ram:TypeCode>
|
||||
<ram:BasisAmount currencyID="EUR">336.00</ram:BasisAmount>
|
||||
<ram:CategoryCode>S</ram:CategoryCode>
|
||||
<ram:RateApplicablePercent>19.00</ram:RateApplicablePercent>
|
||||
</ram:ApplicableTradeTax>
|
||||
<ram:SpecifiedTradePaymentTerms>
|
||||
<ram:Description>Zahlbar ohne Abzug bis zum 30.05.2017</ram:Description>
|
||||
<ram:DueDateDateTime>
|
||||
<udt:DateTimeString format="102">20170530</udt:DateTimeString>
|
||||
</ram:DueDateDateTime>
|
||||
</ram:SpecifiedTradePaymentTerms>
|
||||
<ram:SpecifiedTradeSettlementHeaderMonetarySummation>
|
||||
<ram:LineTotalAmount currencyID="EUR">496.00</ram:LineTotalAmount>
|
||||
<ram:ChargeTotalAmount currencyID="EUR">0.00</ram:ChargeTotalAmount>
|
||||
<ram:AllowanceTotalAmount currencyID="EUR">0.00</ram:AllowanceTotalAmount>
|
||||
<ram:TaxBasisTotalAmount currencyID="EUR">496.00</ram:TaxBasisTotalAmount>
|
||||
<ram:TaxTotalAmount currencyID="EUR">75.04</ram:TaxTotalAmount>
|
||||
<ram:GrandTotalAmount currencyID="EUR">571.04</ram:GrandTotalAmount>
|
||||
<ram:DuePayableAmount currencyID="EUR">571.04</ram:DuePayableAmount>
|
||||
</ram:SpecifiedTradeSettlementHeaderMonetarySummation>
|
||||
</ram:ApplicableHeaderTradeSettlement>
|
||||
</rsm:SupplyChainTradeTransaction>
|
||||
</rsm:CrossIndustryInvoice>
|
||||
|
||||
@@ -30,6 +30,7 @@ package org.mustangproject.ZUGFeRD;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
|
||||
import org.mustangproject.FileAttachment;
|
||||
import org.mustangproject.ZUGFeRD.model.DocumentCodeTypeConstants;
|
||||
|
||||
public interface IExportableTransaction {
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
package org.mustangproject.ZUGFeRD;
|
||||
|
||||
import javax.xml.transform.*;
|
||||
import javax.xml.transform.stream.StreamResult;
|
||||
import javax.xml.transform.stream.StreamSource;
|
||||
import java.io.*;
|
||||
|
||||
|
||||
/***
|
||||
* Uses a XSLT transformation to upgrade
|
||||
* from ZUGFeRD 1 to ZUGFeRD 2 (=Factur-X1 ˜= XRechnung)
|
||||
* This is an external functionality of the software and not very complete, for
|
||||
* internal operations (generation of ZF2) of course the ZF2PullProvider is used
|
||||
*/
|
||||
public class XMLUpgrader {
|
||||
|
||||
static final ClassLoader CLASS_LOADER = XMLUpgrader.class.getClassLoader();
|
||||
private static final String RESOURCE_PATH = ""; //$NON-NLS-1$
|
||||
private TransformerFactory mFactory = null;
|
||||
private Templates mXsltTemplate = null;
|
||||
|
||||
public XMLUpgrader() {
|
||||
mFactory = new net.sf.saxon.TransformerFactoryImpl();
|
||||
//fact = TransformerFactory.newInstance();
|
||||
mFactory.setURIResolver(new ClasspathResourceURIResolver());
|
||||
}
|
||||
|
||||
/***
|
||||
* Takes a filename of a ZF1 XML file and returns the string of ZF2 XML
|
||||
* @param xmlFilename
|
||||
* @return String the updated XML
|
||||
* @throws FileNotFoundException
|
||||
* @throws TransformerException
|
||||
* @throws UnsupportedEncodingException
|
||||
*/
|
||||
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
|
||||
*/
|
||||
mXsltTemplate = mFactory.newTemplates(new StreamSource(CLASS_LOADER.getResourceAsStream(RESOURCE_PATH + "stylesheets/ZF1ToZF2.xsl")));
|
||||
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
applySchematronXsl(new FileInputStream(xmlFilename), baos);
|
||||
String res = null;
|
||||
res = baos.toString("UTF-8");
|
||||
return res;
|
||||
}
|
||||
|
||||
protected 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,11 +30,13 @@ import java.util.HashMap;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
import com.sun.org.apache.xerces.internal.impl.dv.util.Base64;
|
||||
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.FileAttachment;
|
||||
import org.mustangproject.Invoice;
|
||||
import org.mustangproject.XMLTools;
|
||||
|
||||
@@ -496,13 +498,13 @@ public class ZUGFeRD2PullProvider implements IXMLProvider, IAbsoluteValueProvide
|
||||
// Additional Documents of XRechnung (Rechnungsbegruendende Unterlagen - BG-24 XRechnung)
|
||||
if (trans.getAdditionalReferencedDocuments() != null) {
|
||||
for (FileAttachment f : trans.getAdditionalReferencedDocuments()) {
|
||||
final String documentContent = Base64.encodeBase64String(f.getData());
|
||||
// final String documentContent = Base64.encodeBase64String(f.getData());
|
||||
xml = xml + " <ram:AdditionalReferencedDocument>\n"
|
||||
+ " <ram:IssuerAssignedID>" + f.getFilename() + "</ram:IssuerAssignedID>\n"
|
||||
+ " <ram:TypeCode>916</ram:TypeCode>\n"
|
||||
+ " <ram:Name>" + f.getDescription() + "</ram:Name>\n"
|
||||
+ " <ram:AttachmentBinaryObject mimeCode=\"" + f.getMimetype() + "\"\n"
|
||||
+ " filename=\"" + f.getFilename() + ">" + documentContent + "\n"
|
||||
// + " filename=\"" + f.getFilename() + ">" + documentContent + "\n"
|
||||
+ " </ram:AdditionalReferencedDocument>\n";
|
||||
}
|
||||
}
|
||||
|
||||
343
library/src/main/resources/stylesheets/ZF1ToZF2.xsl
Normal file
343
library/src/main/resources/stylesheets/ZF1ToZF2.xsl
Normal file
@@ -0,0 +1,343 @@
|
||||
<!--
|
||||
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.
|
||||
-->
|
||||
<!--
|
||||
This XSL transformation will attempt to migrate from ZF1 (which was a customized UN/CEFACT CII 2013b) to ZF2
|
||||
(which is vanilla UN/CEFACT CII 2016b).
|
||||
|
||||
In general, some elements have been renamed and with many elements the sequence of the sub-elements is now defined
|
||||
-->
|
||||
<xsl:stylesheet version="2.0"
|
||||
xpath-default-namespace="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100"
|
||||
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"
|
||||
exclude-result-prefixes="qdt"
|
||||
>
|
||||
<!-- 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"/>
|
||||
|
||||
|
||||
<xsl:template
|
||||
name="search-and-replace"><!-- quelle: https://www.data2type.de/xml-xslt-xslfo/xslt/xslt-kochbuch/strings/text-ersetzen/ , replace does not work in MSXML... -->
|
||||
<xsl:param name="input"/>
|
||||
<xsl:param name="search-string"/>
|
||||
<xsl:param name="replace-string"/>
|
||||
<xsl:choose>
|
||||
<!-- Feststellen, ob die Eingabe den Suchstring enthält -->
|
||||
<xsl:when test="$search-string and contains($input,$search-string)">
|
||||
<!-- Ist dies der Fall, dann Verkettung des Teilstrings vor dem Suchstring mit dem Ersatzstring und mit dem Ergebnis der rekursiven Anwendung dieses Templates mit dem verbleibenden Teilstring. -->
|
||||
<xsl:value-of select="substring-before($input,$search-string)"/>
|
||||
<xsl:value-of select="$replace-string"/>
|
||||
<xsl:call-template name="search-and-replace">
|
||||
<xsl:with-param name="input" select="substring-after($input,$search-string)"/>
|
||||
<xsl:with-param name="search-string" select="$search-string"/>
|
||||
<xsl:with-param name="replace-string" select="$replace-string"/>
|
||||
</xsl:call-template>
|
||||
</xsl:when>
|
||||
<xsl:otherwise>
|
||||
<!-- Keine weiteren Vorkommen des Suchstrings, daher einfach Rückgabe des aktuellen Eingabestrings -->
|
||||
<xsl:value-of select="$input"/>
|
||||
</xsl:otherwise>
|
||||
</xsl:choose>
|
||||
</xsl:template>
|
||||
|
||||
|
||||
<!-- 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: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() = 'GuidelineSpecifiedDocumentContextParameter']/*[local-name() = 'ID']">
|
||||
<!--
|
||||
We need to replace the old ZF1 guideline IDs (=profiles) with the new ones:
|
||||
''' urn:ferd:CrossIndustryDocument:invoice:1p0:basic -> urn:cen.eu:en16931:2017#compliant#urn:factur-x.eu:1p0:basic
|
||||
''' urn:ferd:CrossIndustryDocument:invoice:1p0:comfort -> urn:cen.eu:en16931:2017
|
||||
''' urn:ferd:CrossIndustryDocument:invoice:1p0:extended -> urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended
|
||||
|
||||
-->
|
||||
<ram:ID>
|
||||
|
||||
|
||||
<xsl:variable name="correctedBasic">
|
||||
<xsl:call-template name="search-and-replace">
|
||||
<xsl:with-param name="input" select="./text()"/>
|
||||
<xsl:with-param name="search-string" select="'urn:ferd:CrossIndustryDocument:invoice:1p0:basic'"/>
|
||||
<xsl:with-param name="replace-string"
|
||||
select="'urn:cen.eu:en16931:2017#compliant#urn:factur-x.eu:1p0:basic'"/>
|
||||
</xsl:call-template>
|
||||
</xsl:variable>
|
||||
|
||||
<xsl:variable name="alsoCorrectedComfort">
|
||||
<xsl:call-template name="search-and-replace">
|
||||
<xsl:with-param name="input" select="$correctedBasic"/>
|
||||
<xsl:with-param name="search-string" select="'urn:ferd:CrossIndustryDocument:invoice:1p0:comfort'"/>
|
||||
<xsl:with-param name="replace-string" select="'urn:cen.eu:en16931:2017'"/>
|
||||
</xsl:call-template>
|
||||
</xsl:variable>
|
||||
|
||||
<xsl:call-template name="search-and-replace">
|
||||
<xsl:with-param name="input" select="$alsoCorrectedComfort"/>
|
||||
<xsl:with-param name="search-string" select="'urn:ferd:CrossIndustryDocument:invoice:1p0:extended'"/>
|
||||
<xsl:with-param name="replace-string"
|
||||
select="'urn:cen.eu:en16931:2017#conformant#urn:factur-x.eu:1p0:extended'"/>
|
||||
</xsl:call-template>
|
||||
|
||||
</ram:ID>
|
||||
</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>
|
||||
Reference in New Issue
Block a user