Using the Mustang classes

Simple invoice

There is one test file which you can use for further reference, one on the XRechnung and one regarding the invoice importer.
First there is the construction and configuration of an exporter, which loads the PDF/A-file to attach the invoice to:


import org.mustangproject.ZUGFeRD.IZUGFeRDExporter;
import org.mustangproject.ZUGFeRD.ZUGFeRDExporterFromPDFA;
//...
        String sourcePDF="MustangGnuaccountingBeispielRE-20190610_507blanko.pdf";
        try {
            IZUGFeRDExporter ze = new ZUGFeRDExporterFromPDFA().load(sourcePDF).setProducer("My Application").
                    setCreator(System.getProperty("user.name"));
        } catch (IOException e) {
            e.printStackTrace();
        }


Then you do the same with your invoice, which has a lot more configuration:


            ze.setTransaction(new Invoice().setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date())
                    .setSender(new TradeParty("ACME co", "teststr", "55232", "teststadt", "DE")
                            .addBankDetails(new BankDetails("777666555", "DE4321"))).setOwnTaxID("4711").setOwnVATID("DE19990815")
                    .setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE")
                            .setContact(new Contact("nameRep", "phoneRep", "emailRep@test.com"))).setNumber("X12")
                    .addItem(new Item(new Product("Testproduct", "", "C62", new BigDecimal(19)),
                            new BigDecimal(2.5), new BigDecimal(1.0))));

You can chain several addItem behind one another. In this case we have an invoice numbered “X12” with a 1.0 times 19%, 2.5€ “Testproduct” in the unit “piece”(C62, refer to the sheet units in this list) with 19% VAT.
Now export it


ze.export("factur-x.pdf");

That’s it. Feel free to validate it and please make sure the calculated amounts in the XML match those in your PDF.

Recipients

In Germany, you get a valid XRechnung if you specify the Leitweg-ID as reference number, use the XRechnung profile and specify the rest of the required attributes, i.e. bank (transfer) details, seller contact phone and email and seller and buyer organization email like this:


import org.mustangproject.*;
import org.mustangproject.ZUGFeRD.*;
import java.math.BigDecimal;
import java.nio.charset.StandardCharsets;
import java.util.Date;
//...

        TradeParty recipient = new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE").setEmail("info@mueller.com");
        Invoice i = new Invoice().setDueDate(new Date()).setIssueDate(new
                        Date()).setDeliveryDate(new Date())
                .setSender(new TradeParty("Test company", "teststr", "55232", "teststadt", "DE").addTaxID("DE4711").addVATID("DE0815").setContact(new org.mustangproject.Contact("Hans Test", "+49123456789", "test@example.org")).addBankDetails(new org.mustangproject.BankDetails("DE12500105170648489890", "COBADEFXXX")).setEmail("info@example.org"))
                .setRecipient(recipient)
                .setReferenceNumber("991-01484-64")//leitweg-id
                .setNumber("123").addItem(new Item(new Product("Testprodukt", "", "C62", BigDecimal.ZERO), new BigDecimal("1.00"), new BigDecimal(1.0)));

		ZUGFeRD2PullProvider zf2p = new ZUGFeRD2PullProvider();
		zf2p.setProfile(Profiles.getByName("XRechnung"));
		zf2p.generateXML(i);
		String theXML = new String(zf2p.getXML(), StandardCharsets.UTF_8);
	

In France, Recipients are identified via their Siret number. It’s typecode is 0002, which can be set via setLegalOrganisation:


TradeParty recipient = new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE");
String siret="0815";
String sirenTypeCode="0002";
recipient.setLegalOrganisation(new LegalOrganisation(siret,sirenTypeCode));

For german B2G invoices, as described here, the Leitweg-ID can be set with invoice.setReferenceNumber().

Verify amounts

To verify that the total Mustang calculated matches the ones you mention in your PDF you can use


		TransactionCalculator tc=new TransactionCalculator(i);
		// now confirm tc.getTotalGross() matches your total

Corrected invoice

To revoke and reissue an issue send a corrected invoice, use a negative quantity on the items to be revoked and use setCorrection referring to the number of the invoice. The negative quantity will also mean a negative grand total. The following will nullify the previous invoice:


ze.setTransaction(new Invoice().setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date())
.setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE").addBankDetails(new BankDetails("777666555", "DE4321"))).setOwnTaxID("4711").setOwnVATID("DE19990815")
.setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE")
.setContact(new Contact("nameRep", "phoneRep", "emailRep@test.com"))).setNumber("X13")
.addItem(new Item(new Product("Testproduct", "", "C62", new BigDecimal(19)), new BigDecimal("2.5"), new BigDecimal(-1.0))).setCorrection("X12"));

Credit notes

