feat: send invoices and reminder notifications to the customers

This commit is contained in:
Ahmed Bouhuolia
2023-12-21 22:57:17 +02:00
parent ef52eaf91a
commit d2c63878ed
10 changed files with 227 additions and 45 deletions

View File

@@ -1,7 +1,18 @@
import { Inject, Service } from 'typedi';
import * as R from 'ramda';
import { assign } from 'lodash';
import { SendInvoiceMailDTO } from '@/interfaces';
import Mail from '@/lib/Mail';
import HasTenancyService from '@/services/Tenancy/TenancyService';
import { CommandSaleInvoiceValidators } from './CommandSaleInvoiceValidators';
import { SaleInvoiceMailFormatter } from './SaleInvoiceMailFormatter';
import {
DEFAULT_INVOICE_REMINDER_MAIL_CONTENT,
DEFAULT_INVOICE_REMINDER_MAIL_SUBJECT,
ERRORS,
} from './constants';
import { SaleInvoicePdf } from './SaleInvoicePdf';
import { ServiceError } from '@/exceptions';
@Service()
export class SendInvoiceMailReminder {
@@ -11,6 +22,15 @@ export class SendInvoiceMailReminder {
@Inject('agenda')
private agenda: any;
@Inject()
private commandInvoiceValidator: CommandSaleInvoiceValidators;
@Inject()
private invoiceFormatter: SaleInvoiceMailFormatter;
@Inject()
private invoicePdf: SaleInvoicePdf;
/**
* Triggers the reminder mail of the given sale invoice.
* @param {number} tenantId
@@ -19,12 +39,12 @@ export class SendInvoiceMailReminder {
public async triggerMail(
tenantId: number,
saleInvoiceId: number,
messageDTO: SendInvoiceMailDTO
messageOptions: SendInvoiceMailDTO
) {
const payload = {
tenantId,
saleInvoiceId,
messageDTO,
messageOptions,
};
await this.agenda.now('sale-invoice-reminder-mail-send', payload);
}
@@ -33,13 +53,13 @@ export class SendInvoiceMailReminder {
* Triggers the mail invoice.
* @param {number} tenantId
* @param {number} saleInvoiceId
* @param {SendInvoiceMailDTO} messageDTO
* @param {SendInvoiceMailDTO} messageOptions
* @returns {Promise<void>}
*/
public async sendMail(
tenantId: number,
saleInvoiceId: number,
messageDTO: SendInvoiceMailDTO
messageOptions: SendInvoiceMailDTO
) {
const { SaleInvoice } = this.tenancy.models(tenantId);
@@ -47,17 +67,45 @@ export class SendInvoiceMailReminder {
.findById(saleInvoiceId)
.withGraphFetched('customer');
const toEmail = messageDTO.to || saleInvoice.customer.email;
const subject = messageDTO.subject || saleInvoice.invoiceNo;
// Validates the invoice existance.
this.commandInvoiceValidator.validateInvoiceExistance(saleInvoice);
if (!toEmail) {
return null;
const parsedMessageOptions = {
attachInvoice: true,
subject: DEFAULT_INVOICE_REMINDER_MAIL_SUBJECT,
body: DEFAULT_INVOICE_REMINDER_MAIL_CONTENT,
to: saleInvoice.customer.email,
...messageOptions,
};
// In case there is no email address from the customer or from options, throw an error.
if (!parsedMessageOptions.to) {
throw new ServiceError(ERRORS.NO_INVOICE_CUSTOMER_EMAIL_ADDR);
}
const formatter = R.curry(this.invoiceFormatter.formatText)(
tenantId,
saleInvoiceId
);
const toEmail = parsedMessageOptions.to;
const subject = await formatter(parsedMessageOptions.subject);
const body = await formatter(parsedMessageOptions.body);
const attachments = [];
if (parsedMessageOptions.attachInvoice) {
// Retrieves document buffer of the invoice pdf document.
const invoicePdfBuffer = await this.invoicePdf.saleInvoicePdf(
tenantId,
saleInvoiceId
);
attachments.push({
filename: 'invoice.pdf',
content: invoicePdfBuffer,
});
}
const mail = new Mail()
.setSubject(subject)
.setView('mail/UserInvite.html')
.setTo(toEmail)
.setData({});
.setContent(body)
.setAttachments(attachments);
await mail.send();
}