lbx-invoice
This packages aims to take care of most of your invoicing concerns, including:
- Generation of continuous invoice numbers by saving the amount of created invoices through one year
- Generation of invoice pdf files in the format PDF-A from a invoice model instance
This library was built with customization in mind, so most things can easily be modified.
Usage
Register the component
The minimum required code changes to use the library to its full extend is simply registering it in the application.ts
:
import { BaseInvoiceRepository, LbxInvoiceComponent, NumberInvoicesRepository } from 'lbx-invoice';
export class MyApplication extends BootMixin(ServiceMixin(RepositoryMixin(RestApplication))) {
constructor(options: ApplicationConfig = {}) {
this.component(LbxInvoiceComponent);
this.repository(BaseInvoiceRepository);
this.repository(NumberInvoicesRepository);
}
}
If you don't want to use the predefined repositories you can create your own and bind them to the corresponding key in LbxInvoiceBindings
.
Almost everything above comes from the library out of the box. You only need to create your own PdfService for generating the files.
Create your own PdfService
import { BaseCompanyInfo, BaseInvoice, BasePdfService } from 'lbx-invoice';
const invoicePath: string = path.join(__dirname, '..', '../src/services/invoices');
@injectable({ scope: BindingScope.TRANSIENT })
export class InvoicePdfService extends BasePdfService<BaseInvoice, BaseCompanyInfo> {
protected readonly TAX_OFFICE?: string = undefined;
protected readonly TAX_NUMBER?: string = undefined;
protected readonly IBAN?: string = undefined;
protected readonly BIC?: string = undefined;
protected readonly BANK_NAME?: string = undefined;
protected readonly BANK_CODE?: string = undefined;
protected readonly BANK_ACCOUNT_NUMBER?: string = undefined;
protected readonly companyInfo: BaseCompanyInfo = {
name: 'Example Company',
fullName: 'Example Company LLC',
email: 'info@example-company.com',
phone: '12345 67890123',
address: {
street: 'Example street',
number: '1b',
postcode: '12345',
city: 'Example city'
}
};
protected async handleFinishedInvoicePdf(pdfData: string, invoice: BaseInvoice): Promise<void> {
writeFileSync(path.join(invoicePath, `${invoice.number}.pdf`), pdfData, 'base64');
}
}
Enjoy!
That's it, now you can use it inside your code:
import { BaseInvoice, BaseInvoiceRepository, InvoiceNumberService, LbxInvoiceBindings } from 'lbx-invoice';
export class ExampleInvoiceController {
constructor(
@inject(LbxInvoiceBindings.INVOICE_REPOSITORY)
private readonly baseInvoiceRepository: BaseInvoiceRepository,
@service(InvoicePdfService)
private readonly pdfService: InvoicePdfService,
@inject(LbxInvoiceBindings.INVOICE_NUMBER_SERVICE)
private readonly invoiceNumberService: InvoiceNumberService,
@inject('datasources.db')
private readonly dataSource: DbDataSource
) {}
@post('/invoices')
async create(
@requestBody({
content: {
'application/json': {
schema: getModelSchemaRef(BaseInvoice, {
exclude: ['id', 'number']
})
}
}
})
invoice: Omit<BaseInvoice, 'id'>
): Promise<void> {
const transaction: juggler.Transaction = await this.dataSource.beginTransaction(IsolationLevel.READ_COMMITTED);
try {
invoice.number = await this.invoiceNumberService.generateInvoiceNumber(invoice.customerAddressData, transaction);
const finishedInvoice: BaseInvoice = await this.baseInvoiceRepository.create(invoice, { transaction: transaction });
await this.pdfService.createInvoicePdf(finishedInvoice);
await transaction.commit();
}
catch (error) {
await transaction.rollback();
throw error;
}
}
}
Customization
The library is highly customizable through the usage of Bindings.
Almost everything can be overriden by you when you provide a value for the specific Binding:
import { LbxInvoiceBindings } from 'lbx-invoice';
this.bind(LbxInvoiceBindings.INVOICE_REPOSITORY).toClass(MyCustomInvoiceRepository);
All bindings can be accessed under LbxInvoiceBindings
.