UNPKG

lbx-invoice

Version:

Provides functionality around generating invoices.

204 lines 9.56 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.BaseInvoiceNumberService = void 0; const tslib_1 = require("tslib"); const core_1 = require("@loopback/core"); const rest_1 = require("@loopback/rest"); const keys_1 = require("../keys"); const repositories_1 = require("../repositories"); /** * Handles generating unique and consecutive numbers for invoices. */ let BaseInvoiceNumberService = class BaseInvoiceNumberService { constructor(invoiceRepository, numberInvoicesRepository) { this.invoiceRepository = invoiceRepository; this.numberInvoicesRepository = numberInvoicesRepository; /** * The number of digits used to generate the consecutive number. * @default 4 */ this.NUMBER_OF_DIGITS = 4; /** * The separator for the parts of the invoice number. * @default '-' */ this.SEPARATOR = '-'; /** * How many characters of the company name should be used in the invoice number. * @default 6 */ this.NUMBER_COMPANY_ABBREVIATION_CHARACTERS = 6; /** * How many characters of the private customer first and last name should be used in the invoice number. * @default 3 */ this.NUMBER_PRIVATE_CUSTOMER_ABBREVIATION_CHARACTERS = 3; } /** * Generates a new invoice number. * @param recipientId - The id of the recipient of the invoice. * @param invoiceAddress - The address data of the customer. * @param transaction - An optional transaction from outside to make sure any changes only apply when the transaction is committed. * @param nameAbbreviation - An optional name abbreviation if you don't want to generate one. * @returns A promise of the new invoice number. */ async generateInvoiceNumber(recipientId, invoiceAddress, transaction, nameAbbreviation) { const currentYear = `${new Date().getFullYear()}`; const customerNameAbbreviation = nameAbbreviation !== null && nameAbbreviation !== void 0 ? nameAbbreviation : this.getCustomerNameAbbreviation(invoiceAddress); const consecutiveNumber = await this.getConsecutiveNumber(recipientId, transaction); const result = `${currentYear}${this.SEPARATOR}${customerNameAbbreviation}${this.SEPARATOR}${consecutiveNumber}`; await this.validateInvoiceNumber(result); return result; } /** * Generates a temporary invoice number with the prefix temp. * This does not increase the number of invoices which can be helpful if you create an invoice that might not be sent out. * @param recipientId - The id of the recipient of the invoice. * @param invoiceAddress - The address data of the customer. * @param nameAbbreviation - An optional name abbreviation if you don't want to generate one. * @returns A promise of the new temporary invoice number. */ async generateTemporaryInvoiceNumber(recipientId, invoiceAddress, nameAbbreviation) { const currentYear = `${new Date().getFullYear()}`; const customerNameAbbreviation = nameAbbreviation !== null && nameAbbreviation !== void 0 ? nameAbbreviation : this.getCustomerNameAbbreviation(invoiceAddress); const consecutiveNumber = await this.getTemporaryConsecutiveNumber(recipientId); // eslint-disable-next-line stylistic/max-len const result = `TEMP${this.SEPARATOR}${currentYear}${this.SEPARATOR}${customerNameAbbreviation}${this.SEPARATOR}${consecutiveNumber}`; if (!await this.invoiceRepository.findOne({ where: { number: result } })) { return result; } let suffix = 2; while (await this.invoiceRepository.findOne({ where: { number: `${result}${this.SEPARATOR}${suffix}` } })) { suffix++; } return `${result}${this.SEPARATOR}${suffix}`; } /** * Gets the temporary consecutive number of the invoices in this year and for the provided recipientId. * Prefixes it with zeroes until the result has the same length as this.NUMBER_OF_DIGITS. * @param recipientId - The id of the recipient of the invoice. * @returns The number of invoices over a year filled up with zeroes to match this.NUMBER_OF_DIGITS. */ async getTemporaryConsecutiveNumber(recipientId) { const currentYear = new Date(Date.now()).getFullYear(); let numberOfInvoices = await this.numberInvoicesRepository.findOne({ where: { year: currentYear, recipientId: recipientId } }); if (numberOfInvoices) { numberOfInvoices.number++; } else { numberOfInvoices = { number: 1, year: currentYear, recipientId: recipientId }; } const consecutiveNumber = `${numberOfInvoices.number}`; if (consecutiveNumber.length > this.NUMBER_OF_DIGITS) { return consecutiveNumber; } const difference = this.NUMBER_OF_DIGITS - consecutiveNumber.length; let prefix = ''; for (let i = 0; i < difference; i++) { prefix = `${prefix}0`; } return `${prefix}${consecutiveNumber}`; } /** * Gets the consecutive number of the invoices in this year. * Prefixes it with zeroes until the result has the same length as this.NUMBER_OF_DIGITS. * @param recipientId - The id of the recipient of the invoice. * @param transaction - An optional transaction from outside to make sure any changes only apply when the transaction is committed. * @returns The number of invoices over a year filled up with zeroes to match this.NUMBER_OF_DIGITS. */ async getConsecutiveNumber(recipientId, transaction) { const currentYear = new Date(Date.now()).getFullYear(); let numberOfInvoices = await this.numberInvoicesRepository.findOne({ where: { year: currentYear, recipientId: recipientId } }); if (numberOfInvoices) { numberOfInvoices.number++; await this.numberInvoicesRepository.updateById(numberOfInvoices.id, numberOfInvoices, { transaction: transaction }); } else { numberOfInvoices = await this.numberInvoicesRepository.create({ number: 1, year: currentYear, recipientId: recipientId }, { transaction: transaction }); } const consecutiveNumber = `${numberOfInvoices.number}`; if (consecutiveNumber.length > this.NUMBER_OF_DIGITS) { return consecutiveNumber; } const difference = this.NUMBER_OF_DIGITS - consecutiveNumber.length; let prefix = ''; for (let i = 0; i < difference; i++) { prefix = `${prefix}0`; } return `${prefix}${consecutiveNumber}`; } /** * Gets the customer name abbreviation. * @param invoiceAddress - The address data to get the name abbreviation from. * @returns The first char of first and last name for private customers * and the first two chars of the company name for company customers. */ getCustomerNameAbbreviation(invoiceAddress) { if (invoiceAddress.company && invoiceAddress.companyName) { return this.getCompanyNameAbbreviation(invoiceAddress.companyName); } return this.getPrivateCustomerAbbreviation(invoiceAddress); } getPrivateCustomerAbbreviation(invoiceAddress) { let res = ''; for (let i = 0; i < this.NUMBER_PRIVATE_CUSTOMER_ABBREVIATION_CHARACTERS; i++) { if (invoiceAddress.firstName[i]) { res += invoiceAddress.firstName[i]; } } for (let i = 0; i < this.NUMBER_PRIVATE_CUSTOMER_ABBREVIATION_CHARACTERS; i++) { if (invoiceAddress.lastName[i]) { res += invoiceAddress.lastName[i]; } } return res.toUpperCase(); } getCompanyNameAbbreviation(companyName) { companyName = companyName.replaceAll(/\s/g, ''); companyName = companyName.replaceAll(/[^\da-z]/gi, ''); let res = ''; for (let i = 0; i < this.NUMBER_COMPANY_ABBREVIATION_CHARACTERS; i++) { if (companyName[i]) { res += companyName[i]; } } return res.toUpperCase(); } // TODO: Is this still needed? /** * Validates the given invoice number. * @param invoiceNumber - The invoice number to validate. */ async validateInvoiceNumber(invoiceNumber) { if (await this.invoiceRepository.findOne({ where: { number: invoiceNumber } })) { throw new rest_1.HttpErrors.Conflict(`The generated invoice-number ${invoiceNumber} already exists!`); } } }; exports.BaseInvoiceNumberService = BaseInvoiceNumberService; exports.BaseInvoiceNumberService = BaseInvoiceNumberService = tslib_1.__decorate([ (0, core_1.injectable)({ scope: core_1.BindingScope.TRANSIENT }), tslib_1.__param(0, (0, core_1.inject)(keys_1.LbxInvoiceBindings.INVOICE_REPOSITORY)), tslib_1.__param(1, (0, core_1.inject)(keys_1.LbxInvoiceBindings.NUMBER_INVOICES_REPOSITORY)), tslib_1.__metadata("design:paramtypes", [repositories_1.BaseInvoiceRepository, repositories_1.NumberInvoicesRepository]) ], BaseInvoiceNumberService); //# sourceMappingURL=base-invoice-number.service.js.map