Merge branch 'master' of github.com:ZUGFeRD/mustangproject
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -6,6 +6,7 @@ target/
|
|||||||
pom.xml.*
|
pom.xml.*
|
||||||
bin/
|
bin/
|
||||||
/.gradle/
|
/.gradle/
|
||||||
|
log/
|
||||||
|
|
||||||
# ignore intelliJ foobar
|
# ignore intelliJ foobar
|
||||||
*.iml
|
*.iml
|
||||||
|
|||||||
@@ -181,6 +181,19 @@
|
|||||||
</execution>
|
</execution>
|
||||||
</executions>
|
</executions>
|
||||||
</plugin>
|
</plugin>
|
||||||
|
<plugin>
|
||||||
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
<artifactId>maven-failsafe-plugin</artifactId>
|
||||||
|
<version>2.22.2</version>
|
||||||
|
<executions>
|
||||||
|
<execution>
|
||||||
|
<goals>
|
||||||
|
<goal>integration-test</goal>
|
||||||
|
<goal>verify</goal>
|
||||||
|
</goals>
|
||||||
|
</execution>
|
||||||
|
</executions>
|
||||||
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
<licenses>
|
<licenses>
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package org.mustangproject.commandline;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.io.BufferedReader;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStreamReader;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
|
public class CliIT {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCii2Ubl() throws Exception {
|
||||||
|
Path output = Paths.get("target/ubl.xml");
|
||||||
|
Files.deleteIfExists(output);
|
||||||
|
Path jar = Files.newDirectoryStream(Paths.get("target"), "Mustang-CLI-*.jar").iterator().next();
|
||||||
|
ProcessBuilder pb = new ProcessBuilder("java", "-jar", jar.toString(),
|
||||||
|
"--action", "ubl", "--source", "src/test/resources/cii.xml", "--out",
|
||||||
|
output.toString());
|
||||||
|
pb.redirectErrorStream(true);
|
||||||
|
Process process = pb.start();
|
||||||
|
String result = getOutput(process);
|
||||||
|
process.waitFor(10, TimeUnit.SECONDS);
|
||||||
|
if (!result.isEmpty()) {
|
||||||
|
System.out.println(result);
|
||||||
|
}
|
||||||
|
assertTrue(new String(Files.readAllBytes(output), StandardCharsets.UTF_8).contains("Invoice"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getOutput(Process process) throws IOException {
|
||||||
|
BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
String line;
|
||||||
|
while ((line = reader.readLine()) != null) {
|
||||||
|
builder.append(line);
|
||||||
|
builder.append(System.getProperty("line.separator"));
|
||||||
|
}
|
||||||
|
return builder.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
191
Mustang-CLI/src/test/resources/cii.xml
Normal file
191
Mustang-CLI/src/test/resources/cii.xml
Normal file
@@ -0,0 +1,191 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
|
||||||
|
<rsm:CrossIndustryInvoice xmlns:rsm="urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:ram="urn:un:unece:uncefact:data:standard:ReusableAggregateBusinessInformationEntity:100" xmlns:udt="urn:un:unece:uncefact:data:standard:UnqualifiedDataType:100">
|
||||||
|
<rsm:ExchangedDocumentContext>
|
||||||
|
<ram:GuidelineSpecifiedDocumentContextParameter>
|
||||||
|
<ram:ID>urn:cen.eu:en16931:2017</ram:ID>
|
||||||
|
</ram:GuidelineSpecifiedDocumentContextParameter>
|
||||||
|
</rsm:ExchangedDocumentContext>
|
||||||
|
<rsm:ExchangedDocument>
|
||||||
|
<ram:ID>RE-20201121/508</ram:ID>
|
||||||
|
<ram:TypeCode>380</ram:TypeCode>
|
||||||
|
<ram:IssueDateTime>
|
||||||
|
<udt:DateTimeString format="102">20201121</udt:DateTimeString>
|
||||||
|
</ram:IssueDateTime>
|
||||||
|
</rsm:ExchangedDocument>
|
||||||
|
<rsm:SupplyChainTradeTransaction>
|
||||||
|
<ram:IncludedSupplyChainTradeLineItem>
|
||||||
|
<ram:AssociatedDocumentLineDocument>
|
||||||
|
<ram:LineID>1</ram:LineID>
|
||||||
|
</ram:AssociatedDocumentLineDocument>
|
||||||
|
<ram:SpecifiedTradeProduct>
|
||||||
|
<ram:Name>Design (hours)</ram:Name>
|
||||||
|
<ram:Description>Of a sample invoice</ram:Description>
|
||||||
|
</ram:SpecifiedTradeProduct>
|
||||||
|
<ram:SpecifiedLineTradeAgreement>
|
||||||
|
<ram:GrossPriceProductTradePrice>
|
||||||
|
<ram:ChargeAmount>160.0000</ram:ChargeAmount>
|
||||||
|
<ram:BasisQuantity unitCode="HUR">1.0000</ram:BasisQuantity>
|
||||||
|
</ram:GrossPriceProductTradePrice>
|
||||||
|
<ram:NetPriceProductTradePrice>
|
||||||
|
<ram:ChargeAmount>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>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>Ballons</ram:Name>
|
||||||
|
<ram:Description>various colors, ~2000ml</ram:Description>
|
||||||
|
</ram:SpecifiedTradeProduct>
|
||||||
|
<ram:SpecifiedLineTradeAgreement>
|
||||||
|
<ram:GrossPriceProductTradePrice>
|
||||||
|
<ram:ChargeAmount>0.7900</ram:ChargeAmount>
|
||||||
|
<ram:BasisQuantity unitCode="H87">1.0000</ram:BasisQuantity>
|
||||||
|
</ram:GrossPriceProductTradePrice>
|
||||||
|
<ram:NetPriceProductTradePrice>
|
||||||
|
<ram:ChargeAmount>0.7900</ram:ChargeAmount>
|
||||||
|
<ram:BasisQuantity unitCode="H87">1.0000</ram:BasisQuantity>
|
||||||
|
</ram:NetPriceProductTradePrice>
|
||||||
|
</ram:SpecifiedLineTradeAgreement>
|
||||||
|
<ram:SpecifiedLineTradeDelivery>
|
||||||
|
<ram:BilledQuantity unitCode="H87">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>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>Hot air „heiße Luft“ (litres)</ram:Name>
|
||||||
|
<ram:Description/>
|
||||||
|
</ram:SpecifiedTradeProduct>
|
||||||
|
<ram:SpecifiedLineTradeAgreement>
|
||||||
|
<ram:GrossPriceProductTradePrice>
|
||||||
|
<ram:ChargeAmount>0.0250</ram:ChargeAmount>
|
||||||
|
<ram:BasisQuantity unitCode="LTR">1.0000</ram:BasisQuantity>
|
||||||
|
</ram:GrossPriceProductTradePrice>
|
||||||
|
<ram:NetPriceProductTradePrice>
|
||||||
|
<ram:ChargeAmount>0.0250</ram:ChargeAmount>
|
||||||
|
<ram:BasisQuantity unitCode="LTR">1.0000</ram:BasisQuantity>
|
||||||
|
</ram:NetPriceProductTradePrice>
|
||||||
|
</ram:SpecifiedLineTradeAgreement>
|
||||||
|
<ram:SpecifiedLineTradeDelivery>
|
||||||
|
<ram:BilledQuantity unitCode="LTR">800.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>20.00</ram:LineTotalAmount>
|
||||||
|
</ram:SpecifiedTradeSettlementLineMonetarySummation>
|
||||||
|
</ram:SpecifiedLineTradeSettlement>
|
||||||
|
</ram:IncludedSupplyChainTradeLineItem>
|
||||||
|
<ram:ApplicableHeaderTradeAgreement>
|
||||||
|
<ram:BuyerReference>AB321</ram:BuyerReference>
|
||||||
|
<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="VA">DE136695976</ram:ID>
|
||||||
|
</ram:SpecifiedTaxRegistration>
|
||||||
|
</ram:SellerTradeParty>
|
||||||
|
<ram:BuyerTradeParty>
|
||||||
|
<ram:ID>2</ram:ID>
|
||||||
|
<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:BuyerTradeParty>
|
||||||
|
</ram:ApplicableHeaderTradeAgreement>
|
||||||
|
<ram:ApplicableHeaderTradeDelivery>
|
||||||
|
<ram:ActualDeliverySupplyChainEvent>
|
||||||
|
<ram:OccurrenceDateTime>
|
||||||
|
<udt:DateTimeString format="102">20201110</udt:DateTimeString>
|
||||||
|
</ram:OccurrenceDateTime>
|
||||||
|
</ram:ActualDeliverySupplyChainEvent>
|
||||||
|
</ram:ApplicableHeaderTradeDelivery>
|
||||||
|
<ram:ApplicableHeaderTradeSettlement>
|
||||||
|
<ram:PaymentReference>RE-20201121/508</ram:PaymentReference>
|
||||||
|
<ram:InvoiceCurrencyCode>EUR</ram:InvoiceCurrencyCode>
|
||||||
|
<ram:SpecifiedTradeSettlementPaymentMeans>
|
||||||
|
<ram:TypeCode>42</ram:TypeCode>
|
||||||
|
<ram:Information>Bank transfer</ram:Information>
|
||||||
|
<ram:PayeePartyCreditorFinancialAccount>
|
||||||
|
<ram:IBANID>DE88200800000970375700</ram:IBANID>
|
||||||
|
<ram:AccountName>Max Mustermann</ram:AccountName>
|
||||||
|
</ram:PayeePartyCreditorFinancialAccount>
|
||||||
|
<ram:PayeeSpecifiedCreditorFinancialInstitution>
|
||||||
|
<ram:BICID>COBADEFFXXX</ram:BICID>
|
||||||
|
</ram:PayeeSpecifiedCreditorFinancialInstitution>
|
||||||
|
</ram:SpecifiedTradeSettlementPaymentMeans>
|
||||||
|
<ram:ApplicableTradeTax>
|
||||||
|
<ram:CalculatedAmount>11.20</ram:CalculatedAmount>
|
||||||
|
<ram:TypeCode>VAT</ram:TypeCode>
|
||||||
|
<ram:BasisAmount>160.00</ram:BasisAmount>
|
||||||
|
<ram:CategoryCode>S</ram:CategoryCode>
|
||||||
|
<ram:RateApplicablePercent>7.00</ram:RateApplicablePercent>
|
||||||
|
</ram:ApplicableTradeTax>
|
||||||
|
<ram:ApplicableTradeTax>
|
||||||
|
<ram:CalculatedAmount>63.84</ram:CalculatedAmount>
|
||||||
|
<ram:TypeCode>VAT</ram:TypeCode>
|
||||||
|
<ram:BasisAmount>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 12.12.2020</ram:Description>
|
||||||
|
<ram:DueDateDateTime>
|
||||||
|
<udt:DateTimeString format="102">20201212</udt:DateTimeString>
|
||||||
|
</ram:DueDateDateTime>
|
||||||
|
</ram:SpecifiedTradePaymentTerms>
|
||||||
|
<ram:SpecifiedTradeSettlementHeaderMonetarySummation>
|
||||||
|
<ram:LineTotalAmount>496.00</ram:LineTotalAmount>
|
||||||
|
<ram:ChargeTotalAmount>0.00</ram:ChargeTotalAmount>
|
||||||
|
<ram:AllowanceTotalAmount>0.00</ram:AllowanceTotalAmount>
|
||||||
|
<ram:TaxBasisTotalAmount>496.00</ram:TaxBasisTotalAmount>
|
||||||
|
<ram:TaxTotalAmount currencyID="EUR">75.04</ram:TaxTotalAmount>
|
||||||
|
<ram:GrandTotalAmount>571.04</ram:GrandTotalAmount>
|
||||||
|
<ram:TotalPrepaidAmount>0.00</ram:TotalPrepaidAmount>
|
||||||
|
<ram:DuePayableAmount>571.04</ram:DuePayableAmount>
|
||||||
|
</ram:SpecifiedTradeSettlementHeaderMonetarySummation>
|
||||||
|
</ram:ApplicableHeaderTradeSettlement>
|
||||||
|
</rsm:SupplyChainTradeTransaction>
|
||||||
|
</rsm:CrossIndustryInvoice>
|
||||||
@@ -122,6 +122,7 @@
|
|||||||
<groupId>org.xmlunit</groupId>
|
<groupId>org.xmlunit</groupId>
|
||||||
<artifactId>xmlunit-assertj</artifactId>
|
<artifactId>xmlunit-assertj</artifactId>
|
||||||
<version>2.6.3</version>
|
<version>2.6.3</version>
|
||||||
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- API -->
|
<!-- API -->
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -153,7 +154,7 @@
|
|||||||
<artifactId>maven-shade-plugin</artifactId>
|
<artifactId>maven-shade-plugin</artifactId>
|
||||||
<version>3.2.1</version>
|
<version>3.2.1</version>
|
||||||
<configuration>
|
<configuration>
|
||||||
<shadedArtifactAttached>false</shadedArtifactAttached>
|
<shadedArtifactAttached>true</shadedArtifactAttached>
|
||||||
<minimizeJar>false</minimizeJar><!-- no longer java 11 compatible if set to true because it removes e.g. javax/xml/bind/annotation/XmlSchema-->
|
<minimizeJar>false</minimizeJar><!-- no longer java 11 compatible if set to true because it removes e.g. javax/xml/bind/annotation/XmlSchema-->
|
||||||
<filters>
|
<filters>
|
||||||
|
|
||||||
|
|||||||
@@ -57,4 +57,31 @@ public class Profiles {
|
|||||||
return getByName(name, ZUGFeRDExporterFromA3.DefaultZUGFeRDVersion);
|
return getByName(name, ZUGFeRDExporterFromA3.DefaultZUGFeRDVersion);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Obtains a profile by name, disregarding version. First searches among
|
||||||
|
* 1.x profiles and fatre that among 2.x profiles.
|
||||||
|
*
|
||||||
|
* @param name profile name to search for
|
||||||
|
*
|
||||||
|
* @return a profile matching the requested name
|
||||||
|
*/
|
||||||
|
public static Profile getByNameDisregardingVersion(String name)
|
||||||
|
{
|
||||||
|
Profile result = null;
|
||||||
|
|
||||||
|
result = zf1Map.get(name.toUpperCase());
|
||||||
|
|
||||||
|
if (result == null)
|
||||||
|
{
|
||||||
|
result = zf2Map.get(name.toUpperCase());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result==null)
|
||||||
|
{
|
||||||
|
throw new RuntimeException("Profile " + name + " not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,8 +40,10 @@ public class XMPSchemaZugferd extends XMPSchema {
|
|||||||
* @param URN the xml URI for the XMP
|
* @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 prefix the xml namespace prefix for the XMP, zf for ZUGFeRD, fx for Factur-X
|
||||||
* @param filename the filename of the invoice
|
* @param filename the filename of the invoice
|
||||||
|
* @param version meta-data version to set. May be null, and then it is set automatically
|
||||||
*/
|
*/
|
||||||
public XMPSchemaZugferd(XMPMetadata metadata, int zfVersion, boolean isFacturX, Profile conformanceLevel, String URN, String prefix, String filename) {
|
public XMPSchemaZugferd(XMPMetadata metadata, int zfVersion, boolean isFacturX, Profile conformanceLevel,
|
||||||
|
String URN, String prefix, String filename, String version) {
|
||||||
super(metadata, URN, prefix, "ZUGFeRD Schema");
|
super(metadata, URN, prefix, "ZUGFeRD Schema");
|
||||||
|
|
||||||
setAboutAsSimple("");
|
setAboutAsSimple("");
|
||||||
@@ -50,9 +52,12 @@ public class XMPSchemaZugferd extends XMPSchema {
|
|||||||
setTextPropertyValue("ConformanceLevel", conformanceLevelValue);
|
setTextPropertyValue("ConformanceLevel", conformanceLevelValue);
|
||||||
setTextPropertyValue("DocumentType", "INVOICE");
|
setTextPropertyValue("DocumentType", "INVOICE");
|
||||||
setTextPropertyValue("DocumentFileName", filename);
|
setTextPropertyValue("DocumentFileName", filename);
|
||||||
String version="1.0";
|
|
||||||
if ((zfVersion==2)&&(!isFacturX)) {
|
if (version == null) {
|
||||||
version="2p0";
|
version = "1.0";
|
||||||
|
if ((zfVersion==2)&&(!isFacturX)) {
|
||||||
|
version="2p0";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
setTextPropertyValue("Version", version);
|
setTextPropertyValue("Version", version);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
|
|||||||
@Deprecated
|
@Deprecated
|
||||||
protected String subject;
|
protected String subject;
|
||||||
|
|
||||||
private PDDocument doc;
|
protected PDDocument doc;
|
||||||
|
|
||||||
private HashMap<String, byte[]> additionalXMLs = new HashMap<String, byte[]>();
|
private HashMap<String, byte[]> additionalXMLs = new HashMap<String, byte[]>();
|
||||||
|
|
||||||
@@ -116,6 +116,11 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
|
|||||||
protected int ZFVersion = DefaultZUGFeRDVersion;
|
protected int ZFVersion = DefaultZUGFeRDVersion;
|
||||||
private boolean attachZUGFeRDHeaders = true;
|
private boolean attachZUGFeRDHeaders = true;
|
||||||
|
|
||||||
|
// Specific metaData version in case of XRechnung. We need it to be settable
|
||||||
|
// by the caller if necessary.
|
||||||
|
protected String XRechnungVersion = null; // Default XRechnung as of late 2021 is 2p0
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Makes A PDF/A3a-compliant document from a PDF-A1 compliant document (on the
|
* 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)
|
* metadata level, this will not e.g. convert graphics to JPG-2000)
|
||||||
@@ -162,13 +167,18 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
|
|||||||
* @return the URN of the namespace
|
* @return the URN of the namespace
|
||||||
*/
|
*/
|
||||||
public String getNamespaceForVersion(int ver) {
|
public String getNamespaceForVersion(int ver) {
|
||||||
|
// In the case of XRechnung, it is the same as Factur-X
|
||||||
|
if ((ver >= 2) && (this.profile != null) &&
|
||||||
|
this.profile.getName().equalsIgnoreCase(Profiles.getByName("XRECHNUNG").getName()))
|
||||||
|
{
|
||||||
|
return "urn:factur-x:pdfa:CrossIndustryDocument:invoice:1p0#";
|
||||||
|
} else
|
||||||
if (isFacturX) {
|
if (isFacturX) {
|
||||||
return "urn:factur-x:pdfa:CrossIndustryDocument:invoice:1p0#";
|
return "urn:factur-x:pdfa:CrossIndustryDocument:invoice:1p0#";
|
||||||
} else if (ver == 1) {
|
} else if (ver == 1) {
|
||||||
return "urn:ferd:pdfa:CrossIndustryDocument:invoice:1p0#";
|
return "urn:ferd:pdfa:CrossIndustryDocument:invoice:1p0#";
|
||||||
} else if (ver == 2) {
|
} else if (ver == 2) {
|
||||||
return "urn:zugferd:pdfa:CrossIndustryDocument:invoice:2p0#";
|
return "urn:zugferd:pdfa:CrossIndustryDocument:invoice:2p0#";
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
throw new IllegalArgumentException("Version not supported");
|
throw new IllegalArgumentException("Version not supported");
|
||||||
}
|
}
|
||||||
@@ -180,6 +190,12 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
|
|||||||
* @return the namespace prefix as string, without colon
|
* @return the namespace prefix as string, without colon
|
||||||
*/
|
*/
|
||||||
public String getPrefixForVersion(int ver) {
|
public String getPrefixForVersion(int ver) {
|
||||||
|
// In the case of XRechnung, it is the same as Factur-X
|
||||||
|
if ((ver >= 2) && (this.profile != null) &&
|
||||||
|
this.profile.getName().equalsIgnoreCase(Profiles.getByName("XRECHNUNG").getName()))
|
||||||
|
{
|
||||||
|
return "fx";
|
||||||
|
} else
|
||||||
if (isFacturX) {
|
if (isFacturX) {
|
||||||
return "fx";
|
return "fx";
|
||||||
} else {
|
} else {
|
||||||
@@ -187,6 +203,7 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* internal helper: return the name of the file attachment for the given zf/fx version
|
* internal helper: return the name of the file attachment for the given zf/fx version
|
||||||
* @param ver the zf/fx version
|
* @param ver the zf/fx version
|
||||||
@@ -194,13 +211,17 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
|
|||||||
* @return the filename of the file to be embedded
|
* @return the filename of the file to be embedded
|
||||||
*/
|
*/
|
||||||
public String getFilenameForVersion(int ver, Profile profile) {
|
public String getFilenameForVersion(int ver, Profile profile) {
|
||||||
if (isFacturX) {
|
boolean isXRechnung =
|
||||||
|
(ver >= 2) && (this.profile != null) &&
|
||||||
|
this.profile.getName().equalsIgnoreCase(Profiles.getByName("XRECHNUNG").getName());
|
||||||
|
|
||||||
|
if (isFacturX && (!isXRechnung)) {
|
||||||
return "factur-x.xml";
|
return "factur-x.xml";
|
||||||
} else {
|
} else {
|
||||||
if (ver == 1) {
|
if (ver == 1) {
|
||||||
return "ZUGFeRD-invoice.xml";
|
return "ZUGFeRD-invoice.xml";
|
||||||
} else {
|
} else {
|
||||||
if (profile.getName().equals("XRECHNUNG")) {
|
if (isXRechnung) {
|
||||||
return "xrechnung.xml";
|
return "xrechnung.xml";
|
||||||
} else {
|
} else {
|
||||||
return "zugferd-invoice.xml";
|
return "zugferd-invoice.xml";
|
||||||
@@ -222,6 +243,19 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets a specific XRechnung version from outside. This version needs to be present in the
|
||||||
|
* meta-data as well. The caller may wish to generate a specific version of XRechnung
|
||||||
|
* depending on the time period etc.
|
||||||
|
*
|
||||||
|
* @param XRechnungVersion the XRechnung version
|
||||||
|
*/
|
||||||
|
public void setXRechnungSpecificVersion(String XRechnungVersion)
|
||||||
|
{
|
||||||
|
this.XRechnungVersion = XRechnungVersion;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* Generate ZF2.0/2.1 files with filename zugferd-invoice.xml instead of factur-x.xml
|
* Generate ZF2.0/2.1 files with filename zugferd-invoice.xml instead of factur-x.xml
|
||||||
*/
|
*/
|
||||||
@@ -302,6 +336,24 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Embeds an external file (generic - any type allowed) in the PDF.
|
||||||
|
* The embedding is done in the default PDF document.
|
||||||
|
*
|
||||||
|
* @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(String filename, String relationship, String description,
|
||||||
|
String subType, byte[] data) throws IOException {
|
||||||
|
PDFAttachGenericFile(this.doc, filename, relationship, description, subType, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Embeds an external file (generic - any type allowed) in the PDF.
|
* Embeds an external file (generic - any type allowed) in the PDF.
|
||||||
*
|
*
|
||||||
@@ -468,10 +520,19 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
|
|||||||
*/
|
*/
|
||||||
protected void addXMP(XMPMetadata metadata) {
|
protected void addXMP(XMPMetadata metadata) {
|
||||||
|
|
||||||
|
String metaDataVersion = null; // default will be used
|
||||||
|
|
||||||
|
// The XRechnung version may be settable from outside.
|
||||||
|
if ((this.XRechnungVersion != null) && (this.profile != null) &&
|
||||||
|
this.profile.getName().equalsIgnoreCase(Profiles.getByName("XRECHNUNG").getName()))
|
||||||
|
{
|
||||||
|
metaDataVersion = this.XRechnungVersion;
|
||||||
|
}
|
||||||
|
|
||||||
if (attachZUGFeRDHeaders) {
|
if (attachZUGFeRDHeaders) {
|
||||||
XMPSchemaZugferd zf = new XMPSchemaZugferd(metadata, ZFVersion, isFacturX, xmlProvider.getProfile(),
|
XMPSchemaZugferd zf = new XMPSchemaZugferd(metadata, ZFVersion, isFacturX, xmlProvider.getProfile(),
|
||||||
getNamespaceForVersion(ZFVersion), getPrefixForVersion(ZFVersion),
|
getNamespaceForVersion(ZFVersion), getPrefixForVersion(ZFVersion),
|
||||||
getFilenameForVersion(ZFVersion, xmlProvider.getProfile()));
|
getFilenameForVersion(ZFVersion, xmlProvider.getProfile()), metaDataVersion);
|
||||||
|
|
||||||
metadata.addSchema(zf);
|
metadata.addSchema(zf);
|
||||||
}
|
}
|
||||||
@@ -481,8 +542,9 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
|
|||||||
metadata.addSchema(pdfaex);
|
metadata.addSchema(pdfaex);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void removeCidSet(PDDocumentCatalog catalog, PDDocument doc) {
|
private void removeCidSet(PDDocumentCatalog catalog, PDDocument doc)
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
// https://github.com/ZUGFeRD/mustangproject/issues/249
|
// https://github.com/ZUGFeRD/mustangproject/issues/249
|
||||||
|
|
||||||
COSName cidSet = COSName.getPDFName("CIDSet");
|
COSName cidSet = COSName.getPDFName("CIDSet");
|
||||||
@@ -508,7 +570,7 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
e.printStackTrace();
|
throw e;
|
||||||
}
|
}
|
||||||
// do stuff with the font
|
// do stuff with the font
|
||||||
}
|
}
|
||||||
@@ -568,7 +630,21 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
|
|||||||
prepareDocument();
|
prepareDocument();
|
||||||
xmlProvider.generateXML(trans);
|
xmlProvider.generateXML(trans);
|
||||||
String filename = getFilenameForVersion(ZFVersion, xmlProvider.getProfile());
|
String filename = getFilenameForVersion(ZFVersion, xmlProvider.getProfile());
|
||||||
PDFAttachGenericFile(doc, filename, "Alternative",
|
|
||||||
|
String relationship = "Alternative";
|
||||||
|
// ZUGFeRD 2.1.1 Technical Supplement | Part A | 2.2.2. Data Relationship
|
||||||
|
// See documentation ZUGFeRD211_EN/Documentation/ZUGFeRD-2.1.1 - Specification_TA_Part-A.pdf
|
||||||
|
// https://www.ferd-net.de/standards/zugferd-2.1.1/index.html
|
||||||
|
if (ZFVersion >= 2)
|
||||||
|
{
|
||||||
|
if (this.profile.getName().equalsIgnoreCase(Profiles.getByName("MINIMUM").getName()) ||
|
||||||
|
this.profile.getName().equalsIgnoreCase(Profiles.getByName("BASICWL").getName()))
|
||||||
|
{
|
||||||
|
relationship = "Data";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PDFAttachGenericFile(doc, filename, relationship,
|
||||||
"Invoice metadata conforming to ZUGFeRD standard (http://www.ferd-net.de/front_content.php?idcat=231&lang=4)",
|
"Invoice metadata conforming to ZUGFeRD standard (http://www.ferd-net.de/front_content.php?idcat=231&lang=4)",
|
||||||
"text/xml", xmlProvider.getXML());
|
"text/xml", xmlProvider.getXML());
|
||||||
|
|
||||||
@@ -583,14 +659,16 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
|
|||||||
* Reads the XMPMetadata from the PDDocument, if it exists.
|
* Reads the XMPMetadata from the PDDocument, if it exists.
|
||||||
* Otherwise creates XMPMetadata.
|
* Otherwise creates XMPMetadata.
|
||||||
*/
|
*/
|
||||||
protected XMPMetadata getXmpMetadata() {
|
protected XMPMetadata getXmpMetadata()
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
PDMetadata meta = doc.getDocumentCatalog().getMetadata();
|
PDMetadata meta = doc.getDocumentCatalog().getMetadata();
|
||||||
if (meta != null) {
|
if ((meta != null) && (meta.getLength() > 0)) {
|
||||||
try {
|
try {
|
||||||
DomXmpParser xmpParser = new DomXmpParser();
|
DomXmpParser xmpParser = new DomXmpParser();
|
||||||
return xmpParser.parse(meta.toByteArray());
|
return xmpParser.parse(meta.toByteArray());
|
||||||
} catch (XmpParsingException | IOException e) {
|
} catch (XmpParsingException e) {
|
||||||
// TODO use logging or handle the error somehow
|
throw new IOException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return XMPMetadata.createXMPMetadata();
|
return XMPMetadata.createXMPMetadata();
|
||||||
@@ -724,7 +802,9 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
|
|||||||
/**
|
/**
|
||||||
* Adds an OutputIntent and the sRGB color profile if no OutputIntent exist
|
* Adds an OutputIntent and the sRGB color profile if no OutputIntent exist
|
||||||
*/
|
*/
|
||||||
protected void addSRGBOutputIntend() {
|
protected void addSRGBOutputIntend()
|
||||||
|
throws IOException
|
||||||
|
{
|
||||||
if (!doc.getDocumentCatalog().getOutputIntents().isEmpty()) {
|
if (!doc.getDocumentCatalog().getOutputIntents().isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -740,7 +820,7 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
|
|||||||
doc.getDocumentCatalog().addOutputIntent(intent);
|
doc.getDocumentCatalog().addOutputIntent(intent);
|
||||||
}
|
}
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
// TODO use logging or handle the error somehow
|
throw e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -74,6 +74,11 @@
|
|||||||
<artifactId>ph-schematron</artifactId>
|
<artifactId>ph-schematron</artifactId>
|
||||||
<version>5.6.0</version>
|
<version>5.6.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.helger</groupId>
|
||||||
|
<artifactId>ph-jaxb</artifactId>
|
||||||
|
<version>9.5.4</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.mustangproject</groupId>
|
<groupId>org.mustangproject</groupId>
|
||||||
<artifactId>library</artifactId>
|
<artifactId>library</artifactId>
|
||||||
@@ -83,6 +88,7 @@
|
|||||||
<groupId>org.xmlunit</groupId>
|
<groupId>org.xmlunit</groupId>
|
||||||
<artifactId>xmlunit-core</artifactId>
|
<artifactId>xmlunit-core</artifactId>
|
||||||
<version>2.6.3</version>
|
<version>2.6.3</version>
|
||||||
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.xmlunit</groupId>
|
<groupId>org.xmlunit</groupId>
|
||||||
|
|||||||
Reference in New Issue
Block a user