1. Quick Start

The example code from MinimalInvoice.java represents a valid basic invoice and the steps on how to convert and attach an invoice to a PDF.

Let us step through the code and take a look at the interesting parts.

1.1. Creating the invoice model

private Invoice createInvoice() {

   Invoice invoice = new Invoice(BASIC);    (1)
   invoice.setHeader(new Header()
      .setInvoiceNumber("20131122-42")
      .setCode(_380)
      .setIssued(today)
      .setName("Rechnung"));

   Trade trade = new Trade();
   trade.setAgreement(new Agreement()    (2)
         .setSeller(new TradeParty()
               .setName("Seller Inc.")
               .setAddress(new Address("80331", "Marienplatz 1", "München", DE))
               .addTaxRegistrations(new TaxRegistration("DE122...", FC)))
         .setBuyer(new TradeParty()
               .setName("Buyer Inc.")
               .setAddress(new Address("50667", "Domkloster 4", "Köln", DE))
               .addTaxRegistrations(new TaxRegistration("DE123...", FC))));

   trade.setDelivery(new Delivery(nextMonth));

   ItemTax itemTax = new ItemTax();
   itemTax.setPercentage(BigDecimal.valueOf(19));
   itemTax.setType(TaxCode.VAT);

   trade.addItem(new Item()
      .setProduct(new Product().setName("Saddle"))
      .setAgreement(new SpecifiedAgreement().setGrossPrice(new GrossPrice(new Amount(100, EUR))).setNetPrice(new Price(new Amount(100, EUR))))
      .setSettlement(new SpecifiedSettlement().addTradeTax(itemTax))
      .setDelivery(new SpecifiedDelivery(new Quantity(1, UNIT))));

   trade.setSettlement(new Settlement()
   .setPaymentReference("20131122-42")
   .setCurrency(EUR)
   .addPaymentMeans(new PaymentMeans()
      .setPayerAccount(new DebtorFinancialAccount("DE01234.."))
         .setPayerInstitution(new FinancialInstitution("GENO...")))
   .setMonetarySummation(new MonetarySummation()
      .setLineTotal(new Amount(100, EUR))
      .setChargeTotal(new Amount(0,EUR))
      .setAllowanceTotal(new Amount(0, EUR))
      .setTaxBasisTotal(new Amount(100, EUR))
      .setTaxTotal(new Amount(19, EUR))
      .setDuePayable(new Amount(119, EUR))
      .setTotalPrepaid(new Amount(0, EUR))
      .setGrandTotal(new Amount(119, EUR))));

   invoice.setTrade(trade);

   return invoice;
}
1 A new invoice instance is created with one of the three allowed profiles. BASIC, COMPFORT or EXTENDED
2 The implementation of the model as a fluent interface makes the creation of the invoice self-explanatory.

1.2. Transforming the invoice model to XML and vice versa.

public void transformInvoiceToXml(Invoice invoice) throws IOException {
   InvoiceTransformer transformer = new InvoiceTransformer();   (1)
   FileOutputStream outputStream = new FileOutputStream("target/minimal-invoice.xml");
   transformer.fromModel(invoice, outputStream);   (2)
}
1 The InvoiceTransformer is responsible for transforming XML to Model and vice versa.
2 Transform the given invoice to an OutputStream.

1.3. Append a ZUGFeRD invoice to an existing PDF

This alternative step performs a model conversation. So you don’t have to do it yourself.

public void appendInvoiceToPdf() throws IOException {
   Invoice invoice = createInvoice();
   PdfHandler handler = new PdfHandler();   (1)
   InputStream inputPdf = getClass().getResourceAsStream("/acme_invoice-42.pdf");
   OutputStream resultingPdf = new FileOutputStream("target/acme_invoice-42_ZUGFeRD.pdf");
   handler.appendInvoice(invoice, inputPdf, resultingPdf);   (2)
}
1 The PdfHandler bridges together the invoice with PDFs.
2 Here we append an invoice to an PDF defined as inputPdf. The is written to the resultingPdf output stream.

1.4. Extract ZUGFeRD invoice from PDF

This step internally also performs a model conversation.

