Skip to content
Filipe Roque edited this page Aug 14, 2020 · 44 revisions

Billy is a billing library for applications providing them with ability to create, manage, and store billing artifacts such as invoices and credit notes. It also supports the export of the persisted data in PDF and SAF-T formats.

Billy was built to be easily extended to support additional taxing systems for different countries. Billy's core module was based on the OECD's SAF-T schema, providing a standard module from which one can extend and further develop to support new modules for different legislation.

The objective is for all modules to be compliant with the existing regulations for their country/region. However, we do not intend to provide a certified library. This should be the responsibility of any application that uses or will use Billy.

Get Billy

You can obtain Billy by downloading the latest release or by cloning the latest sources from GitHub

Maven projects

Add the following maven dependency to your project pom.xml:

<dependency>
  <groupId>com.premiumminds</groupId>
  <artifactId>billy-portugal</artifactId>
  <version>3.3.1</version> <!-- UPDATE THIS -->
</dependency>

Check out sonatype repository for latest snapshots and releases.


Bootstrap Billy

Bootstrap incorporates entities that are essential for any application using Billy, for instance, the billy-portugal bootstrap provides you with all the contexts and taxes available for Portuguese legislation, providing an easy and quick start for new applications using Billy.

Just run main() from PortugalBootstrap to bootstrap Billy.

Get Started Guide

This guide combines an overview of Billy with a quick tutorial that helps you to get started. We'll follow the process of creating and issuing an invoice and then export it to pdf and to SAF-T(PT) xml format.

Initiating Billy

Start by creating a new instance of Billy:

BillyPortugal billyPortugal = new BillyPortugal();

This provides access to builders, issuing services, persistence services and export services for each available entity in Billy.

Creating the new application

First obtain the application builder:

PTApplication.Builder applicationBuilder = billyPortugal.applications().builder();

Populate it with the application's information:

applicationBuilder.setDeveloperCompanyName("Premium Minds")
                  .setDeveloperCompanyTaxIdentifier("12345789")
                  .setSoftwareCertificationNumber(123)
                  .setName("Billy")
                  .setVersion("1.0")
                  .setApplicationKeysPath(new URL("http://www.keys.path"));

Each application will need to have at least one contact, so we'll start by creating it.

Create a new contact

Obtain the builder and fill it with the required values:

PTContact.Builder contactBuilder = billyPortugal.contacts().builder();

contactBuilder.setName("Bob Conner")
              .setTelephone("219211231");

Now you can add the customer to the new application:

applicationBuilder.addContact(contactBuilder)
                  .setMainContact(contactBuilder);

Creating a new invoice

Billy's main focus is to manage invoices, so to create a new invoice, we'll start by getting the appropriate builder:

PTInvoice.Builder invoiceBuilder = billyPortugal.invoices().builder();

Lets define the simple parameters of the invoice:

invoiceBuilder.setSelfBilled(false)
              .setCancelled(false)
              .setBilled(false)
              .setDate(new Date())
              .setSourceId("Source ID")
              .setSourceBilling(SourceBilling.P);

Naturally, an invoice requires a business and a customer. These entities need to be first persisted and then their UID is set in the invoice.

Creating a new Business

As always we first obtain the builder and populated with the required values:

PTBusiness.Builder businessBuilder = billyPortugal.businesses().builder();

businessBuilder.addApplication(applicationBuilder) 
               .addContact(contactBuilder, true) 
               .setMainContactUID(contactBuilder.build().getUID())
               .setName("Business")
               .setCommercialName("Business, INC")
               .setFinancialID("500003564", "PT");

Creating a new address

You'll notice that the new business requires an address builder!

PTAddress.Builder addressBuilder = billyPortugal.addresses().builder();
addressBuilder.setStreetName("Av. 5 de Outubro")
              .setNumber("2")
              .setPostalCode("1000-100")
              .setCity("Lisbon")
              .setISOCountry("Portugal")
              .setDetails("Av. 5 de Outubro Nº 2 1000-100 Lisboa");

Add the new address to the business

businessBuilder.setAddress(addressBuilder)
               .setBillingAddress(addressBuilder);

After populating the businessBuilder we can persist it in Billy's database:

PTBusiness business = billyPortugal.businesses().persistence().create(businessBuilder);

