mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-16 04:40:32 +00:00
fix: mail services
This commit is contained in:
@@ -37,7 +37,8 @@ export interface CommonMailOptions {
|
||||
cc?: Array<string>;
|
||||
bcc?: Array<string>;
|
||||
formatArgs?: Record<string, any>;
|
||||
toOptions: Array<AddressItem>;
|
||||
fromOptions: Array<AddressItem>;
|
||||
}
|
||||
|
||||
export interface CommonMailOptionsDTO extends Partial<CommonMailOptions> {
|
||||
}
|
||||
export interface CommonMailOptionsDTO extends Partial<CommonMailOptions> {}
|
||||
|
||||
@@ -58,7 +58,7 @@ export class PdfTemplate extends TenantModel {
|
||||
* @returns {string}
|
||||
*/
|
||||
get companyLogoUri() {
|
||||
return this.attributes.companyLogoKey
|
||||
return this.attributes?.companyLogoKey
|
||||
? getUploadedObjectUri(this.attributes.companyLogoKey)
|
||||
: '';
|
||||
}
|
||||
|
||||
@@ -23,22 +23,24 @@ export class ContactMailNotification {
|
||||
public async getDefaultMailOptions(
|
||||
tenantId: number,
|
||||
customerId: number
|
||||
): Promise<Pick<CommonMailOptions, 'to' | 'from'>> {
|
||||
): Promise<
|
||||
Pick<CommonMailOptions, 'to' | 'from' | 'toOptions' | 'fromOptions'>
|
||||
> {
|
||||
const { Customer } = this.tenancy.models(tenantId);
|
||||
const customer = await Customer.query()
|
||||
.findById(customerId)
|
||||
.throwIfNotFound();
|
||||
|
||||
const toAddresses = customer.contactAddresses;
|
||||
const fromAddresses = await this.mailTenancy.senders(tenantId);
|
||||
const toOptions = customer.contactAddresses;
|
||||
const fromOptions = await this.mailTenancy.senders(tenantId);
|
||||
|
||||
const toAddress = toAddresses.find((a) => a.primary);
|
||||
const fromAddress = fromAddresses.find((a) => a.primary);
|
||||
const toAddress = toOptions.find((a) => a.primary);
|
||||
const fromAddress = fromOptions.find((a) => a.primary);
|
||||
|
||||
const to = toAddress?.mail ? castArray(toAddress?.mail) : [];
|
||||
const from = fromAddress?.mail ? castArray(fromAddress?.mail) : [];
|
||||
|
||||
return { to, from };
|
||||
return { to, from, toOptions, fromOptions };
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -129,8 +129,8 @@ export class SendSaleInvoiceMailCommon {
|
||||
...commonArgs,
|
||||
'Customer Name': invoice.customer.displayName,
|
||||
'Invoice Number': invoice.invoiceNo,
|
||||
'Invoice DueAmount': invoice.dueAmountFormatted,
|
||||
'Invoice DueDate': invoice.dueDateFormatted,
|
||||
'Invoice Due Amount': invoice.dueAmountFormatted,
|
||||
'Invoice Due Date': invoice.dueDateFormatted,
|
||||
'Invoice Date': invoice.invoiceDateFormatted,
|
||||
'Invoice Amount': invoice.totalFormatted,
|
||||
'Overdue Days': invoice.overdueDays,
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
import { Inject, Service } from 'typedi';
|
||||
import Mail from '@/lib/Mail';
|
||||
import { ISaleInvoiceMailSend, SendInvoiceMailDTO } from '@/interfaces';
|
||||
import {
|
||||
ISaleInvoiceMailSend,
|
||||
SaleInvoiceMailOptions,
|
||||
SendInvoiceMailDTO,
|
||||
} from '@/interfaces';
|
||||
import { SaleInvoicePdf } from './SaleInvoicePdf';
|
||||
import { SendSaleInvoiceMailCommon } from './SendInvoiceInvoiceMailCommon';
|
||||
import { mergeAndValidateMailOptions } from '@/services/MailNotification/utils';
|
||||
@@ -47,6 +51,34 @@ export class SendSaleInvoiceMail {
|
||||
} as ISaleInvoiceMailSend);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the formatted mail options.
|
||||
* @param {number} tenantId
|
||||
* @param {number} saleInvoiceId
|
||||
* @param {SendInvoiceMailDTO} messageOptions
|
||||
* @returns {Promise<SaleInvoiceMailOptions>}
|
||||
*/
|
||||
async getFormattedMailOptions(
|
||||
tenantId: number,
|
||||
saleInvoiceId: number,
|
||||
messageOptions: SendInvoiceMailDTO
|
||||
): Promise<SaleInvoiceMailOptions> {
|
||||
const defaultMessageOptions = await this.invoiceMail.getInvoiceMailOptions(
|
||||
tenantId,
|
||||
saleInvoiceId
|
||||
);
|
||||
// Merges message options with default options and parses the options values.
|
||||
const parsedMessageOptions = mergeAndValidateMailOptions(
|
||||
defaultMessageOptions,
|
||||
messageOptions
|
||||
);
|
||||
return this.invoiceMail.formatInvoiceMailOptions(
|
||||
tenantId,
|
||||
saleInvoiceId,
|
||||
parsedMessageOptions
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Triggers the mail invoice.
|
||||
* @param {number} tenantId
|
||||
@@ -59,21 +91,11 @@ export class SendSaleInvoiceMail {
|
||||
saleInvoiceId: number,
|
||||
messageOptions: SendInvoiceMailDTO
|
||||
) {
|
||||
const defaultMessageOptions = await this.invoiceMail.getInvoiceMailOptions(
|
||||
const formattedMessageOptions = await this.getFormattedMailOptions(
|
||||
tenantId,
|
||||
saleInvoiceId
|
||||
);
|
||||
// Merges message options with default options and parses the options values.
|
||||
const parsedMessageOptions = mergeAndValidateMailOptions(
|
||||
defaultMessageOptions,
|
||||
saleInvoiceId,
|
||||
messageOptions
|
||||
);
|
||||
const formattedMessageOptions =
|
||||
await this.invoiceMail.formatInvoiceMailOptions(
|
||||
tenantId,
|
||||
saleInvoiceId,
|
||||
parsedMessageOptions
|
||||
);
|
||||
const mail = new Mail()
|
||||
.setSubject(formattedMessageOptions.subject)
|
||||
.setTo(formattedMessageOptions.to)
|
||||
|
||||
@@ -112,17 +112,20 @@ export class SendPaymentReceiveMailNotification {
|
||||
};
|
||||
|
||||
/**
|
||||
* Triggers the mail invoice.
|
||||
* Retrieves the formatted mail options of the given payment receive.
|
||||
* @param {number} tenantId
|
||||
* @param {number} saleInvoiceId
|
||||
* @param {number} paymentReceiveId
|
||||
* @param {SendInvoiceMailDTO} messageDTO
|
||||
* @returns {Promise<void>}
|
||||
* @returns {Promise<PaymentReceiveMailOpts>}
|
||||
*/
|
||||
public async sendMail(
|
||||
public getFormattedMailOptions = async (
|
||||
tenantId: number,
|
||||
paymentReceiveId: number,
|
||||
messageDTO: SendInvoiceMailDTO
|
||||
): Promise<void> {
|
||||
) => {
|
||||
const formatterArgs = await this.textFormatter(tenantId, paymentReceiveId);
|
||||
|
||||
// Default message options.
|
||||
const defaultMessageOpts = await this.getMailOptions(
|
||||
tenantId,
|
||||
paymentReceiveId
|
||||
@@ -132,17 +135,43 @@ export class SendPaymentReceiveMailNotification {
|
||||
defaultMessageOpts,
|
||||
messageDTO
|
||||
);
|
||||
// Formats the message options.
|
||||
return this.contactMailNotification.formatMailOptions(
|
||||
tenantId,
|
||||
parsedMessageOpts,
|
||||
formatterArgs
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Triggers the mail invoice.
|
||||
* @param {number} tenantId
|
||||
* @param {number} saleInvoiceId - Invoice id.
|
||||
* @param {SendInvoiceMailDTO} messageDTO - Message options.
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
public async sendMail(
|
||||
tenantId: number,
|
||||
paymentReceiveId: number,
|
||||
messageDTO: SendInvoiceMailDTO
|
||||
): Promise<void> {
|
||||
// Retrieves the formatted mail options.
|
||||
const formattedMessageOptions = await this.getFormattedMailOptions(
|
||||
tenantId,
|
||||
paymentReceiveId,
|
||||
messageDTO
|
||||
);
|
||||
const mail = new Mail()
|
||||
.setSubject(parsedMessageOpts.subject)
|
||||
.setTo(parsedMessageOpts.to)
|
||||
.setCC(parsedMessageOpts.cc)
|
||||
.setBCC(parsedMessageOpts.bcc)
|
||||
.setContent(parsedMessageOpts.message);
|
||||
.setSubject(formattedMessageOptions.subject)
|
||||
.setTo(formattedMessageOptions.to)
|
||||
.setCC(formattedMessageOptions.cc)
|
||||
.setBCC(formattedMessageOptions.bcc)
|
||||
.setContent(formattedMessageOptions.message);
|
||||
|
||||
const eventPayload = {
|
||||
tenantId,
|
||||
paymentReceiveId,
|
||||
messageOptions: parsedMessageOpts,
|
||||
messageOptions: formattedMessageOptions,
|
||||
};
|
||||
// Triggers `onPaymentReceiveMailSend` event.
|
||||
await this.eventPublisher.emitAsync(
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
export const DEFAULT_PAYMENT_MAIL_SUBJECT = 'Payment Received by {CompanyName}';
|
||||
export const DEFAULT_PAYMENT_MAIL_SUBJECT =
|
||||
'Payment Received for {Customer Name} from {Company Name}';
|
||||
export const DEFAULT_PAYMENT_MAIL_CONTENT = `
|
||||
<p>Dear {CustomerName}</p>
|
||||
<p>Dear {Customer Name}</p>
|
||||
<p>Thank you for your payment. It was a pleasure doing business with you. We look forward to work together again!</p>
|
||||
<p>
|
||||
Payment Date : <strong>{PaymentDate}</strong><br />
|
||||
Amount : <strong>{PaymentAmount}</strong></br />
|
||||
Payment Date : <strong>{Payment Date}</strong><br />
|
||||
Amount : <strong>{Payment Amount}</strong></br />
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<i>Regards</i><br />
|
||||
<i>{CompanyName}</i>
|
||||
<i>{Company Name}</i>
|
||||
</p>
|
||||
`;
|
||||
|
||||
|
||||
@@ -114,6 +114,58 @@ export class SaleReceiptMailNotification {
|
||||
return transformReceiptToMailDataArgs(receipt);
|
||||
};
|
||||
|
||||
/**
|
||||
* Formats the mail options of the given sale receipt.
|
||||
* @param {number} tenantId
|
||||
* @param {number} receiptId
|
||||
* @param {SaleReceiptMailOpts} mailOptions
|
||||
* @returns {Promise<SaleReceiptMailOpts>}
|
||||
*/
|
||||
public async formatEstimateMailOptions(
|
||||
tenantId: number,
|
||||
receiptId: number,
|
||||
mailOptions: SaleReceiptMailOpts
|
||||
): Promise<SaleReceiptMailOpts> {
|
||||
const formatterArgs = await this.textFormatterArgs(tenantId, receiptId);
|
||||
const formattedOptions =
|
||||
(await this.contactMailNotification.formatMailOptions(
|
||||
tenantId,
|
||||
mailOptions,
|
||||
formatterArgs
|
||||
)) as SaleReceiptMailOpts;
|
||||
return formattedOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the formatted mail options of the given sale receipt.
|
||||
* @param {number} tenantId
|
||||
* @param {number} saleReceiptId
|
||||
* @param {SaleReceiptMailOptsDTO} messageOpts
|
||||
* @returns {Promise<SaleReceiptMailOpts>}
|
||||
*/
|
||||
public getFormatMailOptions = async (
|
||||
tenantId: number,
|
||||
saleReceiptId: number,
|
||||
messageOpts: SaleReceiptMailOptsDTO
|
||||
): Promise<SaleReceiptMailOpts> => {
|
||||
const defaultMessageOptions = await this.getMailOptions(
|
||||
tenantId,
|
||||
saleReceiptId
|
||||
);
|
||||
// Merges message opts with default options.
|
||||
const parsedMessageOpts = mergeAndValidateMailOptions(
|
||||
defaultMessageOptions,
|
||||
messageOpts
|
||||
) as SaleReceiptMailOpts;
|
||||
|
||||
// Formats the message options.
|
||||
return this.formatEstimateMailOptions(
|
||||
tenantId,
|
||||
saleReceiptId,
|
||||
parsedMessageOpts
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Triggers the mail notification of the given sale receipt.
|
||||
* @param {number} tenantId - Tenant id.
|
||||
@@ -126,25 +178,21 @@ export class SaleReceiptMailNotification {
|
||||
saleReceiptId: number,
|
||||
messageOpts: SaleReceiptMailOptsDTO
|
||||
) {
|
||||
const defaultMessageOptions = await this.getMailOptions(
|
||||
// Formats the message options.
|
||||
const formattedMessageOptions = await this.getFormatMailOptions(
|
||||
tenantId,
|
||||
saleReceiptId
|
||||
);
|
||||
// Merges message opts with default options.
|
||||
const parsedMessageOpts = mergeAndValidateMailOptions(
|
||||
defaultMessageOptions,
|
||||
saleReceiptId,
|
||||
messageOpts
|
||||
) as SaleReceiptMailOpts;
|
||||
|
||||
);
|
||||
const mail = new Mail()
|
||||
.setSubject(parsedMessageOpts.subject)
|
||||
.setTo(parsedMessageOpts.to)
|
||||
.setCC(parsedMessageOpts.cc)
|
||||
.setBCC(parsedMessageOpts.bcc)
|
||||
.setContent(parsedMessageOpts.message);
|
||||
.setSubject(formattedMessageOptions.subject)
|
||||
.setTo(formattedMessageOptions.to)
|
||||
.setCC(formattedMessageOptions.cc)
|
||||
.setBCC(formattedMessageOptions.bcc)
|
||||
.setContent(formattedMessageOptions.message);
|
||||
|
||||
// Attaches the receipt pdf document.
|
||||
if (parsedMessageOpts.attachReceipt) {
|
||||
if (formattedMessageOptions.attachReceipt) {
|
||||
// Retrieves document buffer of the receipt pdf document.
|
||||
const [receiptPdfBuffer, filename] =
|
||||
await this.receiptPdfService.saleReceiptPdf(tenantId, saleReceiptId);
|
||||
|
||||
@@ -32,7 +32,7 @@ function EstimateMailDialogFormRoot({
|
||||
closeDialog,
|
||||
}) {
|
||||
const { mutateAsync: sendEstimateMail } = useSendSaleEstimateMail();
|
||||
const { mailOptions, saleEstimateId, redirectToEstimatesList } =
|
||||
const { mailOptions, saleEstimateId, } =
|
||||
useEstimateMailDialogBoot();
|
||||
|
||||
const initialValues = transformMailFormToInitialValues(
|
||||
|
||||
@@ -25,8 +25,8 @@ export function EstimateMailDialogFormContent({
|
||||
<Form>
|
||||
<div className={Classes.DIALOG_BODY}>
|
||||
<MailNotificationForm
|
||||
fromAddresses={mailOptions.from_addresses}
|
||||
toAddresses={mailOptions.to_addresses}
|
||||
fromAddresses={mailOptions.from_options}
|
||||
toAddresses={mailOptions.to_options}
|
||||
/>
|
||||
<AttachFormGroup name={'attachEstimate'} inline>
|
||||
<FSwitch name={'attachEstimate'} label={'Attach Estimate'} />
|
||||
|
||||
@@ -22,6 +22,7 @@ interface PaymentMailDialogBootProps {
|
||||
*/
|
||||
function PaymentMailDialogBoot({
|
||||
paymentReceiveId,
|
||||
redirectToPaymentsList,
|
||||
...props
|
||||
}: PaymentMailDialogBootProps) {
|
||||
const { data: mailOptions, isLoading: isMailOptionsLoading } =
|
||||
|
||||
@@ -25,8 +25,8 @@ export function PaymentMailDialogFormContent({
|
||||
<Form>
|
||||
<div className={Classes.DIALOG_BODY}>
|
||||
<MailNotificationForm
|
||||
fromAddresses={mailOptions.from_addresses}
|
||||
toAddresses={mailOptions.to_addresses}
|
||||
fromAddresses={mailOptions.from_options}
|
||||
toAddresses={mailOptions.to_options}
|
||||
/>
|
||||
<AttachFormGroup name={'attachPayment'} inline>
|
||||
<FSwitch name={'attachPayment'} label={'Attach Payment'} />
|
||||
|
||||
@@ -25,8 +25,8 @@ export function ReceiptMailDialogFormContent({
|
||||
<Form>
|
||||
<div className={Classes.DIALOG_BODY}>
|
||||
<MailNotificationForm
|
||||
fromAddresses={mailOptions.from_addresses}
|
||||
toAddresses={mailOptions.to_addresses}
|
||||
fromAddresses={mailOptions.from_options}
|
||||
toAddresses={mailOptions.to_options}
|
||||
/>
|
||||
<AttachFormGroup name={'attachReceipt:'} inline>
|
||||
<FSwitch name={'attachReceipt:'} label={'Attach Receipt'} />
|
||||
|
||||
@@ -66,7 +66,7 @@ export function MailNotificationForm({
|
||||
</FFormGroup>
|
||||
</HeaderBox>
|
||||
|
||||
<MailMessageEditor name={'body'} />
|
||||
<MailMessageEditor name={'message'} />
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ export const initialMailNotificationValues = {
|
||||
from: [],
|
||||
to: [],
|
||||
subject: '',
|
||||
body: '',
|
||||
message: '',
|
||||
};
|
||||
|
||||
export interface MailNotificationFormValues {
|
||||
@@ -26,7 +26,7 @@ export const transformMailFormToRequest = (
|
||||
};
|
||||
|
||||
/**
|
||||
* Transformes the mail options response values to form initial values.
|
||||
* Transforms the mail options response values to form initial values.
|
||||
* @param {any} mailOptions
|
||||
* @param {MailNotificationFormValues} initialValues
|
||||
* @returns {MailNotificationFormValues}
|
||||
|
||||
Reference in New Issue
Block a user