mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-15 12:20:31 +00:00
refactor: notification mail services
This commit is contained in:
@@ -13,15 +13,19 @@ export const SALE_ESTIMATE_EDITED = 'Sale estimate edited';
|
||||
export const SALE_ESTIMATE_DELETED = 'Sale estimate deleted';
|
||||
export const SALE_ESTIMATE_PDF_VIEWED = 'Sale estimate PDF viewed';
|
||||
export const SALE_ESTIMATE_VIEWED = 'Sale estimate viewed';
|
||||
export const SALE_ESTIMATE_MAIL_SENT = 'Sale estimate mail sent';
|
||||
|
||||
export const PAYMENT_RECEIVED_CREATED = 'Payment received created';
|
||||
export const PAYMENT_RECEIVED_EDITED = 'payment received edited';
|
||||
export const PAYMENT_RECEIVED_DELETED = 'Payment received deleted';
|
||||
export const PAYMENT_RECEIVED_PDF_VIEWED = 'Payment received PDF viewed';
|
||||
export const PAYMENT_RECEIVED_MAIL_SENT = 'Payment received mail sent';
|
||||
|
||||
export const SALE_RECEIPT_PDF_VIEWED = 'Sale credit PDF viewed';
|
||||
export const SALE_RECEIPT_MAIL_SENT = 'Sale credit mail sent';
|
||||
|
||||
export const CREDIT_NOTE_PDF_VIEWED = 'Credit note PDF viewed';
|
||||
export const CREDIT_NOTE_MAIL_SENT = 'Credit note mail sent';
|
||||
|
||||
export const BILL_CREATED = 'Bill created';
|
||||
export const BILL_EDITED = 'Bill edited';
|
||||
|
||||
@@ -36,7 +36,7 @@ export interface CommonMailOptions {
|
||||
to: Array<string>;
|
||||
cc?: Array<string>;
|
||||
bcc?: Array<string>;
|
||||
data?: Record<string, any>;
|
||||
formatArgs?: Record<string, any>;
|
||||
}
|
||||
|
||||
export interface CommonMailOptionsDTO extends Partial<CommonMailOptions> {
|
||||
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
PAYMENT_RECEIVED_EDITED,
|
||||
PAYMENT_RECEIVED_DELETED,
|
||||
PAYMENT_RECEIVED_PDF_VIEWED,
|
||||
PAYMENT_RECEIVED_MAIL_SENT,
|
||||
} from '@/constants/event-tracker';
|
||||
|
||||
@Service()
|
||||
@@ -39,6 +40,10 @@ export class PaymentReceivedEventsTracker extends EventSubscriber {
|
||||
events.paymentReceive.onPdfViewed,
|
||||
this.handleTrackPdfViewedPaymentReceivedEvent
|
||||
);
|
||||
bus.subscribe(
|
||||
events.paymentReceive.onMailSent,
|
||||
this.handleTrackMailSentPaymentReceivedEvent
|
||||
);
|
||||
}
|
||||
|
||||
private handleTrackPaymentReceivedCreatedEvent = ({
|
||||
@@ -80,4 +85,14 @@ export class PaymentReceivedEventsTracker extends EventSubscriber {
|
||||
properties: {},
|
||||
});
|
||||
};
|
||||
|
||||
private handleTrackMailSentPaymentReceivedEvent = ({
|
||||
tenantId,
|
||||
}: IPaymentReceivedDeletedPayload) => {
|
||||
this.posthog.trackEvent({
|
||||
distinctId: `tenant-${tenantId}`,
|
||||
event: PAYMENT_RECEIVED_MAIL_SENT,
|
||||
properties: {},
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import {
|
||||
SALE_ESTIMATE_DELETED,
|
||||
SALE_ESTIMATE_PDF_VIEWED,
|
||||
SALE_ESTIMATE_VIEWED,
|
||||
SALE_ESTIMATE_MAIL_SENT,
|
||||
} from '@/constants/event-tracker';
|
||||
|
||||
@Service()
|
||||
@@ -44,6 +45,10 @@ export class SaleEstimateEventsTracker extends EventSubscriber {
|
||||
events.saleEstimate.onViewed,
|
||||
this.handleTrackViewedEstimateEvent
|
||||
);
|
||||
bus.subscribe(
|
||||
events.saleEstimate.onMailSent,
|
||||
this.handleTrackMailSentEstimateEvent
|
||||
);
|
||||
}
|
||||
|
||||
private handleTrackEstimateCreatedEvent = ({
|
||||
@@ -93,4 +98,12 @@ export class SaleEstimateEventsTracker extends EventSubscriber {
|
||||
properties: {},
|
||||
});
|
||||
};
|
||||
|
||||
private handleTrackMailSentEstimateEvent = ({ tenantId }) => {
|
||||
this.posthog.trackEvent({
|
||||
distinctId: `tenant-${tenantId}`,
|
||||
event: SALE_ESTIMATE_MAIL_SENT,
|
||||
properties: {},
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ export class ContactMailNotification {
|
||||
* @param {number} tenantId - Tenant id.
|
||||
* @returns {Promise<CommonMailOptions>}
|
||||
*/
|
||||
public async parseMailOptions(
|
||||
public async formatMailOptions(
|
||||
tenantId: number,
|
||||
mailOptions: CommonMailOptions,
|
||||
formatterArgs?: Record<string, any>
|
||||
|
||||
@@ -44,3 +44,13 @@ export function validateRequiredMailOptions(
|
||||
throw new ServiceError(ERRORS.MAIL_BODY_NOT_FOUND);
|
||||
}
|
||||
}
|
||||
|
||||
export const mergeAndValidateMailOptions = (
|
||||
mailOptions: CommonMailOptions,
|
||||
overridedOptions: Partial<CommonMailOptions>
|
||||
): CommonMailOptions => {
|
||||
const parsedMessageOptions = parseMailOptions(mailOptions, overridedOptions);
|
||||
validateRequiredMailOptions(parsedMessageOptions);
|
||||
|
||||
return parsedMessageOptions;
|
||||
};
|
||||
|
||||
@@ -13,9 +13,10 @@ import {
|
||||
SaleEstimateMailOptionsDTO,
|
||||
} from '@/interfaces';
|
||||
import { ContactMailNotification } from '@/services/MailNotification/ContactMailNotification';
|
||||
import { parseAndValidateMailOptions } from '@/services/MailNotification/utils';
|
||||
import { mergeAndValidateMailOptions } from '@/services/MailNotification/utils';
|
||||
import { EventPublisher } from '@/lib/EventPublisher/EventPublisher';
|
||||
import events from '@/subscribers/events';
|
||||
import { transformEstimateToMailDataArgs } from './utils';
|
||||
|
||||
@Service()
|
||||
export class SendSaleEstimateMail {
|
||||
@@ -65,23 +66,17 @@ export class SendSaleEstimateMail {
|
||||
}
|
||||
|
||||
/**
|
||||
* Formates the text of the mail.
|
||||
* Formate the text of the mail.
|
||||
* @param {number} tenantId - Tenant id.
|
||||
* @param {number} estimateId - Estimate id.
|
||||
* @returns {Promise<Record<string, any>>}
|
||||
*/
|
||||
public formatterData = async (tenantId: number, estimateId: number) => {
|
||||
public formatterArgs = async (tenantId: number, estimateId: number) => {
|
||||
const estimate = await this.getSaleEstimateService.getEstimate(
|
||||
tenantId,
|
||||
estimateId
|
||||
);
|
||||
return {
|
||||
CustomerName: estimate.customer.displayName,
|
||||
EstimateNumber: estimate.estimateNumber,
|
||||
EstimateDate: estimate.formattedEstimateDate,
|
||||
EstimateAmount: estimate.formattedAmount,
|
||||
EstimateExpirationDate: estimate.formattedExpirationDate,
|
||||
};
|
||||
return transformEstimateToMailDataArgs(estimate);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -92,7 +87,9 @@ export class SendSaleEstimateMail {
|
||||
*/
|
||||
public getMailOptions = async (
|
||||
tenantId: number,
|
||||
saleEstimateId: number
|
||||
saleEstimateId: number,
|
||||
defaultSubject: string = DEFAULT_ESTIMATE_REMINDER_MAIL_SUBJECT,
|
||||
defaultMessage: string = DEFAULT_ESTIMATE_REMINDER_MAIL_CONTENT
|
||||
): Promise<SaleEstimateMailOptions> => {
|
||||
const { SaleEstimate } = this.tenancy.models(tenantId);
|
||||
|
||||
@@ -100,22 +97,45 @@ export class SendSaleEstimateMail {
|
||||
.findById(saleEstimateId)
|
||||
.throwIfNotFound();
|
||||
|
||||
const formatterData = await this.formatterData(tenantId, saleEstimateId);
|
||||
const formatArgs = await this.formatterArgs(tenantId, saleEstimateId);
|
||||
|
||||
const mailOptions = await this.contactMailNotification.getMailOptions(
|
||||
tenantId,
|
||||
saleEstimate.customerId,
|
||||
DEFAULT_ESTIMATE_REMINDER_MAIL_SUBJECT,
|
||||
DEFAULT_ESTIMATE_REMINDER_MAIL_CONTENT,
|
||||
formatterData
|
||||
);
|
||||
const mailOptions =
|
||||
await this.contactMailNotification.getDefaultMailOptions(
|
||||
tenantId,
|
||||
saleEstimate.customerId
|
||||
);
|
||||
return {
|
||||
...mailOptions,
|
||||
data: formatterData,
|
||||
message: defaultMessage,
|
||||
subject: defaultSubject,
|
||||
attachEstimate: true,
|
||||
formatArgs,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Formats the given mail options.
|
||||
* @param {number} tenantId
|
||||
* @param {number} saleEstimateId
|
||||
* @param {SaleEstimateMailOptions} mailOptions
|
||||
* @returns {Promise<SaleEstimateMailOptions>}
|
||||
*/
|
||||
public formatMailOptions = async (
|
||||
tenantId: number,
|
||||
saleEstimateId: number,
|
||||
mailOptions: SaleEstimateMailOptions
|
||||
): Promise<SaleEstimateMailOptions> => {
|
||||
const formatterArgs = await this.formatterArgs(tenantId, saleEstimateId);
|
||||
|
||||
const formattedOptions =
|
||||
await this.contactMailNotification.formatMailOptions(
|
||||
tenantId,
|
||||
mailOptions,
|
||||
formatterArgs
|
||||
);
|
||||
return { ...formattedOptions };
|
||||
};
|
||||
|
||||
/**
|
||||
* Sends the mail notification of the given sale estimate.
|
||||
* @param {number} tenantId
|
||||
@@ -133,27 +153,52 @@ export class SendSaleEstimateMail {
|
||||
saleEstimateId
|
||||
);
|
||||
// Overrides and validates the given mail options.
|
||||
const messageOpts = parseAndValidateMailOptions(
|
||||
const parsedMessageOptions = mergeAndValidateMailOptions(
|
||||
localMessageOpts,
|
||||
messageOptions
|
||||
) as SaleEstimateMailOptions;
|
||||
|
||||
const formattedOptions = await this.formatMailOptions(
|
||||
tenantId,
|
||||
saleEstimateId,
|
||||
parsedMessageOptions
|
||||
);
|
||||
const mail = new Mail()
|
||||
.setSubject(messageOpts.subject)
|
||||
.setTo(messageOpts.to)
|
||||
.setContent(messageOpts.body);
|
||||
.setSubject(formattedOptions.subject)
|
||||
.setTo(formattedOptions.to)
|
||||
.setContent(formattedOptions.message);
|
||||
|
||||
// Attaches the estimate pdf to the mail.
|
||||
if (formattedOptions.attachEstimate) {
|
||||
// Retrieves the estimate pdf and attaches it to the mail.
|
||||
const [estimatePdfBuffer, estimateFilename] =
|
||||
await this.estimatePdf.getSaleEstimatePdf(tenantId, saleEstimateId);
|
||||
|
||||
if (messageOpts.attachEstimate) {
|
||||
const estimatePdfBuffer = await this.estimatePdf.getSaleEstimatePdf(
|
||||
tenantId,
|
||||
saleEstimateId
|
||||
);
|
||||
mail.setAttachments([
|
||||
{
|
||||
filename: messageOpts.data?.EstimateNumber || 'estimate.pdf',
|
||||
filename: `${estimateFilename}.pdf`,
|
||||
content: estimatePdfBuffer,
|
||||
},
|
||||
]);
|
||||
}
|
||||
|
||||
const eventPayload = {
|
||||
tenantId,
|
||||
saleEstimateId,
|
||||
messageOptions,
|
||||
formattedOptions,
|
||||
};
|
||||
// Triggers `onSaleEstimateMailSend` event.
|
||||
await this.eventPublisher.emitAsync(
|
||||
events.saleEstimate.onMailSend,
|
||||
eventPayload as ISaleEstimateMailPresendEvent
|
||||
);
|
||||
await mail.send();
|
||||
|
||||
// Triggers `onSaleEstimateMailSent` event.
|
||||
await this.eventPublisher.emitAsync(
|
||||
events.saleEstimate.onMailSent,
|
||||
eventPayload as ISaleEstimateMailPresendEvent
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
export const DEFAULT_ESTIMATE_REMINDER_MAIL_SUBJECT =
|
||||
'Estimate {EstimateNumber} is awaiting your approval';
|
||||
export const DEFAULT_ESTIMATE_REMINDER_MAIL_CONTENT = `<p>Dear {CustomerName}</p>
|
||||
'Estimate {Estimate Number} is awaiting your approval';
|
||||
export const DEFAULT_ESTIMATE_REMINDER_MAIL_CONTENT = `<p>Dear {Customer Name}</p>
|
||||
<p>Thank you for your business, You can view or print your estimate from attachements.</p>
|
||||
<p>
|
||||
Estimate <strong>#{EstimateNumber}</strong><br />
|
||||
Expiration Date : <strong>{EstimateExpirationDate}</strong><br />
|
||||
Amount : <strong>{EstimateAmount}</strong></br />
|
||||
Estimate <strong>#{Estimate Number}</strong><br />
|
||||
Expiration Date : <strong>{Estimate Expiration Date}</strong><br />
|
||||
Amount : <strong>{Estimate Amount}</strong></br />
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<i>Regards</i><br />
|
||||
<i>{CompanyName}</i>
|
||||
<i>{Company Name}</i>
|
||||
</p>
|
||||
`;
|
||||
|
||||
|
||||
@@ -22,3 +22,13 @@ export const transformEstimateToPdfTemplate = (
|
||||
customerAddress: contactAddressTextFormat(estimate.customer),
|
||||
};
|
||||
};
|
||||
|
||||
export const transformEstimateToMailDataArgs = (estimate: any) => {
|
||||
return {
|
||||
'Customer Name': estimate.customer.displayName,
|
||||
'Estimate Number': estimate.estimateNumber,
|
||||
'Estimate Date': estimate.formattedEstimateDate,
|
||||
'Estimate Amount': estimate.formattedAmount,
|
||||
'Estimate Expiration Date': estimate.formattedExpirationDate,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -21,6 +21,7 @@ export class GetInvoicePaymentMail {
|
||||
|
||||
/**
|
||||
* Retrieves the mail template attributes of the given invoice.
|
||||
* Invoice template attributes are composed of the invoice and branding template attributes.
|
||||
* @param {number} tenantId - Tenant id.
|
||||
* @param {number} invoiceId - Invoice id.
|
||||
*/
|
||||
|
||||
@@ -75,20 +75,22 @@ export class SendSaleInvoiceMailCommon {
|
||||
tenantId,
|
||||
invoiceId
|
||||
);
|
||||
const parsedOptions = await this.contactMailNotification.parseMailOptions(
|
||||
tenantId,
|
||||
mailOptions,
|
||||
formatterArgs
|
||||
);
|
||||
const formattedOptions =
|
||||
await this.contactMailNotification.formatMailOptions(
|
||||
tenantId,
|
||||
mailOptions,
|
||||
formatterArgs
|
||||
);
|
||||
const message = await this.getInvoicePaymentMail.getMailTemplate(
|
||||
tenantId,
|
||||
invoiceId,
|
||||
{
|
||||
// # Invoice message
|
||||
invoiceMessage: parsedOptions.message,
|
||||
invoiceMessage: formattedOptions.message,
|
||||
preview: formattedOptions.message,
|
||||
}
|
||||
);
|
||||
return { ...parsedOptions, message };
|
||||
return { ...formattedOptions, message };
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -111,13 +113,13 @@ export class SendSaleInvoiceMailCommon {
|
||||
);
|
||||
return {
|
||||
...commonArgs,
|
||||
['Customer Name']: invoice.customer.displayName,
|
||||
['Invoice Number']: invoice.invoiceNo,
|
||||
['Invoice DueAmount']: invoice.dueAmountFormatted,
|
||||
['Invoice DueDate']: invoice.dueDateFormatted,
|
||||
['Invoice Date']: invoice.invoiceDateFormatted,
|
||||
['Invoice Amount']: invoice.totalFormatted,
|
||||
['Overdue Days']: invoice.overdueDays,
|
||||
'Customer Name': invoice.customer.displayName,
|
||||
'Invoice Number': invoice.invoiceNo,
|
||||
'Invoice DueAmount': invoice.dueAmountFormatted,
|
||||
'Invoice DueDate': invoice.dueDateFormatted,
|
||||
'Invoice Date': invoice.invoiceDateFormatted,
|
||||
'Invoice Amount': invoice.totalFormatted,
|
||||
'Overdue Days': invoice.overdueDays,
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -3,10 +3,7 @@ import Mail from '@/lib/Mail';
|
||||
import { ISaleInvoiceMailSend, SendInvoiceMailDTO } from '@/interfaces';
|
||||
import { SaleInvoicePdf } from './SaleInvoicePdf';
|
||||
import { SendSaleInvoiceMailCommon } from './SendInvoiceInvoiceMailCommon';
|
||||
import {
|
||||
parseMailOptions,
|
||||
validateRequiredMailOptions,
|
||||
} from '@/services/MailNotification/utils';
|
||||
import { mergeAndValidateMailOptions } from '@/services/MailNotification/utils';
|
||||
import { EventPublisher } from '@/lib/EventPublisher/EventPublisher';
|
||||
import events from '@/subscribers/events';
|
||||
|
||||
@@ -18,12 +15,12 @@ export class SendSaleInvoiceMail {
|
||||
@Inject()
|
||||
private invoiceMail: SendSaleInvoiceMailCommon;
|
||||
|
||||
@Inject('agenda')
|
||||
private agenda: any;
|
||||
|
||||
@Inject()
|
||||
private eventPublisher: EventPublisher;
|
||||
|
||||
@Inject('agenda')
|
||||
private agenda: any;
|
||||
|
||||
/**
|
||||
* Sends the invoice mail of the given sale invoice.
|
||||
* @param {number} tenantId
|
||||
@@ -67,13 +64,10 @@ export class SendSaleInvoiceMail {
|
||||
saleInvoiceId
|
||||
);
|
||||
// Merges message options with default options and parses the options values.
|
||||
const parsedMessageOptions = parseMailOptions(
|
||||
const parsedMessageOptions = mergeAndValidateMailOptions(
|
||||
defaultMessageOptions,
|
||||
messageOptions
|
||||
);
|
||||
// Validates the required mail options.
|
||||
validateRequiredMailOptions(parsedMessageOptions);
|
||||
|
||||
const formattedMessageOptions =
|
||||
await this.invoiceMail.formatInvoiceMailOptions(
|
||||
tenantId,
|
||||
|
||||
@@ -13,9 +13,10 @@ import {
|
||||
} from './constants';
|
||||
import { GetPaymentReceived } from './GetPaymentReceived';
|
||||
import { ContactMailNotification } from '@/services/MailNotification/ContactMailNotification';
|
||||
import { parseAndValidateMailOptions } from '@/services/MailNotification/utils';
|
||||
import { mergeAndValidateMailOptions } from '@/services/MailNotification/utils';
|
||||
import { EventPublisher } from '@/lib/EventPublisher/EventPublisher';
|
||||
import events from '@/subscribers/events';
|
||||
import { transformPaymentReceivedToMailDataArgs } from './utils';
|
||||
|
||||
@Service()
|
||||
export class SendPaymentReceiveMailNotification {
|
||||
@@ -77,15 +78,19 @@ export class SendPaymentReceiveMailNotification {
|
||||
.findById(paymentId)
|
||||
.throwIfNotFound();
|
||||
|
||||
const formatterData = await this.textFormatter(tenantId, paymentId);
|
||||
const formatArgs = await this.textFormatter(tenantId, paymentId);
|
||||
|
||||
return this.contactMailNotification.getMailOptions(
|
||||
tenantId,
|
||||
paymentReceive.customerId,
|
||||
DEFAULT_PAYMENT_MAIL_SUBJECT,
|
||||
DEFAULT_PAYMENT_MAIL_CONTENT,
|
||||
formatterData
|
||||
);
|
||||
const mailOptions =
|
||||
await this.contactMailNotification.getDefaultMailOptions(
|
||||
tenantId,
|
||||
paymentReceive.customerId
|
||||
);
|
||||
return {
|
||||
...mailOptions,
|
||||
subject: DEFAULT_PAYMENT_MAIL_SUBJECT,
|
||||
message: DEFAULT_PAYMENT_MAIL_CONTENT,
|
||||
...formatArgs,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -103,12 +108,7 @@ export class SendPaymentReceiveMailNotification {
|
||||
tenantId,
|
||||
invoiceId
|
||||
);
|
||||
return {
|
||||
CustomerName: payment.customer.displayName,
|
||||
PaymentNumber: payment.payment_receive_no,
|
||||
PaymentDate: payment.formattedPaymentDate,
|
||||
PaymentAmount: payment.formattedAmount,
|
||||
};
|
||||
return transformPaymentReceivedToMailDataArgs(payment);
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -128,14 +128,31 @@ export class SendPaymentReceiveMailNotification {
|
||||
paymentReceiveId
|
||||
);
|
||||
// Parsed message opts with default options.
|
||||
const parsedMessageOpts = parseAndValidateMailOptions(
|
||||
const parsedMessageOpts = mergeAndValidateMailOptions(
|
||||
defaultMessageOpts,
|
||||
messageDTO
|
||||
);
|
||||
await new Mail()
|
||||
const mail = new Mail()
|
||||
.setSubject(parsedMessageOpts.subject)
|
||||
.setTo(parsedMessageOpts.to)
|
||||
.setContent(parsedMessageOpts.body)
|
||||
.send();
|
||||
.setContent(parsedMessageOpts.message);
|
||||
|
||||
const eventPayload = {
|
||||
tenantId,
|
||||
paymentReceiveId,
|
||||
messageOptions: parsedMessageOpts,
|
||||
};
|
||||
// Triggers `onPaymentReceiveMailSend` event.
|
||||
await this.eventPublisher.emitAsync(
|
||||
events.paymentReceive.onMailSend,
|
||||
eventPayload
|
||||
);
|
||||
await mail.send();
|
||||
|
||||
// Triggers `onPaymentReceiveMailSent` event.
|
||||
await this.eventPublisher.emitAsync(
|
||||
events.paymentReceive.onMailSent,
|
||||
eventPayload
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,3 +21,12 @@ export const transformPaymentReceivedToPdfTemplate = (
|
||||
customerAddress: contactAddressTextFormat(payment.customer),
|
||||
};
|
||||
};
|
||||
|
||||
export const transformPaymentReceivedToMailDataArgs = (payment: any) => {
|
||||
return {
|
||||
'Customer Name': payment.customer.displayName,
|
||||
'Payment Number': payment.paymentReceiveNo,
|
||||
'Payment Date': payment.formattedPaymentDate,
|
||||
'Payment Amount': payment.formattedAmount,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -13,9 +13,10 @@ import {
|
||||
SaleReceiptMailOptsDTO,
|
||||
} from '@/interfaces';
|
||||
import { ContactMailNotification } from '@/services/MailNotification/ContactMailNotification';
|
||||
import { parseAndValidateMailOptions } from '@/services/MailNotification/utils';
|
||||
import { mergeAndValidateMailOptions } from '@/services/MailNotification/utils';
|
||||
import { EventPublisher } from '@/lib/EventPublisher/EventPublisher';
|
||||
import events from '@/subscribers/events';
|
||||
import { transformReceiptToMailDataArgs } from './utils';
|
||||
|
||||
@Service()
|
||||
export class SaleReceiptMailNotification {
|
||||
@@ -79,18 +80,19 @@ export class SaleReceiptMailNotification {
|
||||
.findById(saleReceiptId)
|
||||
.throwIfNotFound();
|
||||
|
||||
const formattedData = await this.textFormatter(tenantId, saleReceiptId);
|
||||
const formatArgs = await this.textFormatterArgs(tenantId, saleReceiptId);
|
||||
|
||||
const mailOpts = await this.contactMailNotification.getMailOptions(
|
||||
tenantId,
|
||||
saleReceipt.customerId,
|
||||
DEFAULT_RECEIPT_MAIL_SUBJECT,
|
||||
DEFAULT_RECEIPT_MAIL_CONTENT,
|
||||
formattedData
|
||||
);
|
||||
const mailOptions =
|
||||
await this.contactMailNotification.getDefaultMailOptions(
|
||||
tenantId,
|
||||
saleReceipt.customerId
|
||||
);
|
||||
return {
|
||||
...mailOpts,
|
||||
...mailOptions,
|
||||
message: DEFAULT_RECEIPT_MAIL_CONTENT,
|
||||
subject: DEFAULT_RECEIPT_MAIL_SUBJECT,
|
||||
attachReceipt: true,
|
||||
formatArgs,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -101,7 +103,7 @@ export class SaleReceiptMailNotification {
|
||||
* @param {string} text - The given text.
|
||||
* @returns {Promise<string>}
|
||||
*/
|
||||
public textFormatter = async (
|
||||
public textFormatterArgs = async (
|
||||
tenantId: number,
|
||||
receiptId: number
|
||||
): Promise<Record<string, string>> => {
|
||||
@@ -109,19 +111,14 @@ export class SaleReceiptMailNotification {
|
||||
tenantId,
|
||||
receiptId
|
||||
);
|
||||
return {
|
||||
CustomerName: receipt.customer.displayName,
|
||||
ReceiptNumber: receipt.receiptNumber,
|
||||
ReceiptDate: receipt.formattedReceiptDate,
|
||||
ReceiptAmount: receipt.formattedAmount,
|
||||
};
|
||||
return transformReceiptToMailDataArgs(receipt);
|
||||
};
|
||||
|
||||
/**
|
||||
* Triggers the mail notification of the given sale receipt.
|
||||
* @param {number} tenantId - Tenant id.
|
||||
* @param {number} saleReceiptId - Sale receipt id.
|
||||
* @param {SaleReceiptMailOpts} messageDTO - Overrided message options.
|
||||
* @param {SaleReceiptMailOpts} messageDTO - message options.
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
public async sendMail(
|
||||
@@ -129,30 +126,45 @@ export class SaleReceiptMailNotification {
|
||||
saleReceiptId: number,
|
||||
messageOpts: SaleReceiptMailOptsDTO
|
||||
) {
|
||||
const defaultMessageOpts = await this.getMailOptions(
|
||||
const defaultMessageOptions = await this.getMailOptions(
|
||||
tenantId,
|
||||
saleReceiptId
|
||||
);
|
||||
// Merges message opts with default options.
|
||||
const parsedMessageOpts = parseAndValidateMailOptions(
|
||||
defaultMessageOpts,
|
||||
const parsedMessageOpts = mergeAndValidateMailOptions(
|
||||
defaultMessageOptions,
|
||||
messageOpts
|
||||
);
|
||||
) as SaleReceiptMailOpts;
|
||||
|
||||
const mail = new Mail()
|
||||
.setSubject(parsedMessageOpts.subject)
|
||||
.setTo(parsedMessageOpts.to)
|
||||
.setContent(parsedMessageOpts.body);
|
||||
.setContent(parsedMessageOpts.message);
|
||||
|
||||
// Attaches the receipt pdf document.
|
||||
if (parsedMessageOpts.attachReceipt) {
|
||||
// Retrieves document buffer of the receipt pdf document.
|
||||
const receiptPdfBuffer = await this.receiptPdfService.saleReceiptPdf(
|
||||
tenantId,
|
||||
saleReceiptId
|
||||
);
|
||||
const [receiptPdfBuffer, filename] =
|
||||
await this.receiptPdfService.saleReceiptPdf(tenantId, saleReceiptId);
|
||||
|
||||
mail.setAttachments([
|
||||
{ filename: 'receipt.pdf', content: receiptPdfBuffer },
|
||||
{ filename: `${filename}.pdf`, content: receiptPdfBuffer },
|
||||
]);
|
||||
}
|
||||
const eventPayload = {
|
||||
tenantId,
|
||||
saleReceiptId,
|
||||
messageOptions: {},
|
||||
};
|
||||
await this.eventPublisher.emitAsync(
|
||||
events.saleReceipt.onMailSend,
|
||||
eventPayload
|
||||
);
|
||||
await mail.send();
|
||||
|
||||
await this.eventPublisher.emitAsync(
|
||||
events.saleReceipt.onMailSent,
|
||||
eventPayload
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,10 @@ export class SaleReceiptsPdf {
|
||||
* @param {number} saleInvoiceId -
|
||||
* @returns {Promise<Buffer>}
|
||||
*/
|
||||
public async saleReceiptPdf(tenantId: number, saleReceiptId: number) {
|
||||
public async saleReceiptPdf(
|
||||
tenantId: number,
|
||||
saleReceiptId: number
|
||||
): Promise<[Buffer, string]> {
|
||||
const filename = await this.getSaleReceiptFilename(tenantId, saleReceiptId);
|
||||
|
||||
const brandingAttributes = await this.getReceiptBrandingAttributes(
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
export const DEFAULT_RECEIPT_MAIL_SUBJECT =
|
||||
'Receipt {ReceiptNumber} from {CompanyName}';
|
||||
'Receipt {Receipt Number} from {Company Name}';
|
||||
export const DEFAULT_RECEIPT_MAIL_CONTENT = `
|
||||
<p>Dear {CustomerName}</p>
|
||||
<p>Dear {Customer Name}</p>
|
||||
<p>Thank you for your business, You can view or print your receipt from attachements.</p>
|
||||
<p>
|
||||
Receipt <strong>#{ReceiptNumber}</strong><br />
|
||||
Amount : <strong>{ReceiptAmount}</strong></br />
|
||||
Receipt <strong>#{Receipt Number}</strong><br />
|
||||
Amount : <strong>{Receipt Amount}</strong></br />
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<i>Regards</i><br />
|
||||
<i>{CompanyName}</i>
|
||||
<i>{Company Name}</i>
|
||||
</p>
|
||||
`;
|
||||
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
import { ISaleReceipt, ISaleReceiptBrandingTemplateAttributes } from "@/interfaces";
|
||||
import { contactAddressTextFormat } from "@/utils/address-text-format";
|
||||
import {
|
||||
ISaleReceipt,
|
||||
ISaleReceiptBrandingTemplateAttributes,
|
||||
} from '@/interfaces';
|
||||
import { contactAddressTextFormat } from '@/utils/address-text-format';
|
||||
|
||||
|
||||
|
||||
export const transformReceiptToBrandingTemplateAttributes = (saleReceipt: ISaleReceipt): Partial<ISaleReceiptBrandingTemplateAttributes> => {
|
||||
export const transformReceiptToBrandingTemplateAttributes = (
|
||||
saleReceipt: ISaleReceipt
|
||||
): Partial<ISaleReceiptBrandingTemplateAttributes> => {
|
||||
return {
|
||||
total: saleReceipt.formattedAmount,
|
||||
subtotal: saleReceipt.formattedSubtotal,
|
||||
@@ -18,4 +21,13 @@ export const transformReceiptToBrandingTemplateAttributes = (saleReceipt: ISaleR
|
||||
receiptDate: saleReceipt.formattedReceiptDate,
|
||||
customerAddress: contactAddressTextFormat(saleReceipt.customer),
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
export const transformReceiptToMailDataArgs = (saleReceipt: any) => {
|
||||
return {
|
||||
'Customer Name': saleReceipt.customer.displayName,
|
||||
'Receipt Number': saleReceipt.receiptNumber,
|
||||
'Receipt Date': saleReceipt.formattedReceiptDate,
|
||||
'Receipt Amount': saleReceipt.formattedAmount,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -213,7 +213,7 @@ export default {
|
||||
|
||||
onPreMailSend: 'onSaleEstimatePreMailSend',
|
||||
onMailSend: 'onSaleEstimateMailSend',
|
||||
onMailSent: 'onSaleEstimateMailSend',
|
||||
onMailSent: 'onSaleEstimateMailSent',
|
||||
},
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user