Create a new Customer

The process of creating a new customer is similar to creating a business:

PTCustomer.Builder customerBuilder = billyPortugal.customers().builder();

For the sake of simplicity, we'll reuse the previously defined addressBuilder and contactBuilder used in the business creation:

customerBuilder.setName("John Conner")
               .setTaxRegistrationNumber("123456789", "PT")
               .addAddress(addressBuilder, true)
               .setBillingAddress(addressBuilder)
               .setShippingAddress(addressBuilder)
               .setHasSelfBillingAgreement(false)
               .addContact(contactBuilder);

Now we can persist it in Billy's database:

PTCustomer customer = billyPortugal.customers().persistence().create(customerBuilder);

After creating and persisting the customer and the business in the database, we must add them to the invoice:

invoiceBuilder.setBusinessUID(business.getUID())
              .setCustomerUID(customer.getUID());

Creating new Invoice Entries

An invoice has one or more entries. Each entry has all information about the good/product such as price, currency, description, etc.

To create a new entry we first first obtain the builder:

PTInvoiceEntry.Builder entryBuilder = billyPortugal.invoices().entryBuilder();

Set the required fields:

entryBuilder.setAmountType(AmountType.WITH_TAX)
            .setCurrency(Currency.getInstance("EUR"))
            .setContextUID(billyPortugal.contexts().portugal().allRegions().getUID())
            .setQuantity("10")
            .setTaxPointDate(new Date())
            .setUnitAmount(AmountType.WITH_TAX, "100");   

Creating a new Product

Again create and populate the product builder:

PTProduct.Builder productBuilder = billyPortugal.products().builder();

productBuilder.setDescription(description)
              .setNumberCode("1")
              .setProductCode("1")
              .setType(ProductType.GOODS)
              .setUnitOfMeasure("kg")
              .addTaxUID(billyPortugal.taxes().continent().normal().getUID());

Pesiste the product:

PTProduct product = billyPortugal.products().persistence().create(product);

Now add the product to the invoice entry:

entryBuilder.setProductUID(product.getUID())
            .setDescription(product.getDescription())
            .setUnitOfMeasure(product.getUnitOfMeasure());

We can then add this entry to the invoice:

invoiceBuilder.addEntry(entryBuilder);

Issuing Service

To issue the new invoice you'll need to provide the issuing parameters.

Invoice parameters

This encapsulates the needed parameters to issue your invoice, such as PrivateKey, PublicKey, Series, etc.

PTIssuingParams paramaters = PTIssuingParams.Util.newInstance();

You can use the provided KeyGenerator to generate your keys.

KeyGenerator gen = new KeyGenerator("private/key/dir/pkey.pem");
invoiceParameters.setPrivateKey(gen.getPrivateKey());
invoiceParameters.setPublicKey(gen.getPublicKey());
invoiceParameters.setSeries("New Series");

Issuing the document

After defining the all the parameters you simply issue the document:

billyPortugal.invoices().issue(invoiceBuilder, paramaters);

SAFT-T export service

You can export the SAF-T(PT) xml file containing all the billing information for an application and a business during a given period. You'll need to specify the application's and the business's UID, the certificate number for the SAF-T(PT) file and the period of time that you wish to export.

// one month period
SimpleDateFormat dateFormat = new SimpleDateFormat("dd-mm-yyyy");
Date startDate = dateFormat.parse("01-01-2013");
Date endDate = dateFormat.parse("01-02-2013");

billyPortugal.saft().export(application.getUID(), business.getUID(), 
                          "Certification Number", startDate, endDate);

Export invoice to PDF

You can export a previously issued invoice to pdf format. First you'll need to create a new instance of a TemplateBundle for an invoice. The TemplateBundle encapsulates the configuration details for your pdf:

InputStream xslInputStream = new FileInputStream("xsl/path/file.xsl");
PTInvoiceTemplateBundle templateBundle = new PTInvoiceTemplateBundle("logo/path/logo.png", xslInputStream,
                                                     "Software Certification ID");

Then you need to create a new PDFExportRequest with the issued invoice UID, the TemplateBundle and where you want to export the new pdf to:

billyPortugal.invoices().pdfExport(
             new PTInvoicePDFExportRequest(invoice.getUID(), templateBundle, "path/to/export.pdf" ));