Creating PDF invoices from scratch (Basic profile)

This is a code example of iText PDF, discover more.

31st August 2015
admin-marketing

Switch code for this example

PdfInvoicesBasic.java
  1. /*
  2.  * This example was written by Bruno Lowagie.
  3.  */
  4. package zugferd;
  5.  
  6. import com.itextpdf.text.Chunk;
  7. import com.itextpdf.text.Document;
  8. import com.itextpdf.text.DocumentException;
  9. import com.itextpdf.text.Element;
  10. import com.itextpdf.text.Font;
  11. import com.itextpdf.text.Paragraph;
  12. import com.itextpdf.text.pdf.AFRelationshipValue;
  13. import com.itextpdf.text.pdf.BaseFont;
  14. import com.itextpdf.text.pdf.ICC_Profile;
  15. import com.itextpdf.text.pdf.PdfAConformanceLevel;
  16. import com.itextpdf.text.pdf.PdfAWriter;
  17. import com.itextpdf.text.pdf.PdfArray;
  18. import com.itextpdf.text.pdf.PdfDate;
  19. import com.itextpdf.text.pdf.PdfDictionary;
  20. import com.itextpdf.text.pdf.PdfFileSpecification;
  21. import com.itextpdf.text.pdf.PdfName;
  22. import com.itextpdf.text.pdf.PdfPCell;
  23. import com.itextpdf.text.pdf.PdfPTable;
  24. import com.itextpdf.text.pdf.PdfWriter;
  25. import com.itextpdf.text.xml.xmp.PdfAXmpWriter;
  26. import com.itextpdf.text.zugferd.InvoiceDOM;
  27. import com.itextpdf.text.zugferd.exceptions.DataIncompleteException;
  28. import com.itextpdf.text.zugferd.exceptions.InvalidCodeException;
  29. import com.itextpdf.text.zugferd.profiles.BasicProfile;
  30. import com.itextpdf.xmp.XMPException;
  31.  
  32. import java.io.File;
  33. import java.io.FileInputStream;
  34. import java.io.FileOutputStream;
  35. import java.io.IOException;
  36. import java.sql.SQLException;
  37. import java.text.ParseException;
  38. import java.text.SimpleDateFormat;
  39. import java.util.Date;
  40. import java.util.List;
  41.  
  42. import javax.xml.parsers.ParserConfigurationException;
  43. import javax.xml.transform.TransformerException;
  44.  
  45. import org.xml.sax.SAXException;
  46.  
  47. import zugferd.data.InvoiceData;
  48. import zugferd.pojo.Invoice;
  49. import zugferd.pojo.Item;
  50. import zugferd.pojo.PojoFactory;
  51. import zugferd.pojo.Product;
  52.  
  53. /**
  54.  * Reads invoice data from a test database and creates ZUGFeRD invoices
  55.  * (Basic profile).
  56.  * @author Bruno Lowagie
  57.  */
  58. public class PdfInvoicesBasic {
  59.     public static final String DEST = "results/zugferd/pdf/basic%05d.pdf";
  60.     public static final String ICC = "resources/data/sRGB_CS_profile.icm";
  61.     public static final String FONT = "resources/fonts/OpenSans-Regular.ttf";
  62.     public static final String FONTB = "resources/fonts/OpenSans-Bold.ttf";
  63.    
  64.     protected Font font10;
  65.     protected Font font10b;
  66.     protected Font font12;
  67.     protected Font font12b;
  68.     protected Font font14;
  69.    
  70.     public static void main(String[] args) throws IOException, DocumentException, ParserConfigurationException, SQLException, SAXException, TransformerException, XMPException, ParseException, DataIncompleteException, InvalidCodeException {
  71.         File file = new File(DEST);
  72.         file.getParentFile().mkdirs();
  73.         PdfInvoicesBasic app = new PdfInvoicesBasic();
  74.         PojoFactory factory = PojoFactory.getInstance();
  75.         List invoices = factory.getInvoices();
  76.         for (Invoice invoice : invoices) {
  77.             app.createPdf(invoice);
  78.         }
  79.         factory.close();
  80.     }
  81.    
  82.     public PdfInvoicesBasic() throws DocumentException, IOException {
  83.         BaseFont bf = BaseFont.createFont(FONT, BaseFont.WINANSI, BaseFont.EMBEDDED);
  84.         BaseFont bfb = BaseFont.createFont(FONTB, BaseFont.WINANSI, BaseFont.EMBEDDED);
  85.         font10 = new Font(bf, 10);
  86.         font10b = new Font(bfb, 10);
  87.         font12 = new Font(bf, 12);
  88.         font12b = new Font(bfb, 12);
  89.         font14 = new Font(bf, 14);
  90.     }
  91.    
  92.     public void createPdf(Invoice invoice) throws ParserConfigurationException, SAXException, TransformerException, IOException, DocumentException, XMPException, ParseException, DataIncompleteException, InvalidCodeException {
  93.         String dest = String.format(DEST, invoice.getId());
  94.         InvoiceData invoiceData = new InvoiceData();
  95.         BasicProfile basic = invoiceData.createBasicProfileData(invoice);
  96.        
  97.         // step 1
  98.         Document document = new Document();
  99.         // step 2
  100.         PdfAWriter writer = PdfAWriter.getInstance(document, new FileOutputStream(dest), PdfAConformanceLevel.ZUGFeRDBasic);
  101.         writer.setPdfVersion(PdfWriter.VERSION_1_7);
  102.         writer.createXmpMetadata();
  103.         writer.getXmpWriter().setProperty(PdfAXmpWriter.zugferdSchemaNS, PdfAXmpWriter.zugferdDocumentFileName, "ZUGFeRD-invoice.xml");
  104.         // step 3
  105.         document.open();
  106.         // step 4
  107.         ICC_Profile icc = ICC_Profile.getInstance(new FileInputStream(ICC));
  108.         writer.setOutputIntents("Custom", "", "http://www.color.org", "sRGB IEC61966-2.1", icc);
  109.        
  110.         // header
  111.         Paragraph p;
  112.         p = new Paragraph(basic.getName() + " " + basic.getId(), font14);
  113.         p.setAlignment(Element.ALIGN_RIGHT);
  114.         document.add(p);
  115.         p = new Paragraph(convertDate(basic.getDateTime(), "MMM dd, yyyy"), font12);
  116.         p.setAlignment(Element.ALIGN_RIGHT);
  117.         document.add(p);
  118.        
  119.         // Address seller / buyer
  120.         PdfPTable table = new PdfPTable(2);
  121.         table.setWidthPercentage(100);
  122.         PdfPCell seller = getPartyAddress("From:",
  123.                 basic.getSellerName(),
  124.                 basic.getSellerLineOne(),
  125.                 basic.getSellerLineTwo(),
  126.                 basic.getSellerCountryID(),
  127.                 basic.getSellerPostcode(),
  128.                 basic.getSellerCityName());
  129.         table.addCell(seller);
  130.         PdfPCell buyer = getPartyAddress("To:",
  131.                 basic.getBuyerName(),
  132.                 basic.getBuyerLineOne(),
  133.                 basic.getBuyerLineTwo(),
  134.                 basic.getBuyerCountryID(),
  135.                 basic.getBuyerPostcode(),
  136.                 basic.getBuyerCityName());
  137.         table.addCell(buyer);
  138.         seller = getPartyTax(basic.getSellerTaxRegistrationID(),
  139.                 basic.getSellerTaxRegistrationSchemeID());
  140.         table.addCell(seller);
  141.         buyer = getPartyTax(basic.getBuyerTaxRegistrationID(),
  142.                 basic.getBuyerTaxRegistrationSchemeID());
  143.         table.addCell(buyer);
  144.         document.add(table);
  145.        
  146.         // line items
  147.         table = new PdfPTable(6);
  148.         table.setWidthPercentage(100);
  149.         table.setSpacingBefore(10);
  150.         table.setSpacingAfter(10);
  151.         table.setWidths(new int[]{7, 2, 1, 2, 2, 2});
  152.         table.addCell(getCell("Item:", Element.ALIGN_LEFT, font12b));
  153.         table.addCell(getCell("Price:", Element.ALIGN_LEFT, font12b));
  154.         table.addCell(getCell("Qty:", Element.ALIGN_LEFT, font12b));
  155.         table.addCell(getCell("Subtotal:", Element.ALIGN_LEFT, font12b));
  156.         table.addCell(getCell("VAT:", Element.ALIGN_LEFT, font12b));
  157.         table.addCell(getCell("Total:", Element.ALIGN_LEFT, font12b));
  158.         Product product;
  159.         for (Item item : invoice.getItems()) {
  160.             product = item.getProduct();
  161.             table.addCell(getCell(product.getName(), Element.ALIGN_LEFT, font12));
  162.             table.addCell(getCell(InvoiceData.format2dec(InvoiceData.round(product.getPrice())), Element.ALIGN_RIGHT, font12));
  163.             table.addCell(getCell(String.valueOf(item.getQuantity()), Element.ALIGN_RIGHT, font12));
  164.             table.addCell(getCell(InvoiceData.format2dec(InvoiceData.round(item.getCost())), Element.ALIGN_RIGHT, font12));
  165.             table.addCell(getCell(InvoiceData.format2dec(InvoiceData.round(product.getVat())), Element.ALIGN_RIGHT, font12));
  166.             table.addCell(getCell(
  167.                 InvoiceData.format2dec(InvoiceData.round(item.getCost() + ((item.getCost() * product.getVat()) / 100))),
  168.                 Element.ALIGN_RIGHT, font12));
  169.         }
  170.         document.add(table);
  171.        
  172.         // grand totals
  173.         document.add(getTotalsTable(
  174.                 basic.getTaxBasisTotalAmount(), basic.getTaxTotalAmount(), basic.getGrandTotalAmount(), basic.getGrandTotalAmountCurrencyID(),
  175.                 basic.getTaxTypeCode(), basic.getTaxApplicablePercent(),
  176.                 basic.getTaxBasisAmount(), basic.getTaxCalculatedAmount(), basic.getTaxCalculatedAmountCurrencyID()));
  177.        
  178.         // payment info
  179.         document.add(getPaymentInfo(basic.getPaymentReference(), basic.getPaymentMeansPayeeFinancialInstitutionBIC(), basic.getPaymentMeansPayeeAccountIBAN()));
  180.  
  181.         // XML version
  182.         InvoiceDOM dom = new InvoiceDOM(basic);
  183.         PdfDictionary parameters = new PdfDictionary();
  184.         parameters.put(PdfName.MODDATE, new PdfDate());
  185.         PdfFileSpecification fileSpec = writer.addFileAttachment(
  186.                 "ZUGFeRD invoice", dom.toXML(), null,
  187.                 "ZUGFeRD-invoice.xml", "application/xml",
  188.                 AFRelationshipValue.Alternative, parameters);
  189.         PdfArray array = new PdfArray();
  190.         array.add(fileSpec.getReference());
  191.         writer.getExtraCatalog().put(PdfName.AF, array);
  192.        
  193.         // step 5
  194.         document.close();
  195.     }
  196.    
  197.     public PdfPCell getPartyAddress(String who, String name, String line1, String line2, String countryID, String postcode, String city) {
  198.         PdfPCell cell = new PdfPCell();
  199.         cell.setBorder(PdfPCell.NO_BORDER);
  200.         cell.addElement(new Paragraph(who, font12b));
  201.         cell.addElement(new Paragraph(name, font12));
  202.         cell.addElement(new Paragraph(line1, font12));
  203.         cell.addElement(new Paragraph(line2, font12));
  204.         cell.addElement(new Paragraph(String.format("%s-%s %s", countryID, postcode, city), font12));
  205.         return cell;
  206.     }
  207.     public PdfPCell getPartyTax(String[] taxId, String[] taxSchema) {
  208.         PdfPCell cell = new PdfPCell();
  209.         cell.setBorder(PdfPCell.NO_BORDER);
  210.         cell.addElement(new Paragraph("Tax ID(s):", font10b));
  211.         if (taxId.length == 0) {
  212.             cell.addElement(new Paragraph("Not applicable", font10));
  213.         }
  214.         else {
  215.             int n = taxId.length;
  216.             for (int i = 0; i < n; i++) {
  217.                 cell.addElement(new Paragraph(String.format("%s: %s", taxSchema[i], taxId[i]), font10));
  218.             }
  219.         }
  220.         return cell;
  221.     }
  222.    
  223.     public PdfPTable getTotalsTable(String tBase, String tTax, String tTotal, String tCurrency,
  224.             String[] type, String[] percentage, String base[], String tax[], String currency[]) throws DocumentException {
  225.         PdfPTable table = new PdfPTable(6);
  226.         table.setWidthPercentage(100);
  227.         table.setWidths(new int[]{1, 1, 3, 3, 3, 1});
  228.         table.addCell(getCell("TAX", Element.ALIGN_LEFT, font12b));
  229.         table.addCell(getCell("%", Element.ALIGN_RIGHT, font12b));
  230.         table.addCell(getCell("Base amount:", Element.ALIGN_LEFT, font12b));
  231.         table.addCell(getCell("Tax amount:", Element.ALIGN_LEFT, font12b));
  232.         table.addCell(getCell("Total:", Element.ALIGN_LEFT, font12b));
  233.         table.addCell(getCell("", Element.ALIGN_LEFT, font12b));
  234.         int n = type.length;
  235.         for (int i = 0; i < n; i++) {
  236.             table.addCell(getCell(type[i], Element.ALIGN_RIGHT, font12));
  237.             table.addCell(getCell(percentage[i], Element.ALIGN_RIGHT, font12));
  238.             table.addCell(getCell(base[i], Element.ALIGN_RIGHT, font12));
  239.             table.addCell(getCell(tax[i], Element.ALIGN_RIGHT, font12));
  240.             double total = Double.parseDouble(base[i]) + Double.parseDouble(tax[i]);
  241.             table.addCell(getCell(InvoiceData.format2dec(InvoiceData.round(total)), Element.ALIGN_RIGHT, font12));
  242.             table.addCell(getCell(currency[i], Element.ALIGN_LEFT, font12));
  243.         }
  244.         PdfPCell cell = getCell("", Element.ALIGN_LEFT, font12b);
  245.         cell.setColspan(2);
  246.         cell.setBorder(PdfPCell.NO_BORDER);
  247.         table.addCell(cell);
  248.         table.addCell(getCell(tBase, Element.ALIGN_RIGHT, font12b));
  249.         table.addCell(getCell(tTax, Element.ALIGN_RIGHT, font12b));
  250.         table.addCell(getCell(tTotal, Element.ALIGN_RIGHT, font12b));
  251.         table.addCell(getCell(tCurrency, Element.ALIGN_LEFT, font12b));
  252.         return table;
  253.     }
  254.    
  255.     public PdfPCell getCell(String value, int alignment, Font font) {
  256.         PdfPCell cell = new PdfPCell();
  257.         cell.setUseAscender(true);
  258.         cell.setUseDescender(true);
  259.         Paragraph p = new Paragraph(value, font);
  260.         p.setAlignment(alignment);
  261.         cell.addElement(p);
  262.         return cell;
  263.     }
  264.    
  265.     public Paragraph getPaymentInfo(String ref, String[] bic, String[] iban) {
  266.         Paragraph p = new Paragraph(String.format(
  267.                 "Please wire the amount due to our bank account using the following reference: %s",
  268.                 ref), font12);
  269.         int n = bic.length;
  270.         for (int i = 0; i < n; i++) {
  271.             p.add(Chunk.NEWLINE);
  272.             p.add(String.format("BIC: %s - IBAN: %s", bic[i], iban[i]));
  273.         }
  274.         return p;
  275.     }
  276.    
  277.     public String convertDate(Date d, String newFormat) throws ParseException {
  278.         SimpleDateFormat sdf = new SimpleDateFormat(newFormat);
  279.         return sdf.format(d);
  280.     }
  281. }
Contact

Still have questions? 

We're happy to answer your questions. Reach out to us and we'll get back to you shortly.

Contact us
Stay updated

Join 11,000+ subscribers and become an iText PDF expert by staying up to date with our new products, updates, tips, technical solutions and happenings.

Subscribe Now