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:
ZUGFeRDExporterFromA1 ze = new ZUGFeRDExporterFromA1().setProducer("My Application").setCreator(System.getProperty("user.name")).ignorePDFAErrors().load(SOURCE_PDF));
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(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("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, e.g. bank (transfer) details and seller contact phone and email e.g. like this:
TradeParty recipient = new TradeParty("Franz Müller", "teststr.12", "55232", "Entenhausen", "DE");
Invoice i = new Invoice().setDueDate(new java.util.Date()).setIssueDate(new
java.util.Date()).setDeliveryDate(new java.util.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")))
.setRecipient(recipient)
.setReferenceNumber("991-01484-64")//leitweg-id
.setNumber("123").addItem(new org.mustangproject.Item(new org.mustangproject.Product("Testprodukt", "", "C62", java.math.BigDecimal.ZERO), new BigDecimal("1.00"), new java.math.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:
ZUGFeRDExporterFromA1 ze = new ZUGFeRDExporterFromA1().setProducer("My Application")
.setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2).ignorePDFAErrors()
.load("blanko.pdf")) {
Invoice i = new Invoice().setIssueDate(new Date()).setDueDate(new Date()).setDetailedDeliveryPeriod(new Date(), new Date()).setDeliveryDate(new Date()).setSender(new TradeParty(orgname, "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(number)
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), price, qty))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), price, qty))
.addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), price, qty)).setCreditNote();
ze.setTransaction(i);
ze.export("factur-x.pdf");
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)))
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:
ZUGFeRDExporterFromA1 ze = new ZUGFeRDExporterFromA1().setProducer("My Application")
.setCreator(System.getProperty("user.name")).setZUGFeRDVersion(2).ignorePDFAErrors()
.load("sourcefuile.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(number).addItem(new Item(new Product("Testprodukt", "", "C62", new BigDecimal(19)), price, new BigDecimal(1.0)))
);
ze.export("filename.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());