public void extracInvoiceFromPdf() {
   PdfHandler handler = new PdfHandler();   (1)
   InputStream inputZugferdPdfStream = getClass().getResourceAsStream("/acme_invoice-42_ZUGFeRD.pdf");
   Invoice invoice = handler.extractInvoice(inputZugferdPdfStream);   (2)
   assertThat(invoice).isNotNull();
}
1 The PdfHandler also extracts the invoice from a ZUGFeRD PDF.
2 Extracts the invoice from an existing PDF provided by the inputZugferdPdfStream. The result is the invoice.

1.5. Validate correctness of a ZUGFeRD Invoice

This example shows how one can validates the correction of an invoice.

public void validateInvoice() {
   //setup
   Invoice invoice = createInvoice();
   InvoiceValidator invoiceValidator = new InvoiceValidator();   (1)

   //execute
   Set<ConstraintViolation<Invoice>> violations = invoiceValidator.validate(invoice);   (2)

   for (ConstraintViolation<Invoice> violation : violations) {
     log.log(Level.INFO, violation.getMessage() + " at: " + violation.getPropertyPath() );
   }
   //verify
   assertThat(violations.size()).isZero();   (3)
}
1 Create a new default InvoiceValidator. See the setup section on how to integrate a Validation Framework into your project.
2 Performs the validation by calling the validate(...) method assigning the result to a ConstraintViolation set.
3 If there aren’t any error the resulting Set should’t have any elements.

1.6. Calculate and apply missing invoice amounts

Next to validating the existing amounts of the invoice it is also possible to calculate missing or incomplete amounts. An error is thrown if an existing amount in the model is different then the newly calculated amount.

private Invoice createInvoice() {

   Invoice invoice = new Invoice(EXTENDED);    (1)
   invoice.setHeader(new Header()
      .setInvoiceNumber("20131122-42")
      .setCode(_380)
      .setIssued(today)
      .setName("Rechnung"));

   Trade trade = new Trade();
   trade.setAgreement(new Agreement()
         .setSeller(new TradeParty()
               .setName("Seller Inc.")
               .setAddress(new Address("80331", "Marienplatz 1", "München", DE))
               .addTaxRegistrations(new TaxRegistration("DE122...", FC)))
         .setBuyer(new TradeParty()
               .setName("Buyer Inc.")
               .setAddress(new Address("50667", "Domkloster 4", "Köln", DE))
               .addTaxRegistrations(new TaxRegistration("DE123...", FC))));

   trade.setDelivery(new Delivery(nextMonth));

   ItemTax itemTax = new ItemTax();
   itemTax.setPercentage(BigDecimal.valueOf(19));
   itemTax.setType(TaxCode.VAT);

   trade.addItem(new Item()
      .setProduct(new Product().setName("Saddle"))
      .setAgreement(new SpecifiedAgreement()/*.setGrossPrice(new GrossPrice(new Amount(100, EUR)))*/.setNetPrice(new Price(new Amount(100, EUR))))(2)
      .setSettlement(new SpecifiedSettlement().addTradeTax(itemTax))
      .setDelivery(new SpecifiedDelivery(new Quantity(1, UNIT))));

   trade.setSettlement(new Settlement()
   .setPaymentReference("20131122-42")
   .setCurrency(EUR)
   .addPaymentMeans(new PaymentMeans()
      .setPayerAccount(new DebtorFinancialAccount("DE01234.."))
         .setPayerInstitution(new FinancialInstitution("GENO..."))));
   /*.setMonetarySummation(new MonetarySummation() (3)
      .setLineTotal(new Amount(100, EUR))
      .setChargeTotal(new Amount(0,EUR))
      .setAllowanceTotal(new Amount(0, EUR))
      .setTaxBasisTotal(new Amount(100, EUR))
      .setTaxTotal(new Amount(19, EUR))
      .setDuePayable(new Amount(119, EUR))
      .setTotalPrepaid(new Amount(0, EUR))
      .setGrandTotal(new Amount(119, EUR))));*/

   invoice.setTrade(trade);
   Invoice completedInvoice = new InvoiceCalculator(invoice).complete(); (4)

   log.info(completedInvoice.getTrade().getSettlement().getMonetarySummation().toString());(5)
   /* MonetarySummation [
    * lineTotal=100.00 EUR,
    * chargeTotal=0.00 EUR,
    * allowanceTotal=0.00 EUR,
    * taxBasisTotal=100.00 EUR,
    * taxTotal=19.00 EUR,
    * grandTotal=119.00 EUR,
    * totalPrepaid=0.00 EUR,
    * duePayable=119.00 EUR]
    */

   return completedInvoice;
}
1 EXTENDED is mandatory for applying calculated values.
2 Gross Price is calculated based on the Net Prices.
3 Monetary Summation gets calculated.
4 The invoice calculator does not modify the input invoice and returns a new instance with calculated values.
5 The comment contains the result of the calculation.

