Added Mustang project
This commit is contained in:
33
mustang/pom.xml
Normal file
33
mustang/pom.xml
Normal file
@@ -0,0 +1,33 @@
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<groupId>org.mustangproject.ZUGFeRD</groupId>
|
||||
<artifactId>mustang</artifactId>
|
||||
<version>1.0</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>mustang</name>
|
||||
<url>http://maven.apache.org</url>
|
||||
|
||||
<properties>
|
||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.pdfbox</groupId>
|
||||
<artifactId>pdfbox</artifactId>
|
||||
<version>2.0.0-SNAPSHOT</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<version>3.8.1</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
13
mustang/src/main/java/org/mustangproject/ZUGFeRD/App.java
Normal file
13
mustang/src/main/java/org/mustangproject/ZUGFeRD/App.java
Normal file
@@ -0,0 +1,13 @@
|
||||
package org.mustangproject.ZUGFeRD;
|
||||
|
||||
/**
|
||||
* Hello world!
|
||||
*
|
||||
*/
|
||||
public class App
|
||||
{
|
||||
public static void main( String[] args )
|
||||
{
|
||||
System.out.println( "Hello World!" );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package org.mustangproject.ZUGFeRD;
|
||||
/**
|
||||
* Mustangproject's ZUGFeRD implementation
|
||||
* Neccessary interface for ZUGFeRD exporter
|
||||
* Licensed under the APLv2
|
||||
* @date 2014-05-10
|
||||
* @version 1.0
|
||||
* @author jstaerk
|
||||
* */
|
||||
|
||||
|
||||
public interface IZUGFeRDExportableContact {
|
||||
|
||||
/**
|
||||
* First and last name of the recipient
|
||||
* @return
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* Postal code of the recipient
|
||||
* @return
|
||||
*/
|
||||
String getZIP();
|
||||
|
||||
/**
|
||||
* VAT ID (Umsatzsteueridentifikationsnummer) of the contact
|
||||
* @return
|
||||
*/
|
||||
String getVATID();
|
||||
|
||||
/**
|
||||
* two-letter country code of the contact
|
||||
* @return
|
||||
*/
|
||||
String getCountry();
|
||||
|
||||
/***
|
||||
* Returns the city of the contact
|
||||
* @return
|
||||
*/
|
||||
String getLocation();
|
||||
|
||||
/***
|
||||
* Returns the street address (street+number) of the contact
|
||||
*/
|
||||
String getStreet();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package org.mustangproject.ZUGFeRD;
|
||||
/**
|
||||
* Mustangproject's ZUGFeRD implementation
|
||||
* Neccessary interface for ZUGFeRD exporter
|
||||
* Licensed under the APLv2
|
||||
* @date 2014-05-10
|
||||
* @version 1.0
|
||||
* @author jstaerk
|
||||
* */
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
public interface IZUGFeRDExportableItem {
|
||||
|
||||
IZUGFeRDExportableProduct getProduct();
|
||||
|
||||
/**
|
||||
* The price of one item incl. taxes
|
||||
* @return
|
||||
*/
|
||||
BigDecimal getPriceGross();
|
||||
|
||||
/**
|
||||
* The price of one item excl. taxes
|
||||
* @return
|
||||
*/
|
||||
BigDecimal getPrice();
|
||||
|
||||
/***
|
||||
* how many
|
||||
* @return
|
||||
*/
|
||||
BigDecimal getQuantity();
|
||||
|
||||
/**
|
||||
* The price of quantity items incl. taxes
|
||||
* @return
|
||||
*/
|
||||
BigDecimal getTotalGross();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
package org.mustangproject.ZUGFeRD;
|
||||
import java.math.BigDecimal;
|
||||
/**
|
||||
* Mustangproject's ZUGFeRD implementation
|
||||
* Necessary interface for ZUGFeRD exporter
|
||||
* Licensed under the APLv2
|
||||
* @date 2014-05-10
|
||||
* @version 1.0
|
||||
* @author jstaerk
|
||||
* */
|
||||
|
||||
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
|
||||
*/
|
||||
String getUnit();
|
||||
|
||||
/**
|
||||
* Short name of the product
|
||||
* @return
|
||||
*/
|
||||
String getName();
|
||||
|
||||
/**
|
||||
* long description of the product
|
||||
* @return
|
||||
*/
|
||||
String getDescription();
|
||||
|
||||
/**
|
||||
* VAT percent of the product (e.g. 19, or 5.1 if you like)
|
||||
* @return
|
||||
*/
|
||||
BigDecimal getVATPercent();
|
||||
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
package org.mustangproject.ZUGFeRD;
|
||||
/**
|
||||
* Mustangproject's ZUGFeRD implementation
|
||||
* Neccessary interface for ZUGFeRD exporter
|
||||
* Licensed under the APLv2
|
||||
* @date 2014-05-10
|
||||
* @version 1.0
|
||||
* @author jstaerk
|
||||
* */
|
||||
|
||||
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
|
||||
public interface IZUGFeRDExportableTransaction {
|
||||
|
||||
/**
|
||||
* Number, typically invoice number of the invoice
|
||||
* @return
|
||||
*/
|
||||
String getNumber();
|
||||
|
||||
/**
|
||||
* the date when the invoice was created
|
||||
* @return
|
||||
*/
|
||||
Date getIssueDate();
|
||||
|
||||
|
||||
/**
|
||||
* total amount incl. taxes
|
||||
* @return
|
||||
*/
|
||||
BigDecimal getTotalGross();
|
||||
|
||||
/**
|
||||
* total amount excl. taxes
|
||||
* @return
|
||||
*/
|
||||
BigDecimal getTotal();
|
||||
|
||||
/**
|
||||
* when the invoice is to be paid
|
||||
* @return
|
||||
*/
|
||||
Date getDueDate();
|
||||
|
||||
IZUGFeRDExportableItem[] getZFItems();
|
||||
|
||||
/***
|
||||
* the recipient
|
||||
* @return
|
||||
*/
|
||||
IZUGFeRDExportableContact getRecipient();
|
||||
|
||||
/***
|
||||
* BIC of the sender
|
||||
* @return
|
||||
*/
|
||||
String getOwnBIC();
|
||||
|
||||
/***
|
||||
* Bank name of the sender
|
||||
* @return
|
||||
*/
|
||||
String getOwnBankName();
|
||||
|
||||
/**
|
||||
* IBAN of the sender
|
||||
* @return
|
||||
*/
|
||||
String getOwnIBAN();
|
||||
|
||||
/**
|
||||
* Tax ID (not VAT ID) of the sender
|
||||
*/
|
||||
String getOwnTaxID();
|
||||
|
||||
/**
|
||||
* VAT ID (Umsatzsteueridentifikationsnummer) of the sender
|
||||
* @return
|
||||
*/
|
||||
String getOwnVATID();
|
||||
|
||||
/**
|
||||
* own name
|
||||
* @return
|
||||
*/
|
||||
String getOwnOrganisationName();
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
HashMap<BigDecimal, BigDecimal> getVATPercentAmountMap();
|
||||
|
||||
}
|
||||
335
mustang/src/main/java/org/mustangproject/ZUGFeRD/LICENSE
Normal file
335
mustang/src/main/java/org/mustangproject/ZUGFeRD/LICENSE
Normal file
@@ -0,0 +1,335 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
||||
|
||||
EXTERNAL COMPONENTS
|
||||
|
||||
Apache PDFBox includes a number of components with separate copyright notices
|
||||
and license terms. Your use of these components is subject to the terms and
|
||||
conditions of the following licenses.
|
||||
|
||||
Contributions made to the original PDFBox, JempBox and FontBox projects:
|
||||
|
||||
Copyright (c) 2002-2007, www.pdfbox.org
|
||||
Copyright (c) 2006-2007, www.jempbox.org
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
3. Neither the name of pdfbox; nor the names of its contributors may be
|
||||
used to endorse or promote products derived from this software without
|
||||
specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
SUCH DAMAGE.
|
||||
|
||||
Adobe Font Metrics (AFM) for PDF Core 14 Fonts
|
||||
|
||||
This file and the 14 PostScript(R) AFM files it accompanies may be used,
|
||||
copied, and distributed for any purpose and without charge, with or without
|
||||
modification, provided that all copyright notices are retained; that the
|
||||
AFM files are not distributed without this file; that all modifications
|
||||
to this file or any of the AFM files are prominently noted in the modified
|
||||
file(s); and that this paragraph is not modified. Adobe Systems has no
|
||||
responsibility or obligation to support the use of the AFM files.
|
||||
|
||||
CMaps for PDF Fonts (http://opensource.adobe.com/wiki/display/cmap/Downloads)
|
||||
|
||||
Copyright 1990-2009 Adobe Systems Incorporated.
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
|
||||
Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
|
||||
Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
Neither the name of Adobe Systems Incorporated nor the names of its
|
||||
contributors may be used to endorse or promote products derived from this
|
||||
software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
Glyphlist (http://www.adobe.com/devnet/opentype/archives/glyph.html)
|
||||
|
||||
Copyright (c) 1997,1998,2002,2007 Adobe Systems Incorporated
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this documentation file to use, copy, publish, distribute,
|
||||
sublicense, and/or sell copies of the documentation, and to permit
|
||||
others to do the same, provided that:
|
||||
- No modification, editing or other alteration of this document is
|
||||
allowed; and
|
||||
- The above copyright notice and this permission notice shall be
|
||||
included in all copies of the documentation.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this documentation file, to create their own derivative works
|
||||
from the content of this document to use, copy, publish, distribute,
|
||||
sublicense, and/or sell the derivative works, and to permit others to do
|
||||
the same, provided that the derived work is not represented as being a
|
||||
copy or version of this document.
|
||||
|
||||
Adobe shall not be liable to any party for any loss of revenue or profit
|
||||
or for indirect, incidental, special, consequential, or other similar
|
||||
damages, whether based on tort (including without limitation negligence
|
||||
or strict liability), contract or other legal or equitable grounds even
|
||||
if Adobe has been advised or had reason to know of the possibility of
|
||||
such damages. The Adobe materials are provided on an "AS IS" basis.
|
||||
Adobe specifically disclaims all express, statutory, or implied
|
||||
warranties relating to the Adobe materials, including but not limited to
|
||||
those concerning merchantability or fitness for a particular purpose or
|
||||
non-infringement of any third party rights regarding the Adobe
|
||||
materials.
|
||||
|
||||
|
||||
PaDaF PDF/A preflight (http://sourceforge.net/projects/padaf)
|
||||
|
||||
Copyright 2010 Atos Worldline SAS
|
||||
|
||||
Licensed by Atos Worldline SAS under one or more
|
||||
contributor license agreements. See the NOTICE file distributed with
|
||||
this work for additional information regarding copyright ownership.
|
||||
Atos Worldline SAS licenses this file to You 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.
|
||||
|
||||
25
mustang/src/main/java/org/mustangproject/ZUGFeRD/NOTICE
Normal file
25
mustang/src/main/java/org/mustangproject/ZUGFeRD/NOTICE
Normal file
@@ -0,0 +1,25 @@
|
||||
Mustangproject
|
||||
Copyright 2014 Jochen Staerk <jstaerk@usegroup.de>
|
||||
|
||||
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.
|
||||
|
||||
|
||||
Based on Apache PDFBox developed at
|
||||
The Apache Software Foundation (http://www.apache.org/).
|
||||
|
||||
Apache PDFBox was based on source code originally developed in the PDFBox, JempBox and FontBox projects.
|
||||
Copyright (c) 2002-2007, www.pdfbox.org
|
||||
Copyright (c) 2006-2007, www.jempbox.org
|
||||
|
||||
Apache PDFBox was based on source code originally developed in the PaDaF project.
|
||||
Copyright (c) 2010 Atos Worldline SAS
|
||||
@@ -0,0 +1,160 @@
|
||||
package org.mustangproject.ZUGFeRD;
|
||||
/**
|
||||
* Mustangproject's ZUGFeRD implementation
|
||||
* ZUGFeRD exporter helper class
|
||||
* Licensed under the APLv2
|
||||
* @date 2014-05-10
|
||||
* @version 1.0
|
||||
* @author jstaerk
|
||||
* */
|
||||
import org.apache.jempbox.impl.XMLUtil;
|
||||
import org.apache.jempbox.xmp.XMPSchemaBasic;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
public class XMPSchemaPDFAExtensions extends XMPSchemaBasic {
|
||||
|
||||
private void addProperty(Element listNode, String name, String type,
|
||||
String category, String description) {
|
||||
Element nameNode = schema.getOwnerDocument().createElement(
|
||||
"pdfaProperty:name"); //$NON-NLS-1$
|
||||
XMLUtil.setStringValue(nameNode, name);
|
||||
listNode.appendChild(nameNode);
|
||||
|
||||
Element typeNode = schema.getOwnerDocument().createElement(
|
||||
"pdfaProperty:valueType"); //$NON-NLS-1$
|
||||
XMLUtil.setStringValue(typeNode, type);
|
||||
listNode.appendChild(typeNode);
|
||||
|
||||
Element categoryNode = schema.getOwnerDocument().createElement(
|
||||
"pdfaProperty:category"); //$NON-NLS-1$
|
||||
XMLUtil.setStringValue(categoryNode, category);
|
||||
listNode.appendChild(categoryNode);
|
||||
|
||||
Element descriptionNode = schema.getOwnerDocument().createElement(
|
||||
"pdfaProperty:description"); //$NON-NLS-1$
|
||||
XMLUtil.setStringValue(descriptionNode, description);
|
||||
listNode.appendChild(descriptionNode);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
public XMPSchemaPDFAExtensions(org.apache.jempbox.xmp.XMPMetadata parent) {
|
||||
super(parent);
|
||||
|
||||
// add some namespaces
|
||||
schema.setAttributeNS(NS_NAMESPACE, "xmlns:pdfaExtension", //$NON-NLS-1$
|
||||
"http://www.aiim.org/pdfa/ns/extension/"); //$NON-NLS-1$
|
||||
|
||||
schema.setAttributeNS(NS_NAMESPACE, "xmlns:pdfaSchema", //$NON-NLS-1$
|
||||
"http://www.aiim.org/pdfa/ns/schema#"); //$NON-NLS-1$
|
||||
|
||||
schema.setAttributeNS(NS_NAMESPACE, "xmlns:pdfaProperty", //$NON-NLS-1$
|
||||
"http://www.aiim.org/pdfa/ns/property#"); //$NON-NLS-1$
|
||||
|
||||
// the superclass includes this two namespaces we don't need
|
||||
schema.removeAttributeNS(NS_NAMESPACE, "xapGImg"); //$NON-NLS-1$
|
||||
schema.removeAttributeNS(NS_NAMESPACE, "xmp"); //$NON-NLS-1$
|
||||
|
||||
/*
|
||||
*What we attach is basically this:
|
||||
*pdfaExtension:schemas-node
|
||||
*+--bag
|
||||
* +--rdf:li
|
||||
* +--some text node (multiple)
|
||||
* +--property node
|
||||
* +--rdf:Seq
|
||||
* +--rdf:li (multiple) attribute node
|
||||
* +--some attribute property description text node (multiple)
|
||||
*/
|
||||
Element schemasNode = schema.getOwnerDocument().createElement(
|
||||
"pdfaExtension:schemas"); //$NON-NLS-1$
|
||||
|
||||
Element bagNode = schema.getOwnerDocument()
|
||||
.createElement("rdf:Bag"); //$NON-NLS-1$
|
||||
|
||||
Element bagListNode = schema.getOwnerDocument().createElement(
|
||||
"rdf:li"); //$NON-NLS-1$
|
||||
|
||||
bagListNode.setAttribute("rdf:parseType", "Resource"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
|
||||
Element schemaInfoNode = schema.getOwnerDocument().createElement(
|
||||
"pdfaSchema:schema"); //$NON-NLS-1$
|
||||
XMLUtil.setStringValue(schemaInfoNode,
|
||||
"ZUGFeRD PDFA Extension Schema"); //$NON-NLS-1$
|
||||
bagListNode.appendChild(schemaInfoNode);
|
||||
|
||||
Element nsInfoNode = schema.getOwnerDocument().createElement(
|
||||
"pdfaSchema:namespaceURI"); //$NON-NLS-1$
|
||||
XMLUtil.setStringValue(nsInfoNode, "urn:ferd:pdfa:invoice:rc#"); //$NON-NLS-1$
|
||||
bagListNode.appendChild(nsInfoNode);
|
||||
|
||||
Element prefixInfoNode = schema.getOwnerDocument().createElement(
|
||||
"pdfaSchema:prefix"); //$NON-NLS-1$
|
||||
XMLUtil.setStringValue(prefixInfoNode, "zf"); //$NON-NLS-1$
|
||||
bagListNode.appendChild(prefixInfoNode);
|
||||
|
||||
Element propertyNode = schema.getOwnerDocument().createElement(
|
||||
"pdfaSchema:property"); //$NON-NLS-1$
|
||||
|
||||
Element sequenceNode = schema.getOwnerDocument().createElement(
|
||||
"rdf:Seq"); //$NON-NLS-1$
|
||||
|
||||
Element seqList1Node = schema.getOwnerDocument().createElement(
|
||||
"rdf:li"); //$NON-NLS-1$
|
||||
|
||||
seqList1Node.setAttribute("rdf:parseType", "Resource"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
|
||||
addProperty(seqList1Node, "DocumentFileName", "Text", "external", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
|
||||
"The name of the embedded Zugferd XML invoice file"); //$NON-NLS-1$
|
||||
|
||||
sequenceNode.appendChild(seqList1Node);
|
||||
|
||||
Element seqList2Node = schema.getOwnerDocument().createElement(
|
||||
"rdf:li"); //$NON-NLS-1$
|
||||
seqList2Node.setAttribute("rdf:parseType", "Resource"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
addProperty(seqList2Node, "DocumentType", "Text", "external", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
|
||||
"INVOICE"); //$NON-NLS-1$
|
||||
sequenceNode.appendChild(seqList2Node);
|
||||
|
||||
Element seqList3Node = schema.getOwnerDocument().createElement(
|
||||
"rdf:li"); //$NON-NLS-1$
|
||||
seqList3Node.setAttribute("rdf:parseType", "Resource"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
addProperty(seqList3Node, "Version", "Text", "external", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
|
||||
"The version of the ZUGFeRD data"); //$NON-NLS-1$
|
||||
sequenceNode.appendChild(seqList3Node);
|
||||
|
||||
Element seqList4Node = schema.getOwnerDocument().createElement(
|
||||
"rdf:li"); //$NON-NLS-1$
|
||||
seqList4Node.setAttribute("rdf:parseType", "Resource"); //$NON-NLS-1$ //$NON-NLS-2$
|
||||
addProperty(seqList4Node, "ConformanceLevel", "Text", "external", //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
|
||||
"The conformance level of the ZUGFeRD data, i.e. BASIC or EXTENDED"); //$NON-NLS-1$
|
||||
sequenceNode.appendChild(seqList4Node);
|
||||
|
||||
propertyNode.appendChild(sequenceNode);
|
||||
|
||||
bagListNode.appendChild(propertyNode);
|
||||
|
||||
bagNode.appendChild(bagListNode);
|
||||
schemasNode.appendChild(bagNode);
|
||||
|
||||
schema.appendChild(schemasNode);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package org.mustangproject.ZUGFeRD;
|
||||
/**
|
||||
* Mustangproject's ZUGFeRD implementation
|
||||
* ZUGFeRD exporter helper class
|
||||
* Licensed under the APLv2
|
||||
* @date 2014-05-10
|
||||
* @version 1.0
|
||||
* @author jstaerk
|
||||
* */
|
||||
import org.apache.jempbox.impl.XMLUtil;
|
||||
import org.apache.jempbox.xmp.XMPSchemaBasic;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
|
||||
public class XMPSchemaZugferd extends XMPSchemaBasic {
|
||||
|
||||
/**
|
||||
* This is what needs to be added to the RDF metadata - basically the name of the embedded
|
||||
* Zugferd file
|
||||
* */
|
||||
public XMPSchemaZugferd(org.apache.jempbox.xmp.XMPMetadata parent) {
|
||||
super(parent);
|
||||
|
||||
schema.setAttributeNS(NS_NAMESPACE, "xmlns:zf", //$NON-NLS-1$
|
||||
"urn:ferd:pdfa:invoice:rc#"); //$NON-NLS-1$
|
||||
// the superclass includes this two namespaces we don't need
|
||||
schema.removeAttributeNS(NS_NAMESPACE, "xapGImg"); //$NON-NLS-1$
|
||||
schema.removeAttributeNS(NS_NAMESPACE, "xmp"); //$NON-NLS-1$
|
||||
Element textNode = schema.getOwnerDocument().createElement(
|
||||
"zf:DocumentType"); //$NON-NLS-1$
|
||||
XMLUtil.setStringValue(textNode, "INVOICE"); //$NON-NLS-1$
|
||||
schema.appendChild(textNode);
|
||||
|
||||
textNode = schema.getOwnerDocument().createElement(
|
||||
"zf:DocumentFileName"); //$NON-NLS-1$
|
||||
XMLUtil.setStringValue(textNode, "ZUGFeRD-invoice.xml"); //$NON-NLS-1$
|
||||
schema.appendChild(textNode);
|
||||
|
||||
textNode = schema.getOwnerDocument().createElement("zf:Version"); //$NON-NLS-1$
|
||||
XMLUtil.setStringValue(textNode, "RC"); //$NON-NLS-1$
|
||||
schema.appendChild(textNode);
|
||||
|
||||
textNode = schema.getOwnerDocument().createElement(
|
||||
"zf:ConformanceLevel"); //$NON-NLS-1$
|
||||
XMLUtil.setStringValue(textNode, "BASIC"); //$NON-NLS-1$
|
||||
schema.appendChild(textNode);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,497 @@
|
||||
package org.mustangproject.ZUGFeRD;
|
||||
/**
|
||||
* Mustangproject's ZUGFeRD implementation
|
||||
* ZUGFeRD exporter
|
||||
* Licensed under the APLv2
|
||||
* @date 2014-05-10
|
||||
* @version 1.0
|
||||
* @author jstaerk
|
||||
* */
|
||||
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.math.BigDecimal;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Collections;
|
||||
import java.util.GregorianCalendar;
|
||||
import java.util.HashMap;
|
||||
|
||||
import javax.xml.transform.TransformerException;
|
||||
|
||||
import org.apache.jempbox.xmp.XMPMetadata;
|
||||
import org.apache.jempbox.xmp.XMPSchemaBasic;
|
||||
import org.apache.jempbox.xmp.XMPSchemaDublinCore;
|
||||
import org.apache.jempbox.xmp.XMPSchemaPDF;
|
||||
import org.apache.jempbox.xmp.pdfa.XMPSchemaPDFAId;
|
||||
import org.apache.pdfbox.cos.COSArray;
|
||||
import org.apache.pdfbox.cos.COSDictionary;
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.apache.pdfbox.pdmodel.PDDocumentCatalog;
|
||||
import org.apache.pdfbox.pdmodel.PDDocumentInformation;
|
||||
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.filespecification.PDComplexFileSpecification;
|
||||
import org.apache.pdfbox.pdmodel.common.filespecification.PDEmbeddedFile;
|
||||
|
||||
|
||||
public class ZUGFeRDExporter {
|
||||
/***
|
||||
* You will need Apache PDFBox. 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);
|
||||
|
||||
doc.save(PDFfilename);
|
||||
|
||||
* @author jstaerk
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//// MAIN CLASS
|
||||
|
||||
private String conformanceLevel="U";
|
||||
private String versionStr="1.0";
|
||||
|
||||
private String currencyFormat(BigDecimal value, char decimalDelimiter) {
|
||||
/*
|
||||
* I needed 123,45, locale independent.I tried
|
||||
* NumberFormat.getCurrencyInstance().format( 12345.6789 ); but that is
|
||||
* locale specific.I also tried DecimalFormat df = new DecimalFormat(
|
||||
* "0,00" ); df.setDecimalSeparatorAlwaysShown(true);
|
||||
* df.setGroupingUsed(false); DecimalFormatSymbols symbols = new
|
||||
* DecimalFormatSymbols(); symbols.setDecimalSeparator(',');
|
||||
* symbols.setGroupingSeparator(' ');
|
||||
* df.setDecimalFormatSymbols(symbols);
|
||||
*
|
||||
* but that would not switch off grouping. Although I liked very much
|
||||
* the (incomplete) "BNF diagram" in
|
||||
* http://docs.oracle.com/javase/tutorial/i18n/format/decimalFormat.html
|
||||
* in the end I decided to calculate myself and take eur+sparator+cents
|
||||
*
|
||||
* This function will cut off, i.e. floor() subcent values Tests:
|
||||
* System.err.println(utils.currencyFormat(new BigDecimal(0),
|
||||
* ".")+"\n"+utils.currencyFormat(new BigDecimal("-1.10"),
|
||||
* ",")+"\n"+utils.currencyFormat(new BigDecimal("-1.1"),
|
||||
* ",")+"\n"+utils.currencyFormat(new BigDecimal("-1.01"),
|
||||
* ",")+"\n"+utils.currencyFormat(new BigDecimal("20000123.3489"),
|
||||
* ",")+"\n"+utils.currencyFormat(new BigDecimal("20000123.3419"),
|
||||
* ",")+"\n"+utils.currencyFormat(new BigDecimal("12"), ","));
|
||||
*
|
||||
* results 0.00 -1,10 -1,10 -1,01 20000123,34 20000123,34 12,00
|
||||
*/
|
||||
value=value.setScale( 2, BigDecimal.ROUND_HALF_UP ); // first, round so that e.g. 1.189999999999999946709294817992486059665679931640625 becomes 1.19
|
||||
long totalCent = value.multiply(new BigDecimal(100)).intValue(); //now get the cents
|
||||
long eurOnly = value.longValue();
|
||||
long centOnly = Math.abs(totalCent % 100);
|
||||
StringBuffer res = new StringBuffer();
|
||||
res.append(eurOnly);
|
||||
res.append(decimalDelimiter);
|
||||
if (centOnly < 10) {
|
||||
res.append('0');
|
||||
}
|
||||
res.append(centOnly);
|
||||
return res.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
All files are PDF/A-3, setConformance refers to the level conformance.
|
||||
|
||||
PDF/A-3 has three coformance levels, called "A", "U" and "B".
|
||||
|
||||
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.
|
||||
|
||||
Feel free to pass "A" as new level if you know what you are doing :-)
|
||||
|
||||
|
||||
*/
|
||||
public void setConformanceLevel(String newLevel) {
|
||||
conformanceLevel=newLevel;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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)
|
||||
* */
|
||||
public PDDocumentCatalog PDFmakeA3compliant(PDDocument doc, String producer, String creator,
|
||||
boolean attachZugferdHeaders) throws IOException,
|
||||
TransformerException {
|
||||
String fullProducer=producer+"(via mustangproject.org "+versionStr+")";
|
||||
PDDocumentCatalog cat = doc.getDocumentCatalog();
|
||||
PDMetadata metadata = new PDMetadata(doc);
|
||||
cat.setMetadata(metadata);
|
||||
// we're using the jempbox org.apache.jempbox.xmp.XMPMetadata version,
|
||||
// not the xmpbox one
|
||||
XMPMetadata xmp = new XMPMetadata();
|
||||
|
||||
XMPSchemaPDFAId pdfaid = new XMPSchemaPDFAId(xmp);
|
||||
pdfaid.setAbout(""); //$NON-NLS-1$
|
||||
xmp.addSchema(pdfaid);
|
||||
|
||||
XMPSchemaDublinCore dc = xmp.addDublinCoreSchema();
|
||||
dc.addCreator(creator);
|
||||
dc.setAbout(""); //$NON-NLS-1$
|
||||
|
||||
XMPSchemaBasic xsb = xmp.addBasicSchema();
|
||||
xsb.setAbout(""); //$NON-NLS-1$
|
||||
|
||||
xsb.setCreatorTool(creator);
|
||||
xsb.setCreateDate(GregorianCalendar.getInstance());
|
||||
// PDDocumentInformation pdi=doc.getDocumentInformation();
|
||||
PDDocumentInformation pdi = new PDDocumentInformation();
|
||||
pdi.setProducer(fullProducer);
|
||||
pdi.setAuthor(creator);
|
||||
doc.setDocumentInformation(pdi);
|
||||
|
||||
XMPSchemaPDF pdf = xmp.addPDFSchema();
|
||||
pdf.setProducer(fullProducer);
|
||||
pdf.setAbout(""); //$NON-NLS-1$
|
||||
|
||||
/*
|
||||
// Mandatory: PDF/A3-a is tagged PDF which has to be expressed using a
|
||||
// MarkInfo dictionary (PDF A/3 Standard sec. 6.7.2.2)
|
||||
PDMarkInfo markinfo = new PDMarkInfo();
|
||||
markinfo.setMarked(true);
|
||||
doc.getDocumentCatalog().setMarkInfo(markinfo);
|
||||
*/
|
||||
/*
|
||||
*
|
||||
To be on the safe side, we use level B without Markinfo because we can not
|
||||
guarantee that the user correctly tagged the templates for the PDF.
|
||||
|
||||
* */
|
||||
pdfaid.setConformance(conformanceLevel);//$NON-NLS-1$ //$NON-NLS-1$
|
||||
|
||||
pdfaid.setPart(3);
|
||||
|
||||
if (attachZugferdHeaders) {
|
||||
addZugferdXMP(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
|
||||
*/
|
||||
}
|
||||
|
||||
metadata.importXMPMetadata(xmp);
|
||||
return cat;
|
||||
}
|
||||
|
||||
private String getZugferdXMLForTransaction(IZUGFeRDExportableTransaction trans) {
|
||||
SimpleDateFormat zugferdDateFormat = new SimpleDateFormat("yyyyMMdd"); //$NON-NLS-1$
|
||||
String xml= "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" //$NON-NLS-1$
|
||||
+ "<rsm:Invoice xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" xmlns:rsm=\"urn:un:unece:uncefact:data:standard:CBFBUY:5\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"urn:un:unece:uncefact:data:standard:CBFBUY:5 ../Schema/Invoice.xsd\">\n" //$NON-NLS-1$
|
||||
+ " <rsm:SpecifiedExchangedDocumentContext>\n" //$NON-NLS-1$
|
||||
+ " <TestIndicator>false</TestIndicator>\n" //$NON-NLS-1$
|
||||
+ " <GuidelineSpecifiedDocumentContextParameter>\n" //$NON-NLS-1$
|
||||
+ " <ID>urn:ferd:invoice:rc:comfort</ID>\n" //$NON-NLS-1$
|
||||
+ " </GuidelineSpecifiedDocumentContextParameter>\n" //$NON-NLS-1$
|
||||
+ " </rsm:SpecifiedExchangedDocumentContext>\n" //$NON-NLS-1$
|
||||
+ " <rsm:HeaderExchangedDocument>\n" //$NON-NLS-1$
|
||||
+ " <ID>"+trans.getNumber()+"</ID>\n" //$NON-NLS-1$ //$NON-NLS-2$
|
||||
+ " <Name>RECHNUNG</Name>\n" //$NON-NLS-1$
|
||||
+ " <TypeCode>380</TypeCode>\n" //$NON-NLS-1$
|
||||
+ " <IssueDateTime format=\"102\">"+zugferdDateFormat.format(trans.getIssueDate())+"</IssueDateTime>\n" //date format was 20130605 //$NON-NLS-1$ //$NON-NLS-2$
|
||||
// + " <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:HeaderExchangedDocument>\n" //$NON-NLS-1$
|
||||
+ " <rsm:SpecifiedSupplyChainTradeTransaction>\n" //$NON-NLS-1$
|
||||
+ " <ApplicableSupplyChainTradeAgreement>\n" //$NON-NLS-1$
|
||||
// + " <BuyerReference>AB-312</BuyerReference>\n"
|
||||
+ " <SellerTradeParty>\n" //$NON-NLS-1$
|
||||
// + " <GlobalID schemeID=\"0088\">4000001123452</GlobalID>\n"
|
||||
+ " <Name>"+trans.getOwnOrganisationName()+"</Name>\n" //$NON-NLS-1$ //$NON-NLS-2$
|
||||
/* + " <PostalTradeAddress>\n"
|
||||
+ " <PostcodeCode>80333</PostcodeCode>\n"
|
||||
+ " <LineOne>Lieferantenstraße 20</LineOne>\n"
|
||||
+ " <CityName>München</CityName>\n"
|
||||
+ " <CountryID>DE</CountryID>\n"
|
||||
+ " </PostalTradeAddress>\n"*/
|
||||
+ " <SpecifiedTaxRegistration>\n" //$NON-NLS-1$
|
||||
+ " <ID schemeID=\"FC\">"+trans.getOwnTaxID()+"</ID>\n" //$NON-NLS-1$ //$NON-NLS-2$
|
||||
+ " </SpecifiedTaxRegistration>\n" //$NON-NLS-1$
|
||||
+ " <SpecifiedTaxRegistration>\n" //$NON-NLS-1$
|
||||
+ " <ID schemeID=\"VA\">"+trans.getOwnVATID()+"</ID>\n" //$NON-NLS-1$ //$NON-NLS-2$
|
||||
+ " </SpecifiedTaxRegistration>\n" //$NON-NLS-1$
|
||||
+ " </SellerTradeParty>\n" //$NON-NLS-1$
|
||||
+ " <BuyerTradeParty>\n" //$NON-NLS-1$
|
||||
// + " <ID>GE2020211</ID>\n"
|
||||
// + " <GlobalID schemeID=\"0088\">4000001987658</GlobalID>\n"
|
||||
+ " <Name>"+trans.getRecipient().getName()+"</Name>\n" //$NON-NLS-1$ //$NON-NLS-2$
|
||||
// + " <DefinedTradeContact>\n"
|
||||
// + " <PersonName>xxx</PersonName>\n"
|
||||
// + " </DefinedTradeContact>\n"
|
||||
+ " <PostalTradeAddress>\n" //$NON-NLS-1$
|
||||
+ " <PostcodeCode>"+trans.getRecipient().getZIP()+"</PostcodeCode>\n" //$NON-NLS-1$ //$NON-NLS-2$
|
||||
+ " <LineOne>"+trans.getRecipient().getStreet()+"</LineOne>\n" //$NON-NLS-1$ //$NON-NLS-2$
|
||||
+ " <CityName>"+trans.getRecipient().getLocation()+"</CityName>\n" //$NON-NLS-1$ //$NON-NLS-2$
|
||||
+ " <CountryID>"+trans.getRecipient().getCountry()+"</CountryID>\n" //$NON-NLS-1$ //$NON-NLS-2$
|
||||
+ " </PostalTradeAddress>\n" //$NON-NLS-1$
|
||||
+ " <SpecifiedTaxRegistration>\n" //$NON-NLS-1$
|
||||
+ " <ID schemeID=\"VA\">"+trans.getRecipient().getVATID()+"</ID>\n" //$NON-NLS-1$ //$NON-NLS-2$
|
||||
+ " </SpecifiedTaxRegistration>\n" //$NON-NLS-1$
|
||||
+ " </BuyerTradeParty>\n" //$NON-NLS-1$
|
||||
// + " <BuyerOrderReferencedDocument>\n"
|
||||
// + " <IssueDateTime format=\"102\">20130301</IssueDateTime>\n"
|
||||
// + " <ID>2013-471331</ID>\n"
|
||||
// + " </BuyerOrderReferencedDocument>\n"
|
||||
+ " </ApplicableSupplyChainTradeAgreement>\n" //$NON-NLS-1$
|
||||
/* + " <ApplicableSupplyChainTradeDelivery>\n"
|
||||
+ " <ActualDeliverySupplyChainEvent>\n"
|
||||
+ " <OccurrenceDateTime format=\"102\">20130603</OccurrenceDateTime>\n"
|
||||
+ " </ActualDeliverySupplyChainEvent>\n"
|
||||
+ " <DeliveryNoteReferencedDocument>\n"
|
||||
+ " <IssueDateTime format=\"102\">20130603</IssueDateTime>\n"
|
||||
+ " <ID>2013-51112</ID>\n"
|
||||
+ " </DeliveryNoteReferencedDocument>\n"
|
||||
+ " </ApplicableSupplyChainTradeDelivery>\n"*/
|
||||
+ " <ApplicableSupplyChainTradeSettlement>\n" //$NON-NLS-1$
|
||||
// it's unclear if this is supposed to refer to the SEPA mandate or the transaction purpose
|
||||
// + " <PaymentReference>"+trans.getNumber()+"</PaymentReference>\n" //$NON-NLS-1$ //$NON-NLS-2$
|
||||
+ " <InvoiceCurrencyCode>EUR</InvoiceCurrencyCode>\n" //$NON-NLS-1$
|
||||
+ " <SpecifiedTradeSettlementPaymentMeans>\n" //$NON-NLS-1$
|
||||
+ " <TypeCode>42</TypeCode>\n" //$NON-NLS-1$
|
||||
+ " <Information>Überweisung</Information>\n" //$NON-NLS-1$
|
||||
+ " <PayeePartyCreditorFinancialAccount>\n" //$NON-NLS-1$
|
||||
+ " <IBANID>"+trans.getOwnIBAN()+"</IBANID>\n" //$NON-NLS-1$ //$NON-NLS-2$
|
||||
+ " </PayeePartyCreditorFinancialAccount>\n" //$NON-NLS-1$
|
||||
+ " <PayeeSpecifiedCreditorFinancialInstitution>\n" //$NON-NLS-1$
|
||||
+ " <BICID>"+trans.getOwnBIC()+"</BICID>\n" //$NON-NLS-1$ //$NON-NLS-2$
|
||||
+ " <Name>"+trans.getOwnBankName()+"</Name>\n" //$NON-NLS-1$ //$NON-NLS-2$
|
||||
+ " </PayeeSpecifiedCreditorFinancialInstitution>\n" //$NON-NLS-1$
|
||||
+ " </SpecifiedTradeSettlementPaymentMeans>\n"; //$NON-NLS-1$
|
||||
|
||||
|
||||
|
||||
HashMap<BigDecimal, BigDecimal> VATPercentAmountMap=trans.getVATPercentAmountMap();
|
||||
for (BigDecimal currentTaxPercent : VATPercentAmountMap.keySet()) {
|
||||
BigDecimal amount = VATPercentAmountMap.get(currentTaxPercent);
|
||||
if (amount != null) {
|
||||
xml += " <ApplicableTradeTax>\n" //$NON-NLS-1$
|
||||
+ " <CalculatedAmount currencyID=\"EUR\">"+currencyFormat(amount, '.')+"</CalculatedAmount>\n" //$NON-NLS-1$ //$NON-NLS-2$
|
||||
+ " <TypeCode>VAT</TypeCode>\n" //$NON-NLS-1$
|
||||
// + " <BasisAmount currencyID=\"EUR\">129.37</BasisAmount>\n"
|
||||
+ " <CategoryCode>S</CategoryCode>\n" //$NON-NLS-1$
|
||||
+ " <ApplicablePercent>"+currentTaxPercent+"</ApplicablePercent>\n" //$NON-NLS-1$
|
||||
+ " </ApplicableTradeTax>\n"; //$NON-NLS-1$
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
/* xml+= "
|
||||
+ " <SpecifiedTradeAllowanceCharge>\n"
|
||||
+ " <ChargeIndicator>false</ChargeIndicator>\n"
|
||||
+ " <BasisAmount currencyID=\"EUR\">10</BasisAmount>\n"
|
||||
+ " <ActualAmount>1.00</ActualAmount>\n"
|
||||
+ " <Reason>Sondernachlass</Reason>\n"
|
||||
+ " <CategoryTradeTax>\n"
|
||||
+ " <TypeCode>VAT</TypeCode>\n"
|
||||
+ " <CategoryCode>S</CategoryCode>\n"
|
||||
+ " <ApplicablePercent>19</ApplicablePercent>\n"
|
||||
+ " </CategoryTradeTax>\n"
|
||||
+ " </SpecifiedTradeAllowanceCharge>\n"
|
||||
+ " <SpecifiedTradeAllowanceCharge>\n"
|
||||
+ " <ChargeIndicator>false</ChargeIndicator>\n"
|
||||
+ " <BasisAmount currencyID=\"EUR\">137.30</BasisAmount>\n"
|
||||
+ " <ActualAmount>13.73</ActualAmount>\n"
|
||||
+ " <Reason>Sondernachlass</Reason>\n"
|
||||
+ " <CategoryTradeTax>\n"
|
||||
+ " <TypeCode>VAT</TypeCode>\n"
|
||||
+ " <CategoryCode>S</CategoryCode>\n"
|
||||
+ " <ApplicablePercent>7</ApplicablePercent>\n"
|
||||
+ " </CategoryTradeTax>\n"
|
||||
+ " </SpecifiedTradeAllowanceCharge>\n"
|
||||
+ " <SpecifiedLogisticsServiceCharge>\n"
|
||||
+ " <Description>Versandkosten</Description>\n"
|
||||
+ " <AppliedAmount>5.80</AppliedAmount>\n"
|
||||
+ " <AppliedTradeTax>\n"
|
||||
+ " <TypeCode>VAT</TypeCode>\n"
|
||||
+ " <CategoryCode>S</CategoryCode>\n"
|
||||
+ " <ApplicablePercent>7</ApplicablePercent>\n"
|
||||
+ " </AppliedTradeTax>\n"
|
||||
+ " </SpecifiedLogisticsServiceCharge>\n"*/
|
||||
|
||||
xml=xml+ " <SpecifiedTradePaymentTerms>\n" //$NON-NLS-1$
|
||||
// + " <Description>Zahlbar innerhalb 30 Tagen netto bis 04.07.2013, 3% Skonto innerhalb 10 Tagen bis 15.06.2013</Description>\n"
|
||||
+ " <DueDateDateTime format=\"102\">"+zugferdDateFormat.format(trans.getDueDate())+"</DueDateDateTime>\n"//20130704 //$NON-NLS-1$ //$NON-NLS-2$
|
||||
+ " </SpecifiedTradePaymentTerms>\n" //$NON-NLS-1$
|
||||
+ " <SpecifiedTradeSettlementMonetarySummation>\n" //$NON-NLS-1$
|
||||
+ " <LineTotalAmount currencyID=\"EUR\">"+currencyFormat(trans.getTotal(), '.')+"</LineTotalAmount>\n" //$NON-NLS-1$ //$NON-NLS-2$
|
||||
// + " <ChargeTotalAmount currencyID=\"EUR\">5.80</ChargeTotalAmount>\n"
|
||||
// + " <AllowanceTotalAmount currencyID=\"EUR\">14.73</AllowanceTotalAmount>\n"
|
||||
+ " <TaxBasisTotalAmount currencyID=\"EUR\">"+currencyFormat(trans.getTotal(), '.')+"</TaxBasisTotalAmount>\n" //$NON-NLS-1$ //$NON-NLS-2$
|
||||
+ " <TaxTotalAmount currencyID=\"EUR\">"+currencyFormat(trans.getTotalGross().subtract(trans.getTotal()), '.')+"</TaxTotalAmount>\n" //$NON-NLS-1$ //$NON-NLS-2$
|
||||
+ " <GrandTotalAmount currencyID=\"EUR\">"+currencyFormat(trans.getTotalGross(), '.')+"</GrandTotalAmount>\n" //$NON-NLS-1$ //$NON-NLS-2$
|
||||
// + " <TotalPrepaidAmount currencyID=\"EUR\">0.00</TotalPrepaidAmount>\n"
|
||||
+ " <DuePayableAmount currencyID=\"EUR\">"+currencyFormat(trans.getTotalGross(), '.')+"</DuePayableAmount>\n" //$NON-NLS-1$ //$NON-NLS-2$
|
||||
+ " </SpecifiedTradeSettlementMonetarySummation>\n" //$NON-NLS-1$
|
||||
+ " </ApplicableSupplyChainTradeSettlement>\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";
|
||||
|
||||
|
||||
int lineID=0;
|
||||
for (IZUGFeRDExportableItem currentItem : trans.getZFItems()) {
|
||||
lineID++;
|
||||
xml=xml+ " <IncludedSupplyChainTradeLineItem>\n"+ //$NON-NLS-1$
|
||||
" <AssociatedDocumentLineDocument>\n" //$NON-NLS-1$
|
||||
+ " <LineID>"+lineID+"</LineID>\n" //$NON-NLS-1$ //$NON-NLS-2$
|
||||
+ " </AssociatedDocumentLineDocument>\n" //$NON-NLS-1$
|
||||
|
||||
+ " <SpecifiedSupplyChainTradeAgreement>\n" //$NON-NLS-1$
|
||||
+ " <GrossPriceProductTradePrice>\n" //$NON-NLS-1$
|
||||
+ " <ChargeAmount currencyID=\"EUR\">"+currencyFormat(currentItem.getPriceGross(),'.')+"</ChargeAmount>\n" //$NON-NLS-1$ //$NON-NLS-2$
|
||||
+ " <BasisQuantity unitCode=\""+currentItem.getProduct().getUnit()+"\">1</BasisQuantity>\n" //$NON-NLS-1$ //$NON-NLS-2$
|
||||
// + " <AppliedTradeAllowanceCharge>\n"
|
||||
// + " <ChargeIndicator>false</ChargeIndicator>\n"
|
||||
// + " <ActualAmount currencyID=\"EUR\">0.6667</ActualAmount>\n"
|
||||
// + " <Reason>Rabatt</Reason>\n"
|
||||
// + " </AppliedTradeAllowanceCharge>\n"
|
||||
+ " </GrossPriceProductTradePrice>\n" //$NON-NLS-1$
|
||||
+ " <NetPriceProductTradePrice>\n" //$NON-NLS-1$
|
||||
+ " <ChargeAmount currencyID=\"EUR\">"+currencyFormat(currentItem.getPrice(),'.')+"</ChargeAmount>\n" //$NON-NLS-1$ //$NON-NLS-2$
|
||||
+ " <BasisQuantity unitCode=\""+currentItem.getProduct().getUnit()+"\">1</BasisQuantity>\n" //$NON-NLS-1$ //$NON-NLS-2$
|
||||
+ " </NetPriceProductTradePrice>\n" //$NON-NLS-1$
|
||||
+ " </SpecifiedSupplyChainTradeAgreement>\n" //$NON-NLS-1$
|
||||
|
||||
+ " <SpecifiedSupplyChainTradeDelivery>\n" //$NON-NLS-1$
|
||||
+ " <BilledQuantity unitCode=\""+currentItem.getProduct().getUnit()+"\">"+currentItem.getQuantity()+"</BilledQuantity>\n" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
|
||||
+ " </SpecifiedSupplyChainTradeDelivery>\n" //$NON-NLS-1$
|
||||
+ " <SpecifiedSupplyChainTradeSettlement>\n" //$NON-NLS-1$
|
||||
+ " <ApplicableTradeTax>\n" //$NON-NLS-1$
|
||||
+ " <TypeCode>VAT</TypeCode>\n" //$NON-NLS-1$
|
||||
+ " <CategoryCode>S</CategoryCode>\n" //$NON-NLS-1$
|
||||
+ " <ApplicablePercent>"+currentItem.getProduct().getVATPercent()+"</ApplicablePercent>\n" //$NON-NLS-1$ //$NON-NLS-2$
|
||||
+ " </ApplicableTradeTax>\n" //$NON-NLS-1$
|
||||
+ " <SpecifiedTradeSettlementMonetarySummation>\n" //$NON-NLS-1$
|
||||
+ " <LineTotalAmount currencyID=\"EUR\">"+currencyFormat(currentItem.getTotalGross(),'.')+"</LineTotalAmount>\n" //$NON-NLS-1$ //$NON-NLS-2$
|
||||
+ " </SpecifiedTradeSettlementMonetarySummation>\n" //$NON-NLS-1$
|
||||
+ " </SpecifiedSupplyChainTradeSettlement>\n" //$NON-NLS-1$
|
||||
+ " <SpecifiedTradeProduct>\n" //$NON-NLS-1$
|
||||
// + " <GlobalID schemeID=\"0160\">4012345001235</GlobalID>\n"
|
||||
// + " <SellerAssignedID>KR3M</SellerAssignedID>\n"
|
||||
// + " <BuyerAssignedID>55T01</BuyerAssignedID>\n"
|
||||
+ " <Name>"+currentItem.getProduct().getName()+"</Name>\n" //$NON-NLS-1$ //$NON-NLS-2$
|
||||
+ " <Description>"+currentItem.getProduct().getDescription()+"</Description>\n" //$NON-NLS-1$ //$NON-NLS-2$
|
||||
+ " </SpecifiedTradeProduct>\n" //$NON-NLS-1$
|
||||
+ " </IncludedSupplyChainTradeLineItem>\n"; //$NON-NLS-1$
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
xml=xml + " </rsm:SpecifiedSupplyChainTradeTransaction>\n" //$NON-NLS-1$
|
||||
+ "</rsm:Invoice>"; //$NON-NLS-1$
|
||||
return xml;
|
||||
}
|
||||
|
||||
/**
|
||||
* embed the Zugferd XML structure in a file named ZUGFeRD-invoice.xml
|
||||
* */
|
||||
public void PDFattachZugferdFile(PDDocument doc, IZUGFeRDExportableTransaction trans) throws IOException {
|
||||
|
||||
// embedded files are stored in a named tree
|
||||
PDEmbeddedFilesNameTreeNode efTree = new PDEmbeddedFilesNameTreeNode();
|
||||
|
||||
String filename="ZUGFeRD-invoice.xml"; //$NON-NLS-1$
|
||||
// first create the file specification, which holds the embedded file
|
||||
PDComplexFileSpecification fs = new PDComplexFileSpecification();
|
||||
fs.setFile(filename);
|
||||
|
||||
COSDictionary dict = fs.getCOSDictionary();
|
||||
// Relation "Source" for linking with eg. catalog
|
||||
dict.setName("AFRelationship", "Alternative"); // as defined in Zugferd standard //$NON-NLS-1$ //$NON-NLS-2$
|
||||
|
||||
dict.setString("UF", filename); //$NON-NLS-1$
|
||||
|
||||
// create a dummy file stream, this would probably normally be a
|
||||
// FileInputStream
|
||||
|
||||
byte[] zugferdRaw = getZugferdXMLForTransaction(trans).getBytes("UTF-8"); //$NON-NLS-1$
|
||||
|
||||
byte[] zugferdData;
|
||||
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
ByteArrayInputStream fakeFile = new ByteArrayInputStream(zugferdData);
|
||||
PDEmbeddedFile ef = new PDEmbeddedFile(doc, fakeFile);
|
||||
// now lets some of the optional parameters
|
||||
ef.setSubtype("text/xml");// as defined in Zugferd standard //$NON-NLS-1$
|
||||
ef.setSize(zugferdData.length);
|
||||
ef.setCreationDate(new GregorianCalendar());
|
||||
|
||||
ef.setModDate(GregorianCalendar.getInstance());
|
||||
|
||||
fs.setEmbeddedFile(ef);
|
||||
|
||||
// now add the entry to the embedded file tree and set in the document.
|
||||
efTree.setNames(Collections.singletonMap(filename, fs));
|
||||
PDDocumentNameDictionary names = new PDDocumentNameDictionary(
|
||||
doc.getDocumentCatalog());
|
||||
names.setEmbeddedFiles(efTree);
|
||||
doc.getDocumentCatalog().setNames(names);
|
||||
// AF entry (Array) in catalog with the FileSpec
|
||||
COSArray cosArray = new COSArray();
|
||||
cosArray.add(fs);
|
||||
doc.getDocumentCatalog().getCOSDictionary().setItem("AF", cosArray); //$NON-NLS-1$
|
||||
|
||||
}
|
||||
|
||||
/***
|
||||
* 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
|
||||
*/
|
||||
private void addZugferdXMP(XMPMetadata metadata) {
|
||||
|
||||
XMPSchemaZugferd zf = new XMPSchemaZugferd(metadata);
|
||||
zf.setAbout(""); //$NON-NLS-1$
|
||||
metadata.addSchema(zf);
|
||||
|
||||
XMPSchemaPDFAExtensions pdfaex = new XMPSchemaPDFAExtensions(metadata);
|
||||
pdfaex.setAbout(""); //$NON-NLS-1$
|
||||
metadata.addSchema(pdfaex);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,330 @@
|
||||
package org.mustangproject.ZUGFeRD;
|
||||
/**
|
||||
* Mustangproject's ZUGFeRD implementation
|
||||
* ZUGFeRD importer
|
||||
* Licensed under the APLv2
|
||||
* @date 2014-05-10
|
||||
* @version 1.0
|
||||
* @author jstaerk
|
||||
* */
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Map;
|
||||
|
||||
import javax.xml.parsers.DocumentBuilder;
|
||||
import javax.xml.parsers.DocumentBuilderFactory;
|
||||
import javax.xml.parsers.ParserConfigurationException;
|
||||
|
||||
import org.apache.pdfbox.pdmodel.PDDocument;
|
||||
import org.apache.pdfbox.pdmodel.PDDocumentNameDictionary;
|
||||
import org.apache.pdfbox.pdmodel.PDEmbeddedFilesNameTreeNode;
|
||||
import org.apache.pdfbox.pdmodel.common.COSObjectable;
|
||||
import org.apache.pdfbox.pdmodel.common.filespecification.PDComplexFileSpecification;
|
||||
import org.apache.pdfbox.pdmodel.common.filespecification.PDEmbeddedFile;
|
||||
import org.w3c.dom.Document;
|
||||
import org.w3c.dom.Node;
|
||||
import org.w3c.dom.NodeList;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
public class ZUGFeRDImporter {
|
||||
/*
|
||||
call extract(importFilename).
|
||||
containsMeta() will return if ZUGFeRD data has been found,
|
||||
afterwards you can call getBIC(), getIBAN() etc.
|
||||
|
||||
*/
|
||||
|
||||
/**@var if metadata has been found */
|
||||
private boolean containsMeta=false;
|
||||
/**@var the reference (i.e. invoice number) of the sender */
|
||||
private String foreignReference;
|
||||
private String BIC;
|
||||
private String IBAN;
|
||||
private String holder;
|
||||
private String amount;
|
||||
private String meta;
|
||||
private String bankName;
|
||||
private boolean amountFound;
|
||||
|
||||
|
||||
|
||||
|
||||
public void extract(String pdfFilename) {
|
||||
PDDocument doc;
|
||||
try {
|
||||
doc = PDDocument.load(pdfFilename);
|
||||
// PDDocumentInformation info = doc.getDocumentInformation();
|
||||
PDEmbeddedFilesNameTreeNode etn;
|
||||
PDDocumentNameDictionary names = new PDDocumentNameDictionary(
|
||||
doc.getDocumentCatalog());
|
||||
etn = names.getEmbeddedFiles();
|
||||
Map<String, COSObjectable> efMap = etn.getNames();
|
||||
// String filePath = "/tmp/";
|
||||
|
||||
for (String filename : efMap.keySet()) {
|
||||
/**
|
||||
* currently (in the release candidate of version 1) only one
|
||||
* attached file with the name ZUGFeRD-invoice.xml is allowed
|
||||
* */
|
||||
if (filename.equals("ZUGFeRD-invoice.xml")) { //$NON-NLS-1$
|
||||
containsMeta = true;
|
||||
|
||||
PDComplexFileSpecification fileSpec = (PDComplexFileSpecification) efMap
|
||||
.get(filename);
|
||||
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);
|
||||
|
||||
setMeta(new String(embeddedFile.getByteArray()));
|
||||
// fos.write(embeddedFile.getByteArray());
|
||||
// fos.close();
|
||||
}
|
||||
}
|
||||
|
||||
} catch (IOException e1) {
|
||||
// TODO Auto-generated catch block
|
||||
e1.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void parse() {
|
||||
DocumentBuilderFactory factory = null;
|
||||
DocumentBuilder builder = null;
|
||||
Document document = null;
|
||||
|
||||
factory = DocumentBuilderFactory.newInstance();
|
||||
try {
|
||||
builder = factory.newDocumentBuilder();
|
||||
} catch (ParserConfigurationException ex3) {
|
||||
// TODO Auto-generated catch block
|
||||
ex3.printStackTrace();
|
||||
}
|
||||
|
||||
try {
|
||||
InputStream bais = new ByteArrayInputStream(meta.getBytes());
|
||||
document = builder.parse(bais);
|
||||
} catch (SAXException ex1) {
|
||||
ex1.printStackTrace();
|
||||
} catch (IOException ex2) {
|
||||
ex2.printStackTrace();
|
||||
}
|
||||
// rootNode = document.getDocumentElement();
|
||||
// ApplicableSupplyChainTradeSettlement
|
||||
NodeList ndList = document
|
||||
.getElementsByTagName("PaymentReference"); //$NON-NLS-1$
|
||||
for (int bookingIndex = 0; bookingIndex < ndList
|
||||
.getLength(); bookingIndex++) {
|
||||
Node booking = ndList.item(bookingIndex);
|
||||
// if there is a attribute in the tag number:value
|
||||
|
||||
setForeignReference(booking.getTextContent());
|
||||
|
||||
}
|
||||
/*
|
||||
ndList = document
|
||||
.getElementsByTagName("GermanBankleitzahlID"); //$NON-NLS-1$
|
||||
|
||||
for (int bookingIndex = 0; bookingIndex < ndList
|
||||
.getLength(); bookingIndex++) {
|
||||
Node booking = ndList.item(bookingIndex);
|
||||
// if there is a attribute in the tag number:value
|
||||
setBIC(booking.getTextContent());
|
||||
|
||||
}
|
||||
|
||||
ndList = document.getElementsByTagName("ProprietaryID"); //$NON-NLS-1$
|
||||
|
||||
for (int bookingIndex = 0; bookingIndex < ndList
|
||||
.getLength(); bookingIndex++) {
|
||||
Node booking = ndList.item(bookingIndex);
|
||||
// if there is a attribute in the tag number:value
|
||||
setIBAN(booking.getTextContent());
|
||||
|
||||
}
|
||||
*/
|
||||
ndList = document.getElementsByTagName("PayeePartyCreditorFinancialAccount"); //$NON-NLS-1$
|
||||
|
||||
for (int bookingIndex = 0; bookingIndex < ndList
|
||||
.getLength(); bookingIndex++) {
|
||||
Node booking = ndList.item(bookingIndex);
|
||||
// there are many "name" elements, so get the one below
|
||||
// SellerTradeParty
|
||||
NodeList bookingDetails = booking.getChildNodes();
|
||||
for (int detailIndex = 0; detailIndex < bookingDetails
|
||||
.getLength(); detailIndex++) {
|
||||
Node detail = bookingDetails.item(detailIndex);
|
||||
if (detail.getNodeName().equals("IBANID")) { //$NON-NLS-1$
|
||||
setIBAN(detail.getTextContent());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ndList = document.getElementsByTagName("PayeeSpecifiedCreditorFinancialInstitution"); //$NON-NLS-1$
|
||||
|
||||
for (int bookingIndex = 0; bookingIndex < ndList
|
||||
.getLength(); bookingIndex++) {
|
||||
Node booking = ndList.item(bookingIndex);
|
||||
// there are many "name" elements, so get the one below
|
||||
// SellerTradeParty
|
||||
NodeList bookingDetails = booking.getChildNodes();
|
||||
for (int detailIndex = 0; detailIndex < bookingDetails
|
||||
.getLength(); detailIndex++) {
|
||||
Node detail = bookingDetails.item(detailIndex);
|
||||
if (detail.getNodeName().equals("BICID")) { //$NON-NLS-1$
|
||||
setBIC(detail.getTextContent());
|
||||
}
|
||||
if (detail.getNodeName().equals("Name")) { //$NON-NLS-1$
|
||||
setBankName(detail.getTextContent());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//
|
||||
ndList = document.getElementsByTagName("SellerTradeParty"); //$NON-NLS-1$
|
||||
|
||||
for (int bookingIndex = 0; bookingIndex < ndList
|
||||
.getLength(); bookingIndex++) {
|
||||
Node booking = ndList.item(bookingIndex);
|
||||
// there are many "name" elements, so get the one below
|
||||
// SellerTradeParty
|
||||
NodeList bookingDetails = booking.getChildNodes();
|
||||
for (int detailIndex = 0; detailIndex < bookingDetails
|
||||
.getLength(); detailIndex++) {
|
||||
Node detail = bookingDetails.item(detailIndex);
|
||||
if (detail.getNodeName().equals("Name")) { //$NON-NLS-1$
|
||||
setHolder(detail.getTextContent());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ndList = document.getElementsByTagName("DuePayableAmount"); //$NON-NLS-1$
|
||||
|
||||
for (int bookingIndex = 0; bookingIndex < ndList
|
||||
.getLength(); bookingIndex++) {
|
||||
Node booking = ndList.item(bookingIndex);
|
||||
// if there is a attribute in the tag number:value
|
||||
amountFound=true;
|
||||
setAmount(booking.getTextContent());
|
||||
|
||||
}
|
||||
|
||||
|
||||
if (!amountFound) {
|
||||
/* there is apparently no requirement to mention DuePayableAmount,,
|
||||
* if it's not there, check for GrandTotalAmount
|
||||
*/
|
||||
ndList = document.getElementsByTagName("GrandTotalAmount"); //$NON-NLS-1$
|
||||
for (int bookingIndex = 0; bookingIndex < ndList
|
||||
.getLength(); bookingIndex++) {
|
||||
Node booking = ndList.item(bookingIndex);
|
||||
// if there is a attribute in the tag number:value
|
||||
amountFound=true;
|
||||
setAmount(booking.getTextContent());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public boolean containsMeta() {
|
||||
return containsMeta;
|
||||
}
|
||||
|
||||
public String getForeignReference() {
|
||||
return foreignReference;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void setForeignReference(String foreignReference) {
|
||||
this.foreignReference = foreignReference;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public String getBIC() {
|
||||
return BIC;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void setBIC(String bic) {
|
||||
this.BIC = bic;
|
||||
}
|
||||
|
||||
|
||||
private void setBankName(String bankname) {
|
||||
this.bankName = bankname;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public String getIBAN() {
|
||||
return IBAN;
|
||||
}
|
||||
|
||||
|
||||
public String getBankName() {
|
||||
return bankName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void setIBAN(String IBAN) {
|
||||
this.IBAN = IBAN;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public String getHolder() {
|
||||
return holder;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private void setHolder(String holder) {
|
||||
this.holder = holder;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public String getAmount() {
|
||||
return amount;
|
||||
}
|
||||
|
||||
|
||||
private void setAmount(String amount) {
|
||||
this.amount = amount;
|
||||
}
|
||||
|
||||
public void setMeta(String meta) {
|
||||
this.meta=meta;
|
||||
}
|
||||
|
||||
public String getMeta() {
|
||||
return meta;
|
||||
}
|
||||
|
||||
/**
|
||||
* will return true if the metadata (just extract-ed or set with setMeta) contains ZUGFeRD XML
|
||||
* */
|
||||
public boolean canParse() {
|
||||
|
||||
|
||||
//SpecifiedExchangedDocumentContext is in the schema, so a relatively good indication if zugferd is present - better than just invoice
|
||||
return (meta!=null)&&( meta.length()>0)&&( meta.contains("SpecifiedExchangedDocumentContext")); //$NON-NLS-1$
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package org.mustangproject.ZUGFeRD;
|
||||
|
||||
import junit.framework.Test;
|
||||
import junit.framework.TestCase;
|
||||
import junit.framework.TestSuite;
|
||||
|
||||
/**
|
||||
* Unit test for simple App.
|
||||
*/
|
||||
public class AppTest
|
||||
extends TestCase
|
||||
{
|
||||
/**
|
||||
* Create the test case
|
||||
*
|
||||
* @param testName name of the test case
|
||||
*/
|
||||
public AppTest( String testName )
|
||||
{
|
||||
super( testName );
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the suite of tests being tested
|
||||
*/
|
||||
public static Test suite()
|
||||
{
|
||||
return new TestSuite( AppTest.class );
|
||||
}
|
||||
|
||||
/**
|
||||
* Rigourous Test :-)
|
||||
*/
|
||||
public void testApp()
|
||||
{
|
||||
assertTrue( true );
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user