Credit notes can be implemented with setCreditNote() on the invoice object and positive amounts:


      IZUGFeRDExporter ze = new ZUGFeRDExporterFromPDFA().load(sourcePDF).setProducer("My Application").
                    setCreator(System.getProperty("user.name"));
            Invoice i = new Invoice().setIssueDate(new Date()).setDueDate(new Date()).setDetailedDeliveryPeriod(new Date(), new Date()).setDeliveryDate(new Date()).setSender(new TradeParty("ACME inc", "teststr", "55232", "teststadt", "DE").addTaxID("4711").addVATID("DE0815").addBankDetails(new BankDetails("DE88200800000970375700", "COBADEFFXXX"))).setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE").addVATID("DE0815")).setNumber("0815")
                    .addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), new BigDecimal(1), new BigDecimal(1)))
                    .addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), new BigDecimal(1), new BigDecimal(10)))
                    .addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), new BigDecimal(1.41), new BigDecimal(3)))
                    .setCreditNote();

            ze.setTransaction(i);

            ze.export("factur-x.pdf");
            System.out.println("Invoice written.");

Charges and allowances

Charges and allowances can be on document level or on item level, and they can be absolute amounts or percentual. They need to indicate which VAT rate they refer to and some profiles like EN16931 don’t allow charges on item level.

For a 50% charge on item level if the item is 19% VAT you can use


.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), price, new BigDecimal(1.0)).addCharge(new Charge().setPercent(new BigDecimal(50)).setTaxPercent(new BigDecimal(19))))

and for a 10€ allowance on document level chain the following on the invoice object:


.addAllowance(new Allowance(new BigDecimal(10)).setTaxPercent(new BigDecimal(19)))

Cash discount

In profiles XRechnung or Extended you can add 3% in 7 and 2% in 14 days cash discount as follows:


		Invoice i = new Invoice().setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date())
				.setSender(new TradeParty(orgname,"teststr","55232","teststadt","DE").setEmail("sender@example.com").addTaxID("DE4711").addVATID("DE0815").setContact(new Contact("Hans Test","+49123456789","test@example.org")).addBankDetails(new BankDetails("DE12500105170648489890","COBADEFXXX")))
				.setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE").setEmail("recipient@sample.org"))
				.addCashDiscount(new CashDiscount(new BigDecimal(3),7))
				.addCashDiscount(new CashDiscount(new BigDecimal(2),14))
				.setNumber(number).addItem(new Item(new Product("Testprodukt", "", "C62", BigDecimal.ZERO), amount, new BigDecimal(1.0)));

File attachments

You can add enclosures substantiating the invoice, like measurements or time sheets, base64-coded within in die XML-structure or as additional files to be embedded into the PDF.
If you know you are using a PDF/A-1 as input you can specifically use the attachFile method
(and the operation ignorePDFAErrors() if you e.g. already made sure your PDF-A input is valid)


 ZUGFeRDExporterFromA1 ze = new ZUGFeRDExporterFromA1().setProducer("My Application")
					 .setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2).ignorePDFAErrors()
					 .load("sourcefile.pdf")) {
			byte[] b = {12, 13};
			ze.attachFile("one.pdf", b, "application/pdf", "Alternative");
			ze.attachFile("two.pdf", b, "application/pdf", "Alternative");
			ze.setTransaction(new Invoice().setDueDate(new Date()).setIssueDate(new Date()).setDeliveryDate(new Date()).setSender(new TradeParty(orgname, "teststr", "55232", "teststadt", "DE").addTaxID(taxID)).setOwnVATID("DE0815").setRecipient(new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE").addVATID("DE4711").setContact(new Contact("Franz Müller", "01779999999", "fr...@mueller.de", "teststr. 12", "55232", "Entenhausen", "DE"))).setNumber("0815").addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), new BigDecimal(1.0), new BigDecimal(1.0)))

			);
			ze.export("filename.pdf");

Export from PDF/A-3 files

Please note that ZUGFeRDExporterFromPDFA detects the PDF/A-version and acts on A-1 and A-3 automatically, if you are sure you need PDF/A-3 input you can also use ZUGFeRDExporterFromA3 instead of ZUGFeRDExporterFromA1. Since the factur-x file is always attached the source PDF/A-3 may not already have e.g. a factur-x.xml attachment, so overwriting factur-x is not yet supported.


 ZUGFeRDExporterFromA3 ze = new ZUGFeRDExporterFromA3().setProducer("My Application")
					 .setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2).ignorePDFAErrors()
					 .load("sourcefile.pdf")) {
...

Reading

To parse invoices you can use extractInvoice from ZUGFeRDInvoiceImporter


ZUGFeRDInvoiceImporter zii=new ZUGFeRDInvoiceImporter("./target/testout-ZF2new.pdf");
Invoice invoice=zii.extractInvoice(); // surround this with try/catch

Now you can e.g. get the invoice number (

invoice.getNumber()

), the issue date
(

invoice.getIssueDate()

), the number of items (

invoice.getZFItems().length

), the seconds item quantity (

invoice.getZFItems()[1].getQuantity().toString())

), the unit of the product of the third item(

invoice.getZFItems()[2].getProduct().getUnit()

), the street address of the recipient (

invoice.getRecipient().getStreet()

) or calculate/check the total amount like this:


		TransactionCalculator tc=new TransactionCalculator(invoice);
		assertEquals(new BigDecimal("571.04"),tc.getTotalGross());