2. Setup

Or how to integrate the Konik library into a project.

Broadly there are two different ways on how to integrate the Konik library into a project. Both ways mostly depend upon the type of the target environment of the application and the invoice validator implementation.

Friends of .NET have only one option to choose from.

2.1. Java Projects

The minimal requirement for Konik is Java 6 although we recommend Java 7 and above because of newer JaxB libraries. The Working with Java 6 section contains instructions on how Java 6 users can overcome some of the issues with Java 6.

The Konik Library optionally supports Bean Injections, also known as JSR330 or CDI. This means that Konik fits nicely in environments with Dependency Injection frameworks such as Spring or JEE. The default option for Konik is to use Java Service provider interface (SPI).

2.1.1. JEE Environment

If your environment is JEE6 and above include just

<dependency>
    <groupId>io.konik</groupId>
    <artifactId>konik</artifactId>
    <version>1.2.9</version>
</dependency>
<dependency>
    <groupId>io.konik</groupId>
    <artifactId>pdfbox-carriage</artifactId> (1)
    <version>1.0.1</version>
</dependency>
1 Alternatively a different PDF carriage can be selected. Make sure there is only one PDF carriage on the classpath.

2.1.2. Spring

Select the dependencies according to the JEE Environment description. As Konik has an optional dependency to javax.inject also known as JRS330 which takes not part of Spring by default see use of JSR 330 Standard Annotations in Spring Documentation.

When using Spring you have to add javax.inject dependency to your project, so Spring can use JSR330 annotated components.

<dependency>
    <groupId>javax.inject</groupId>
    <artifactId>javax.inject</artifactId>
    <version>1</version>
</dependency>

In the next step instruct Spring to also scan for the Konik Library components based on the package name preifix io.konik.

 @Configuration
 @ComponentScan(basePackages = "com.acme.app.xyz , io.konik")	(1)
 public class SpringApplicationConfig  {
     ...
 }
1 Declaring with Spring Annotation to scan for injectable components in package io.konik. For alternative XML Configuration refer to Spring Documentation.

2.1.3. Java standalone

Working in a standalone Java project or any other environment which is not JEE5+ or JSR330 compatible.

Followind dependecy is required

<dependency>
    <groupId>io.konik</groupId>
    <artifactId>konik</artifactId>
    <version>1.2.9</version>
</dependency>

<dependency>
    <groupId>io.konik</groupId>
    <artifactId>pdfbox-carriage</artifactId> (1)
    <version>1.0.1</version>
</dependency>
1 Different PDF carriage can be selected. Make sure there is only one PDF carriage on the classpath.

Recommended for invoice validation is this additional dependency. If the stack you are using contains any other validation framework such as Hibernate Validator you can use this instead.

<dependency>
    <groupId>org.apache.bval</groupId>
    <artifactId>bval-jsr</artifactId>
    <version>1.1.1</version>
</dependency>

2.1.4. Working with Java 6

We recommend Java 7 and above because of newer JaxB library which does not contain namespace prefix issues. If you still need to work with Java 6 we recommend to use the latest JaxB libraries. While from the XML point of view this not a problem, other XML implementations who will receive your invoice might still complain about it.

For Java 6 add the latest JaxB files to your project.

<dependencies>
   <dependency>
      <groupId>com.sun.xml.bind</groupId>
      <artifactId>jaxb-impl</artifactId>
      <version>2.2.10-b140310.1920</version>
   </dependency>
   <dependency>
      <groupId>javax.xml.bind</groupId>
      <artifactId>jaxb-api</artifactId>
      <version>2.2.10</version>
   </dependency>
   <dependency>
      <groupId>com.sun.xml.bind</groupId>
      <artifactId>jaxb-core</artifactId>
      <version>2.2.10-b140310.1920</version>
   </dependency>
</dependencies>

2.2. Invoice Validator Option

