Merge branch 'master' of github.com:ZUGFeRD/mustangproject
This commit is contained in:
@@ -115,7 +115,7 @@ corrections
|
|||||||
- support parsing of BT-90 CreditorReferenceID
|
- support parsing of BT-90 CreditorReferenceID
|
||||||
- #871 schema validation does not ignore external entities
|
- #871 schema validation does not ignore external entities
|
||||||
- #868 Fix wrong version in History.md
|
- #868 Fix wrong version in History.md
|
||||||
- #729 Updates about SpecifiedTradeSettlementHeaderMonetarySummation and SpecifiedTradeSettlementPaymentMeans
|
- #729 Updates about SpecifiedTradeSettlementHeaderMonetarySummation and SpecifiedTradeSettlementPaymentMeans. **Breaking Change:** The hardcoded values of ram:TypeCode (58) and ram:Information ("SEPA credit transfer") in the getSettlementXML() method of the IZUGFeRDTradeSettlementPayment interface have been removed. Starting with this version, any code utilizing this interface must explicitly set the corresponding attributes.
|
||||||
- #863 LineCalculator throws NPE if product is null (since 2.17.0)
|
- #863 LineCalculator throws NPE if product is null (since 2.17.0)
|
||||||
- #731 Got a broken translation key when visualizing XML into PDF (xr:Business_process_type)
|
- #731 Got a broken translation key when visualizing XML into PDF (xr:Business_process_type)
|
||||||
- #865 Add sevdesk signature to PDF creators
|
- #865 Add sevdesk signature to PDF creators
|
||||||
|
|||||||
@@ -136,6 +136,7 @@ public class DXExporterFromA1 extends DXExporterFromA3 {
|
|||||||
public DXExporterFromA1 setConformanceLevel(PDFAConformanceLevel newLevel) {
|
public DXExporterFromA1 setConformanceLevel(PDFAConformanceLevel newLevel) {
|
||||||
return (DXExporterFromA1) super.setConformanceLevel(newLevel);
|
return (DXExporterFromA1) super.setConformanceLevel(newLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DXExporterFromA1 setProducer(String producer){
|
public DXExporterFromA1 setProducer(String producer){
|
||||||
return (DXExporterFromA1) super.setProducer(producer);
|
return (DXExporterFromA1) super.setProducer(producer);
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ import jakarta.activation.FileDataSource;
|
|||||||
public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
||||||
|
|
||||||
protected PDFAConformanceLevel conformanceLevel = PDFAConformanceLevel.UNICODE;
|
protected PDFAConformanceLevel conformanceLevel = PDFAConformanceLevel.UNICODE;
|
||||||
|
protected boolean compressionEnabled = false;
|
||||||
protected ArrayList<FileAttachment> fileAttachments = new ArrayList<>();
|
protected ArrayList<FileAttachment> fileAttachments = new ArrayList<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -296,8 +297,8 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
dict.setString("Desc", description);
|
dict.setString("Desc", description);
|
||||||
|
|
||||||
ByteArrayInputStream fakeFile = new ByteArrayInputStream(data);
|
ByteArrayInputStream fakeFile = new ByteArrayInputStream(data);
|
||||||
PDEmbeddedFile ef = new PDEmbeddedFile(doc, fakeFile);
|
COSName filter = compressionEnabled ? COSName.FLATE_DECODE : null;
|
||||||
// ef.addCompression();
|
PDEmbeddedFile ef = new PDEmbeddedFile(doc, fakeFile, filter);
|
||||||
ef.setSubtype(subType);
|
ef.setSubtype(subType);
|
||||||
ef.setSize(data.length);
|
ef.setSize(data.length);
|
||||||
ef.setCreationDate(new GregorianCalendar());
|
ef.setCreationDate(new GregorianCalendar());
|
||||||
@@ -417,7 +418,6 @@ public class DXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DXExporterFromA3 setCreator(String creator) {
|
public DXExporterFromA3 setCreator(String creator) {
|
||||||
this.creator = creator;
|
this.creator = creator;
|
||||||
|
|||||||
@@ -56,6 +56,7 @@ public interface IZUGFeRDExporter extends Closeable, IExporter {
|
|||||||
public IZUGFeRDExporter load(InputStream pdfSource) throws IOException;
|
public IZUGFeRDExporter load(InputStream pdfSource) throws IOException;
|
||||||
public IZUGFeRDExporter setCreator(String creator);
|
public IZUGFeRDExporter setCreator(String creator);
|
||||||
public IZUGFeRDExporter setConformanceLevel(PDFAConformanceLevel newLevel);
|
public IZUGFeRDExporter setConformanceLevel(PDFAConformanceLevel newLevel);
|
||||||
|
public IZUGFeRDExporter setEnablePDFAttachmentCompression(boolean enablePDFAttachmentCompression);
|
||||||
public IZUGFeRDExporter setProducer(String producer);
|
public IZUGFeRDExporter setProducer(String producer);
|
||||||
public IZUGFeRDExporter setZUGFeRDVersion(int version);
|
public IZUGFeRDExporter setZUGFeRDVersion(int version);
|
||||||
public boolean ensurePDFIsValid(final DataSource dataSource) throws IOException;
|
public boolean ensurePDFIsValid(final DataSource dataSource) throws IOException;
|
||||||
|
|||||||
@@ -129,6 +129,9 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
|
|
||||||
private boolean attachZUGFeRDHeaders = true;
|
private boolean attachZUGFeRDHeaders = true;
|
||||||
|
|
||||||
|
/** Defines whether attachments to the PDF should be using FLATE compression */
|
||||||
|
private boolean compressionEnabled = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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)
|
||||||
@@ -296,8 +299,8 @@ public class OXExporterFromA3 extends ZUGFeRDExporterFromA3 {
|
|||||||
dict.setString("Desc", description);
|
dict.setString("Desc", description);
|
||||||
|
|
||||||
ByteArrayInputStream fakeFile = new ByteArrayInputStream(data);
|
ByteArrayInputStream fakeFile = new ByteArrayInputStream(data);
|
||||||
PDEmbeddedFile ef = new PDEmbeddedFile(doc, fakeFile);
|
COSName filter = compressionEnabled ? COSName.FLATE_DECODE : null;
|
||||||
// ef.addCompression();
|
PDEmbeddedFile ef = new PDEmbeddedFile(doc, fakeFile, filter);
|
||||||
ef.setSubtype(subType);
|
ef.setSubtype(subType);
|
||||||
ef.setSize(data.length);
|
ef.setSize(data.length);
|
||||||
ef.setCreationDate(new GregorianCalendar());
|
ef.setCreationDate(new GregorianCalendar());
|
||||||
|
|||||||
@@ -861,7 +861,7 @@ public class ZUGFeRD2PullProvider implements IXMLProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if ((trans.getZFAllowances() != null) && (trans.getZFAllowances().length > 0)) {
|
if ((trans.getZFAllowances() != null) && (trans.getZFAllowances().length > 0)) {
|
||||||
if (profile == Profiles.getByName("XRechnung")) {
|
if ((profile == Profiles.getByName("XRechnung")) || (profile == Profiles.getByName("EN16931")) || (profile == Profiles.getByName("EXTENDED"))) {
|
||||||
for (IZUGFeRDAllowanceCharge allowance : trans.getZFAllowances()) {
|
for (IZUGFeRDAllowanceCharge allowance : trans.getZFAllowances()) {
|
||||||
xml += "<ram:SpecifiedTradeAllowanceCharge>" +
|
xml += "<ram:SpecifiedTradeAllowanceCharge>" +
|
||||||
"<ram:ChargeIndicator>" +
|
"<ram:ChargeIndicator>" +
|
||||||
|
|||||||
@@ -104,6 +104,9 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
|
|||||||
private Profile profile = null;
|
private Profile profile = null;
|
||||||
protected boolean documentPrepared = false;
|
protected boolean documentPrepared = false;
|
||||||
|
|
||||||
|
/** Defines whether attachments to the PDF should be using FLATE compression */
|
||||||
|
private boolean compressionEnabled = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Data (XML invoice) to be added to the ZUGFeRD PDF. It may be externally set,
|
* 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
|
* in which case passing a IZUGFeRDExportableTransaction is not necessary. By
|
||||||
@@ -395,7 +398,8 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
|
|||||||
dict.setString("Desc", description);
|
dict.setString("Desc", description);
|
||||||
|
|
||||||
ByteArrayInputStream fakeFile = new ByteArrayInputStream(data);
|
ByteArrayInputStream fakeFile = new ByteArrayInputStream(data);
|
||||||
PDEmbeddedFile ef = new PDEmbeddedFile(doc, fakeFile);
|
COSName filter = compressionEnabled ? COSName.FLATE_DECODE : null;
|
||||||
|
PDEmbeddedFile ef = new PDEmbeddedFile(doc, fakeFile, filter);
|
||||||
// ef.addCompression();
|
// ef.addCompression();
|
||||||
ef.setSubtype(subType);
|
ef.setSubtype(subType);
|
||||||
ef.setSize(data.length);
|
ef.setSize(data.length);
|
||||||
@@ -506,6 +510,12 @@ public class ZUGFeRDExporterFromA3 extends XRExporter implements IZUGFeRDExporte
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IZUGFeRDExporter setEnablePDFAttachmentCompression(boolean compressionEnabled) {
|
||||||
|
this.compressionEnabled = compressionEnabled;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public ZUGFeRDExporterFromA3 setCreator(String creator) {
|
public ZUGFeRDExporterFromA3 setCreator(String creator) {
|
||||||
this.creator = creator;
|
this.creator = creator;
|
||||||
|
|||||||
@@ -188,6 +188,10 @@ public class ZUGFeRDExporterFromPDFA implements IZUGFeRDExporter {
|
|||||||
return getExporter().setConformanceLevel(newLevel);
|
return getExporter().setConformanceLevel(newLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public IZUGFeRDExporter setEnablePDFAttachmentCompression(boolean compressionEnabled) {
|
||||||
|
return getExporter().setEnablePDFAttachmentCompression(compressionEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
public IZUGFeRDExporter setProducer(String producer) {
|
public IZUGFeRDExporter setProducer(String producer) {
|
||||||
|
|
||||||
return getExporter().setProducer(producer);
|
return getExporter().setProducer(producer);
|
||||||
|
|||||||
@@ -23,7 +23,11 @@ import junit.framework.TestSuite;
|
|||||||
|
|
||||||
import org.apache.pdfbox.Loader;
|
import org.apache.pdfbox.Loader;
|
||||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||||
|
import org.apache.pdfbox.pdmodel.PDDocumentNameDictionary;
|
||||||
|
import org.apache.pdfbox.pdmodel.PDEmbeddedFilesNameTreeNode;
|
||||||
import org.apache.pdfbox.pdmodel.common.PDMetadata;
|
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.pdfbox.pdmodel.encryption.InvalidPasswordException;
|
import org.apache.pdfbox.pdmodel.encryption.InvalidPasswordException;
|
||||||
import org.apache.xmpbox.XMPMetadata;
|
import org.apache.xmpbox.XMPMetadata;
|
||||||
import org.apache.xmpbox.schema.PDFAIdentificationSchema;
|
import org.apache.xmpbox.schema.PDFAIdentificationSchema;
|
||||||
@@ -413,17 +417,18 @@ public class MustangReaderWriterTest extends MustangReaderTestCase {
|
|||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
ze.export(baos);
|
ze.export(baos);
|
||||||
ze.close();
|
ze.close();
|
||||||
String pdfContent = baos.toString(StandardCharsets.UTF_8);
|
byte[] targetBytes = baos.toByteArray();
|
||||||
assertFalse(pdfContent.indexOf(DocumentContextParameterTypeConstants.BASIC) >= 0);
|
String xmlContent = readEmbeddedXmlFromPdf(targetBytes, "ZUGFeRD-invoice.xml");
|
||||||
assertFalse(pdfContent.indexOf(DocumentContextParameterTypeConstants.EXTENDED) >= 0);
|
assertFalse(xmlContent.contains(DocumentContextParameterTypeConstants.BASIC));
|
||||||
assertTrue(pdfContent.indexOf(DocumentContextParameterTypeConstants.COMFORT) >= 0);
|
assertFalse(xmlContent.contains(DocumentContextParameterTypeConstants.EXTENDED));
|
||||||
|
assertTrue(xmlContent.contains(DocumentContextParameterTypeConstants.COMFORT));
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
fail("IOException should not happen in testZExport");
|
fail("IOException should not happen in testZExport");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void testFXExport() throws Exception {
|
public void testFXExport() throws Exception {
|
||||||
|
|
||||||
final String TARGET_PDF = "./target/testout-MustangGnuaccountingBeispielRE-20171118_506fx.pdf";
|
final String TARGET_PDF = "./target/testout-MustangGnuaccountingBeispielRE-20171118_506fx.pdf";
|
||||||
@@ -440,7 +445,8 @@ public class MustangReaderWriterTest extends MustangReaderTestCase {
|
|||||||
result.write(buffer, 0, length);
|
result.write(buffer, 0, length);
|
||||||
}
|
}
|
||||||
|
|
||||||
ze.addAdditionalFile("test.pdf", result.toByteArray());
|
var bytes = result.toByteArray();
|
||||||
|
ze.addAdditionalFile("test.pdf", bytes);
|
||||||
|
|
||||||
ze.setTransaction(this);
|
ze.setTransaction(this);
|
||||||
ze.disableAutoClose(true);
|
ze.disableAutoClose(true);
|
||||||
@@ -449,12 +455,14 @@ public class MustangReaderWriterTest extends MustangReaderTestCase {
|
|||||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
ze.export(baos);
|
ze.export(baos);
|
||||||
ze.close();
|
ze.close();
|
||||||
String pdfContent = baos.toString(StandardCharsets.UTF_8);
|
byte[] targetBytes = baos.toByteArray();
|
||||||
assertFalse(pdfContent.indexOf("(via mustangproject.org") == -1);
|
String pdfContent = new String(targetBytes, StandardCharsets.UTF_8);
|
||||||
|
String xmlContent = readEmbeddedXmlFromPdf(targetBytes, "factur-x.xml");
|
||||||
|
assertTrue(pdfContent.contains("(via mustangproject.org"));
|
||||||
// check for pdf-a schema extension
|
// check for pdf-a schema extension
|
||||||
assertFalse(pdfContent.indexOf("<fx:ConformanceLevel>EN 16931</fx:ConformanceLevel>") == -1);
|
assertTrue(pdfContent.contains("<fx:ConformanceLevel>EN 16931</fx:ConformanceLevel>"));
|
||||||
assertFalse(pdfContent.indexOf("<pdfaSchema:prefix>fx</pdfaSchema:prefix>") == -1);
|
assertTrue(pdfContent.contains("<pdfaSchema:prefix>fx</pdfaSchema:prefix>"));
|
||||||
assertFalse(pdfContent.indexOf("urn:cen.eu:en16931:2017") == -1);
|
assertTrue(xmlContent.contains("urn:cen.eu:en16931:2017"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// now check the contents (like MustangReaderTest)
|
// now check the contents (like MustangReaderTest)
|
||||||
@@ -468,6 +476,27 @@ public class MustangReaderWriterTest extends MustangReaderTestCase {
|
|||||||
assertEquals(getNumber(), zi.getForeignReference());
|
assertEquals(getNumber(), zi.getForeignReference());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static String readEmbeddedXmlFromPdf(byte[] targetBytes, String xmlFilename) throws IOException {
|
||||||
|
// Read attached (compressed) XML file
|
||||||
|
try (PDDocument pdDocument = Loader.loadPDF(targetBytes)) {
|
||||||
|
PDDocumentNameDictionary names = new PDDocumentNameDictionary(pdDocument.getDocumentCatalog());
|
||||||
|
|
||||||
|
PDEmbeddedFilesNameTreeNode embeddedFiles = names.getEmbeddedFiles();
|
||||||
|
Map<String, PDComplexFileSpecification> fileMap = embeddedFiles.getNames();
|
||||||
|
|
||||||
|
|
||||||
|
PDComplexFileSpecification fileSpec = fileMap.get(xmlFilename);
|
||||||
|
if (fileSpec == null) {
|
||||||
|
fail("Files does not contain a file named " + xmlFilename);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
PDEmbeddedFile embeddedFile = fileSpec.getEmbeddedFile();
|
||||||
|
String xmlContent = new String(embeddedFile.toByteArray(), StandardCharsets.UTF_8);
|
||||||
|
System.out.println(xmlContent);
|
||||||
|
return xmlContent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void testExceptionOnPDF14() {
|
public void testExceptionOnPDF14() {
|
||||||
|
|
||||||
final String TARGET_PDF = "./target/testout-MustangGnuaccountingBeispielRE-20170509_505new.pdf";
|
final String TARGET_PDF = "./target/testout-MustangGnuaccountingBeispielRE-20170509_505new.pdf";
|
||||||
|
|||||||
Reference in New Issue
Block a user