The second option to choose from is the {http://beanvalidation.org/}[Java Bean Validation] Provider. With the support of Bean Validation you can verify the correctness of your invoice prior transforming it to xml. Currently there two Open Source Bean Validation Providers Hibernate Validator and Apache BVal.

While Hibernate Validator is superior regarding features BVal has less dependencies and is more compact, which makes it a perfect companion for a standalone application.

See http://hibernate.org/validator/documentation/getting-started/ on what dependencies you might need in your environment.

For BVal just this dependency to your project.

<dependency>
    <groupId>org.apache.bval</groupId>
    <artifactId>bval-jsr303</artifactId>
    <version>0.5</version>
</dependency>

2.2.1. References

A Blog entry deals with the topic of Konik and dependeny injection.

2.3. .NET projects

The .NET package consists of Konik, PDFBox-carriage & BVal for Invoice Validation. Everything is bundled together in one single dll. You can install the Konik library directly via NuGet.

PM> Install-Package ZUGFeRD-NET

You can also browse the NuGet Konik package for details.

2.4. .NET Example

To help you get started there is also an .NET example available on GitHub.

3. Konik Configuration

Konik has sensible default configuration settings out of the box. In most cases you should not need to change this default settings.

List of default Konik configuration options.

#konik library default settings
io.konik.stripTrailingZeros=false
io.konik.jaxb.adapter.TwoDigitRoundingAdapter.scale=2
io.konik.jaxb.adapter.TwoDigitRoundingAdapter.roundingMode=HALF_UP
io.konik.jaxb.adapter.FourDigitRoundingAdapter.scale=4
io.konik.jaxb.adapter.FourDigitRoundingAdapter.roundingMode=HALF_UP
io.konik.jaxb.adapter.MeasureRoundingAdapter.scale=2
io.konik.jaxb.adapter.MeasureRoundingAdapter.roundingMode=HALF_UP
io.konik.jaxb.adapter.QuantityRoundingAdapter.scale=4
io.konik.jaxb.adapter.QuantityRoundingAdapter.roundingMode=HALF_UP

There are two possible ways how Konik can be configured.

3.1. Property file

If a property file with the name io.konik.configuration.properties exists in the root of the classpath it will be loaded when accessing the configuration. When using maven io.konik.configuration.properties should be placed in src/main/resources.

3.2. System property

In addition system properties can be also used to change the Konik configuration. Setting System Properties is either done with -D command line argument on application start or with System.setProperty("io.konik.key","value"); within the application. When using the later method make sure that the property needed are set before Konik Configuration is loaded.

System Properties override file properties. This is can be useful in cases where you define a default configuration in the property file but want to have different configuration in a particular application instance.

4. JavaDoc API Documentation

We host the API Documentation for the last stable release.

API Documentation for latest release of Konik, PDFBox-carriage and iText-carriage.

5. ZUGFeRD Specification

Collection of links to the original ZUGFeRD Specification by AWV e.V.

  • Das ZUGFeRD-Format, Spezifikation und Umsetzungsregeln zum branchen- übergreifenden Kern-Rechnungsformat des Forums elektronische Rechnung Deutschland (FeRD)

  • Technische Dokumentation, Betriebswirtschaftliche Begriffe, Datenmodell und Schema

  • Codelisten, ZUGFeRD Version 1.0, Codelisten Version 1.0

  • Änderungshistorie ZU RC, Hinweise zu Änderungen von Version ZUGFeRD Release Candidate (RC) zu ZUGFeRD 1.0

6. CSV file import and export

Konik >1.1.0 introduces the feature to import and export CSV files. This makes it possible to create create multiple ZUGFeRD invoices from a CSV file. Below you can find exemplary CSV file that contains 3 documents and one CSV with description of each column.

Keep in mind that Konik allows you to import/export multiple:

  • items

  • tax information

in a single file. Columns that hold these information are indexed which means that you can define more than one item or tax information and these values will be mapped to a list of objects. For example, if you would like to define 3 items, the header of the CSV file should contain:

items[0].name,items[0].quantity,items[0].unit,items[0].unitPrice,items[0].taxPercent,items[1].name,items[1].quantity,items[1].unit,items[1].unitPrice,items[1].taxPercent,items[2].name,items[2].quantity,items[2].unit,items[2].unitPrice,items[2].taxPercent

As you can see indexes start from 0 to n-1 when you add n elements.

6.1. CSV file fields description

Field name Description

header.invoiceNumber

Invoice number

header.type

Document type (supported types: rechnung, gutschriftsanzeige, angebot,bestellung, proformarechnung, teilrechnung, korrigierte rechnung, konsolidierte rechnung, vorauszahlungsrechnung, invoice, credit note, offer, order, proforma invoice, partial invoice, corrected invoice, consolidated invoice, prepayment invoice)

header.issued

Date with format yyyyMMdd

header.dueDate

Date with format yyyyMMdd

header.reference

Payment reference

header.customerNumber

Optional customer number (if exists)

header.currency

Currency code (e.g. EUR, USD, CHF, GBP)

header.note

Optional note

recipient.name

Recipient name

recipient.contactName

Recipient contact person

recipient.addressLine1

Address line 1

recipient.addressLine2

Address line 2

recipient.city

City name

recipient.postcode

Postcode

recipient.countryCode

Country code e.g. DE, UK, US, CH, FR, SE

recipient.email

Recipient email address

recipient.taxes[n].number

Tax number

recipient.taxes[n].type

Check reference_codes.csv for all available codes

recipient.bankInfo.bankName

Recipient’s bank name (if present)

recipient.bankInfo.bic

Recipient’s bank BIC

recipient.bankInfo.iban

Recipient’s bank account IBAN

issuer.name

Issuer name

issuer.contactName

Issuer contact person

issuer.addressLine1

Address line 1

issuer.addressLine2

Address line 2

issuer.city

City name

issuer.postcode

Postcode

issuer.countryCode

Country code (e.g. DE, UK, US, CH, FR, SE)

issuer.email

Issuer’s e-mail address

issuer.taxes[n].number

Similar to recipient.taxes[n].number

issuer.taxes[n].type

Similar to recipient.taxes[n].type

issuer.bankInfo.bankName

Similar to recipient.bankInfo.bankName

issuer.bankInfo.bic

Similar to recipient.bankInfo.bic

issuer.bankInfo.iban

Similar to recipient.bankInfo.iban

items[n].name

Item name

items[n].quantity

Quantity (decimal number)

items[n].unit

Check unit_codes.csv for available codes

items[n].unitPrice

Unit price (decimal number)

items[n].taxPercent

Tax percent (decimal number)

6.2. Convert PDF file to ZUGFeRD compliant invoice

Konik CSV feature allows you to convert plain PDF invoice to ZUGFeRD compliant one, using model created from your CSV file. All you have to do is add two optional columns to your CSV file (e.g. in the beginning of the file)

Field name Description

file.input

Path to plain PDF invoice file

file.output

(Optional) Target ZUGFeRD compliant PDF file. If missing, Konik will create output file next to the input path with _zugferd.pdf postfix.

6.2.1. Example: convert 2 PDF files to ZUGFeRD compliant invoice

Let’s start with downloading the latest Konik distribution (>1.0.0) and other dependencies. Here is the list of all required dependencies:

commons-beanutils-1.9.2.jar
commons-io-2.4.jar
commons-lang3-3.3.2.jar
commons-logging-1.2.jar
dozer-5.4.0.jar
guava-18.0.jar
harness-1.0.0.jar
konik-1.1.0-SNAPSHOT.jar
log4j-1.2.17.jar
nv-i18n-1.13.jar
pdfbox-2.0.0-RC2.jar
pdfbox-carriage-1.0.0-SNAPSHOT.jar
pdfconverter-1.0.21.jar
slf4j-api-1.7.12.jar
slf4j-log4j12-1.7.7.jar
super-csv-2.4.0.jar
super-csv-dozer-2.4.0.jar
validation-api-1.1.0.Final.jar
xmpbox-2.0.0-RC2.jar

ATTENTION: Keep in mind that it uses pdfconverter-1.0.21.jar library, which is not open source. PDFConverter handles PDF to PDF/A-3b format conversion - without it you wont be able to attach ZUGFeRD attachment to your invoice. If you want to use PDFConverter contact us via http://konik.io Otherwise you will be able to use only PDF/A compatible files as an input.

Create a new directory:

mkdir -p konik-csv/lib
cd konik-csv

and download all dependencies to the newly created lib subdirectory. In next step create separate directories for input and output files:

# You are in konik-csv/ directory
mkdir input
mkdir output

You can also create a configuration file for Log4j to see all logs in your console (this is optional):

# You are still in konik-csv/ directory
touch log4j.properties

Here is exemplary Log4j configuration you may use (just paste it to log4j.properties using your favorite text editor):

# Root logger option
log4j.rootLogger=INFO, stdout

# Direct log messages to stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n

In this example I will use following CSV file:

file.input,file.output,header.invoiceNumber,header.type,header.issued,header.dueDate,header.reference,header.customerNumber,header.currency,header.note,recipient.name,recipient.contactName,recipient.addressLine1,recipient.addressLine2,recipient.city,recipient.postcode,recipient.countryCode,recipient.email,recipient.taxes[0].number,recipient.taxes[0].type,recipient.taxes[1].number,recipient.taxes[1].type,recipient.bankInfo.bankName,recipient.bankInfo.bic,recipient.bankInfo.iban,issuer.name,issuer.contactName,issuer.addressLine1,issuer.addressLine2,issuer.city,issuer.postcode,issuer.countryCode,issuer.email,issuer.taxes[0].number,issuer.taxes[0].type,issuer.bankInfo.bankName,issuer.bankInfo.bic,issuer.bankInfo.iban,items[0].name,items[0].quantity,items[0].unit,items[0].unitPrice,items[0].taxPercent,items[1].name,items[1].quantity,items[1].unit,items[1].unitPrice,items[1].taxPercent
invoice.pdf,,INVOICE/2015/11/22,Rechnung,20151214,20151231,[email protected],123123123123,EUR,This is simple note in two separate lines,Lorem Ipsum LTD,Joe Doe,Baker Street 21,,London,8231233,DE,[email protected],UK2123432123,FC,UK1231232322,VA,,,,Microsoft,Bill Gates,Silicon Valley 21,,"Los Angeles, California",8323443,US,[email protected],US123123345345,FC,Test Bank Account,TESTBNK,PL123123123123132,Computer mouse,1,UNIT,79,19,Transport service,1,UNIT,9.99,19
invoice2.pdf,,INVOICE/2015/11/23,Rechnung,20151215,20151229,[email protected],123123123123,EUR,email: [email protected],Lorem Ipsum LTD,Joe Doe,Baker Street 21,,London,8231233,DE,[email protected],UK2123432123,FC,UK1231232322,VA,,,,Test Company LTD,,Test Street 2,,Berlin,34234,DE,,DE123123123,FC,Test Bank Account,TESTBNK,PL123123123123132,Beer,8,LITRE,17,8,,,,,

It contains 2 input files: invoice.pdf and invoice2.pdf with no output file specified - we are going to use _zugferd.pdf prefixed files created in the output directory specified via command line. Now, let’s put those 2 input PDF files to the konik-csv/input directory. CSV file is stored in konik-csv/example.csv path.

Now let’s run io.konik.csv.pdf.CsvToZUGFeRDConverter to process CSV file and create ZUGFeRD compliant using data from CSV file and put those newly created PDF/A-3b files to our output subdirectory. Here is what the command looks like:

java -cp "`pwd`/lib/*" -Dlog4j.configuration="file:`pwd`/log4j.properties" -DinputPath="`pwd`/input" -DoutputPath="`pwd`/output" io.konik.csv.pdf.CsvToZUGFeRDConverter example.csv

Keep in mind that in this example we are using Log4j properties file, you can remove -Dlog4j.configuration="file:`pwd/log4j.properties"` from the command line if you don’t want to log any events to your console or any logger appender.

Here is what the output of given command looks like:

2016-01-26 15:16:37 INFO  CsvToZUGFeRDConverter:128 - ----------------------------------------------------------
2016-01-26 15:16:37 INFO  CsvToZUGFeRDConverter:129 - CSV file:		/tmp/konik-csv/example.csv
2016-01-26 15:16:37 INFO  CsvToZUGFeRDConverter:130 - Input path:	/tmp/konik-csv/input
2016-01-26 15:16:37 INFO  CsvToZUGFeRDConverter:131 - Output path:	/tmp/konik-csv/output
2016-01-26 15:16:37 INFO  CsvToZUGFeRDConverter:132 - ----------------------------------------------------------
2016-01-26 15:16:37 INFO  GlobalSettings:113 - Trying to find Dozer configuration file: dozer.properties
2016-01-26 15:16:37 WARN  GlobalSettings:118 - Dozer configuration file not found: dozer.properties.  Using defaults for all Dozer global properties.
2016-01-26 15:16:37 INFO  DozerInitializer:70 - Initializing Dozer. Version: 5.4.0, Thread Name: main
2016-01-26 15:16:38 INFO  JMXPlatformImpl:66 - Dozer JMX MBean [org.dozer.jmx:type=DozerStatisticsController] auto registered with the Platform MBean Server
2016-01-26 15:16:38 INFO  JMXPlatformImpl:66 - Dozer JMX MBean [org.dozer.jmx:type=DozerAdminController] auto registered with the Platform MBean Server
2016-01-26 15:16:38 INFO  DozerBeanMapper:175 - Initializing a new instance of dozer bean mapper.
2016-01-26 15:16:38 INFO  DozerBeanMapper:175 - Initializing a new instance of dozer bean mapper.
2016-01-26 15:16:38 INFO  CsvToZUGFeRDConverter:36 - CSV file contains 2 rows, 0 errors
2016-01-26 15:16:38 INFO  CsvToZUGFeRDConverter:42 - Processing row 1
2016-01-26 15:16:38 INFO  CsvToZUGFeRDConverter:48 - Input file for given row present...
2016-01-26 15:16:38 INFO  CsvToZUGFeRDConverter:52 - Input file: /tmp/konik-csv/input/invoice.pdf
2016-01-26 15:16:38 INFO  CsvToZUGFeRDConverter:60 - Output file: /tmp/konik-csv/output/invoice_zugferd.pdf
2016-01-26 15:16:38 INFO  CsvToZUGFeRDConverter:62 - Starting append invoice process...
2016-01-26 15:16:38 INFO  ConverterBox:34 - Document conversation process started.
2016-01-26 15:16:38 INFO  ConverterBox:63 - Document conversation process finished in 36 ms.
2016-01-26 15:16:38 INFO  ConverterBox:96 - Document conversation process started.
2016-01-26 15:16:38 INFO  ConverterBox:106 - Document conversation process finished in 0 ms.
2016-01-26 15:16:38 INFO  CsvToZUGFeRDConverter:64 - Invoice appended to the output file
2016-01-26 15:16:38 INFO  CsvToZUGFeRDConverter:42 - Processing row 2
2016-01-26 15:16:38 INFO  CsvToZUGFeRDConverter:48 - Input file for given row present...
2016-01-26 15:16:38 INFO  CsvToZUGFeRDConverter:52 - Input file: /tmp/konik-csv/input/invoice2.pdf
2016-01-26 15:16:38 INFO  CsvToZUGFeRDConverter:60 - Output file: /tmp/konik-csv/output/invoice2_zugferd.pdf
2016-01-26 15:16:38 INFO  CsvToZUGFeRDConverter:62 - Starting append invoice process...
2016-01-26 15:16:38 INFO  ConverterBox:34 - Document conversation process started.
2016-01-26 15:16:38 INFO  ConverterBox:63 - Document conversation process finished in 2 ms.
2016-01-26 15:16:38 INFO  ConverterBox:96 - Document conversation process started.
2016-01-26 15:16:38 INFO  ConverterBox:106 - Document conversation process finished in 0 ms.
2016-01-26 15:16:38 INFO  CsvToZUGFeRDConverter:64 - Invoice appended to the output file

In the result we should find 2 new files in konik-csv/output directory:

konik-csv % ls -la output
razem 48
drwxrwxr-x. 2 konik konik    80 01-26 15:16 .
drwxrwxr-x. 5 konik konik   140 01-26 15:15 ..
-rw-rw-r--. 1 konik konik 22367 01-26 15:16 invoice2_zugferd.pdf
-rw-rw-r--. 1 konik konik 22505 01-26 15:16 invoice_zugferd.pdf

7. Z-RECHNUNG SDK

The Konik library integrates with Z-RECHNUNG using SDK components. It allows using all Z-RECHNUNG features directly from your project that uses Konik. This documentation describes how to start using Konik Z-RECHNUNG SDK and use all the Z-RECHNUNG features in your project.

7.1. Before you start

Before you start, Register on Z-RECHNUNG and then go to the Z-RECHNUNG Application Settings page and claim your API key.

One exemplary API key may look like this: 7c8f89cd-e1d9-44f1-ba3c-62f3ccde1909

7.2. Setup config class

Now you can instantiate SDK main configuration class - ZinvoiceApiConfig.java. It’s recommended to instantiate this class as a commonly shared object e.g. Spring Framework bean component. You only need to create one instance and use it as a dependency everywhere this object is required. Here is the code sample of the method that creates API config class instance:

public ZinvoiceApiConfig zinvoiceApiConfig() {
    return new ZinvoiceApiConfig(
            "f4eb6f7b-e3c3-43b2-a456-c116315102b6", (1)
            "https://app.z-rechnung.com" (2)
    );
}
1 Your API key
2 Absolute URL to Z-RECHNUNG online service, without trailing slash.

7.2.1. Setup SDK config class with properties file

You can also instantiate ZinvoiceApiConfig class using default constructor. In that case values from properties file or passed as a system property will be loaded. You can define them in a property file stored in src/main/resources or pass them as a system property with -D option.

io.konik.zinvoice.api-key=1234-1234-1234-1234
io.konik.zinvoice.url=https://app.Z-RECHNUNG.com

More information about overriding default values with properties can be found here - Konik Configuration

7.3. Setup HTTP client class

Each SDK component uses ZinvoiceHttpClient.java class for establishing Z-RECHNUNG connection. It uses ZinvoiceApiConfig instance to get API key and Z-RECHNUNG absolute URL. Each request contains header API-KEY: {your API key here} to authenticate the user.

public ZinvoiceHttpClient zinvoiceHttpClient() {
    return new ZinvoiceHttpClient(
            zinvoiceApiConfig() (3)
    );
}
1 ZinvoiceApiConfig instance (previously defined method in this example)

7.4. Access Z-RECHNUNG services

Currently SDK provides components:

7.4.1. InvoicesApi

InvoicesApi implementation class RestInvoicesApi.java allows you to access your Z-RECHNUNG’s invoices outbox and inbox.

public InvoicesApi invoicesApi() {
    return new RestInvoicesApi(zinvoiceHttpClient()); (6)
}
1 ZinvoiceHttpClient instance

7.4.2. InvoiceApi

InvoiceApi implementation class RestInvoiceApi.java allows you to manage all aspects of the invoice object, including: creating, loading, updating, deleting, downloading, sending to email and uploading ZUGFeRD compatible invoice.

Keep in mind that some features (like downloading PDF invoice for the first time) cost credits. If you don’t have sufficient credits amount, InsufficientCreditsAmountException will be thrown.

public InvoiceApi invoiceApi() {
    return new RestInvoiceApi(zinvoiceHttpClient()); (7)

}
1 ZinvoiceHttpClient instance

7.5. Examples

7.5.1. Loading all created invoices

InvoicesApi invoicesApi = new RestInvoicesApi(zinvoiceHttpClient);
List<InvoicesListElement> outbox = invoicesApi.outbox();
for (InvoiceListElement invoice : outbox) {
    System.out.println(invoice.getId());
}

7.5.2. Loading invoice via ID

InvoiceApi invoiceApi = new RestInvoiceApi(zinvoiceHttpClient);
String invoiceId = "b3f3cb68-5524-11e5-bd6a-28d24459a4d4";
InvoiceDocument invoiceDocument = invoiceApi.getInvoice(invoiceId);
Invoice invoice = invoiceDocument.getInvoice();

7.5.3. Downloading PDF invoice

InvoiceApi invoiceApi = new RestInvoiceApi(zinvoiceHttpClient);
String invoiceId = "b3f3cb68-5524-11e5-bd6a-28d24459a4d4";
InputStream pdf = invoiceApi.downloadInvoiceAsPDF(invoiceId);

FileOutputStream fos = new FileOutputStream("/tmp/invoice.pdf");
ByteStreams.copy(pdf,fos);
fos.close();

7.5.4. Sending invoice via e-mail

InvoiceApi invoiceApi = new RestInvoiceApi(zinvoiceHttpClient);
String invoiceId = "b3f3cb68-5524-11e5-bd6a-28d24459a4d4";
invoiceApi.sendInvoice(invoiceId, "[email protected]", "You can put a message here");