From 3537a05ea2408c65fc6b13abe4fe87f92d49d145 Mon Sep 17 00:00:00 2001 From: Ahmed Bouhuolia Date: Sun, 24 Nov 2024 13:19:26 +0200 Subject: [PATCH] feat: payment received mail preview --- .../api/controllers/Sales/PaymentReceives.ts | 13 ++- .../api/controllers/Sales/SalesEstimates.ts | 17 +++- .../api/controllers/Sales/SalesReceipts.ts | 17 +++- .../server/src/interfaces/PaymentReceive.ts | 7 +- .../Estimates/GetEstimateMailTemplate.ts | 75 +++++++++++++++ ...timateMailTemplateAttributesTransformer.ts | 3 + .../Sales/Estimates/SendSaleEstimateMail.ts | 61 ++++++++---- .../GetPaymentReceivedMailState.tsx | 13 ++- .../GetPaymentReceivedMailTemplate.ts | 75 +++++++++++++++ ...entReceivedMailTemplateAttrsTransformer.ts | 3 + .../PaymentReceivedMailNotification.ts | 95 +++++++++++++++++-- .../Receipts/GetSaleReceiptMailTemplate.ts | 75 +++++++++++++++ ...eceiptMailTemplateAttributesTransformer.ts | 3 + .../Receipts/SaleReceiptMailNotification.ts | 14 ++- .../EstimateSendMailForm.tsx | 2 +- .../PaymentReceivedMailForm.tsx | 6 +- .../ReceiptSendMailForm.tsx | 2 +- .../src/hooks/query/paymentReceives.tsx | 2 +- shared/email-components/src/lib/main.ts | 4 + 19 files changed, 438 insertions(+), 49 deletions(-) create mode 100644 packages/server/src/services/Sales/Estimates/GetEstimateMailTemplate.ts create mode 100644 packages/server/src/services/Sales/Estimates/GetEstimateMailTemplateAttributesTransformer.ts create mode 100644 packages/server/src/services/Sales/PaymentReceived/GetPaymentReceivedMailTemplate.ts create mode 100644 packages/server/src/services/Sales/PaymentReceived/GetPaymentReceivedMailTemplateAttrsTransformer.ts create mode 100644 packages/server/src/services/Sales/Receipts/GetSaleReceiptMailTemplate.ts create mode 100644 packages/server/src/services/Sales/Receipts/GetSaleReceiptMailTemplateAttributesTransformer.ts diff --git a/packages/server/src/api/controllers/Sales/PaymentReceives.ts b/packages/server/src/api/controllers/Sales/PaymentReceives.ts index 0fb903de4..9e128411a 100644 --- a/packages/server/src/api/controllers/Sales/PaymentReceives.ts +++ b/packages/server/src/api/controllers/Sales/PaymentReceives.ts @@ -130,9 +130,18 @@ export default class PaymentReceivesController extends BaseController { [ ...this.paymentReceiveValidation, body('subject').isString().optional(), + body('from').isString().optional(), - body('to').isString().optional(), - body('body').isString().optional(), + + body('to').isArray().exists(), + body('to.*').isString().isEmail().optional(), + + body('cc').isArray().optional({ nullable: true }), + body('cc.*').isString().isEmail().optional(), + + body('bcc').isArray().optional({ nullable: true }), + body('bcc.*').isString().isEmail().optional(), + body('attach_invoice').optional().isBoolean().toBoolean(), ], this.sendPaymentReceiveByMail.bind(this), diff --git a/packages/server/src/api/controllers/Sales/SalesEstimates.ts b/packages/server/src/api/controllers/Sales/SalesEstimates.ts index 961b20fc1..8f284023c 100644 --- a/packages/server/src/api/controllers/Sales/SalesEstimates.ts +++ b/packages/server/src/api/controllers/Sales/SalesEstimates.ts @@ -130,8 +130,18 @@ export default class SalesEstimatesController extends BaseController { [ ...this.validateSpecificEstimateSchema, body('subject').isString().optional(), + body('from').isString().optional(), - body('to').isString().optional(), + + body('to').isArray().exists(), + body('to.*').isString().isEmail().optional(), + + body('cc').isArray().optional({ nullable: true }), + body('cc.*').isString().isEmail().optional(), + + body('bcc').isArray().optional({ nullable: true }), + body('bcc.*').isString().isEmail().optional(), + body('body').isString().optional(), body('attach_invoice').optional().isBoolean().toBoolean(), ], @@ -567,8 +577,9 @@ export default class SalesEstimatesController extends BaseController { const { tenantId } = req; try { - const data = - await this.saleEstimatesApplication.getSaleEstimateState(tenantId); + const data = await this.saleEstimatesApplication.getSaleEstimateState( + tenantId + ); return res.status(200).send({ data }); } catch (error) { next(error); diff --git a/packages/server/src/api/controllers/Sales/SalesReceipts.ts b/packages/server/src/api/controllers/Sales/SalesReceipts.ts index 3b185634f..18a9506cc 100644 --- a/packages/server/src/api/controllers/Sales/SalesReceipts.ts +++ b/packages/server/src/api/controllers/Sales/SalesReceipts.ts @@ -56,8 +56,18 @@ export default class SalesReceiptsController extends BaseController { [ ...this.specificReceiptValidationSchema, body('subject').isString().optional(), + body('from').isString().optional(), - body('to').isString().optional(), + + body('to').isArray().exists(), + body('to.*').isString().isEmail().optional(), + + body('cc').isArray().optional({ nullable: true }), + body('cc.*').isString().isEmail().optional(), + + body('bcc').isArray().optional({ nullable: true }), + body('bcc.*').isString().isEmail().optional(), + body('body').isString().optional(), body('attach_receipt').optional().isBoolean().toBoolean(), ], @@ -399,8 +409,9 @@ export default class SalesReceiptsController extends BaseController { // Retrieves receipt in pdf format. try { - const data = - await this.saleReceiptsApplication.getSaleReceiptState(tenantId); + const data = await this.saleReceiptsApplication.getSaleReceiptState( + tenantId + ); return res.status(200).send({ data }); } catch (error) { next(error); diff --git a/packages/server/src/interfaces/PaymentReceive.ts b/packages/server/src/interfaces/PaymentReceive.ts index ccba86b59..695a3b17a 100644 --- a/packages/server/src/interfaces/PaymentReceive.ts +++ b/packages/server/src/interfaces/PaymentReceive.ts @@ -177,7 +177,9 @@ export type IPaymentReceiveGLCommonEntry = Pick< | 'branchId' >; -export interface PaymentReceiveMailOpts extends CommonMailOptions {} +export interface PaymentReceiveMailOpts extends CommonMailOptions { + attachPdf?: boolean; +} export interface PaymentReceiveMailOptsDTO extends CommonMailOptionsDTO {} @@ -239,7 +241,6 @@ export interface PaymentReceivedPdfTemplateAttributes { paymentReceivedDateLabel: string; } - export interface IPaymentReceivedState { defaultTemplateId: number; -} \ No newline at end of file +} diff --git a/packages/server/src/services/Sales/Estimates/GetEstimateMailTemplate.ts b/packages/server/src/services/Sales/Estimates/GetEstimateMailTemplate.ts new file mode 100644 index 000000000..11fb01bd0 --- /dev/null +++ b/packages/server/src/services/Sales/Estimates/GetEstimateMailTemplate.ts @@ -0,0 +1,75 @@ +import { Inject, Service } from 'typedi'; +import { + renderEstimateEmailTemplate, + EstimatePaymentEmailProps, +} from '@bigcapital/email-components'; +import { GetSaleEstimate } from './GetSaleEstimate'; +import { TransformerInjectable } from '@/lib/Transformer/TransformerInjectable'; +import { GetEstimateMailTemplateAttributesTransformer } from './GetEstimateMailTemplateAttributesTransformer'; +import { GetPdfTemplate } from '@/services/PdfTemplate/GetPdfTemplate'; + +@Service() +export class GetEstimateMailTemplate { + @Inject() + private getEstimateService: GetSaleEstimate; + + @Inject() + private transformer: TransformerInjectable; + + @Inject() + private getBrandingTemplate: GetPdfTemplate; + + /** + * Retrieves the mail template attributes of the given estimate. + * Estimate template attributes are composed of the estimate and branding template attributes. + * @param {number} tenantId + * @param {number} estimateId - Estimate id. + * @returns {Promise} + */ + public async getMailTemplateAttributes( + tenantId: number, + estimateId: number + ): Promise { + const estimate = await this.getEstimateService.getEstimate( + tenantId, + estimateId + ); + const brandingTemplate = await this.getBrandingTemplate.getPdfTemplate( + tenantId, + estimate.pdfTemplateId + ); + const mailTemplateAttributes = await this.transformer.transform( + tenantId, + estimate, + new GetEstimateMailTemplateAttributesTransformer(), + { + estimate, + brandingTemplate, + } + ); + return mailTemplateAttributes; + } + + /** + * Rertieves the mail template html content. + * @param {number} tenantId + * @param {number} estimateId + * @param overrideAttributes + * @returns + */ + public async getMailTemplate( + tenantId: number, + estimateId: number, + overrideAttributes?: Partial + ): Promise { + const attributes = await this.getMailTemplateAttributes( + tenantId, + estimateId + ); + const mergedAttributes = { + ...attributes, + ...overrideAttributes, + }; + return renderEstimateEmailTemplate(mergedAttributes); + } +} diff --git a/packages/server/src/services/Sales/Estimates/GetEstimateMailTemplateAttributesTransformer.ts b/packages/server/src/services/Sales/Estimates/GetEstimateMailTemplateAttributesTransformer.ts new file mode 100644 index 000000000..e1fb9b164 --- /dev/null +++ b/packages/server/src/services/Sales/Estimates/GetEstimateMailTemplateAttributesTransformer.ts @@ -0,0 +1,3 @@ +import { Transformer } from '@/lib/Transformer/Transformer'; + +export class GetEstimateMailTemplateAttributesTransformer extends Transformer {} diff --git a/packages/server/src/services/Sales/Estimates/SendSaleEstimateMail.ts b/packages/server/src/services/Sales/Estimates/SendSaleEstimateMail.ts index 1c1ada66a..adb5600cc 100644 --- a/packages/server/src/services/Sales/Estimates/SendSaleEstimateMail.ts +++ b/packages/server/src/services/Sales/Estimates/SendSaleEstimateMail.ts @@ -17,6 +17,7 @@ import { mergeAndValidateMailOptions } from '@/services/MailNotification/utils'; import { EventPublisher } from '@/lib/EventPublisher/EventPublisher'; import events from '@/subscribers/events'; import { transformEstimateToMailDataArgs } from './utils'; +import { GetEstimateMailTemplate } from './GetEstimateMailTemplate'; @Service() export class SendSaleEstimateMail { @@ -32,12 +33,15 @@ export class SendSaleEstimateMail { @Inject() private contactMailNotification: ContactMailNotification; - @Inject('agenda') - private agenda: any; + @Inject() + private getEstimateMailTemplate: GetEstimateMailTemplate; @Inject() private eventPublisher: EventPublisher; + @Inject('agenda') + private agenda: any; + /** * Triggers the reminder mail of the given sale estimate. * @param {number} tenantId - @@ -132,9 +136,45 @@ export class SendSaleEstimateMail { mailOptions, formatterArgs ); - return { ...formattedOptions }; + // Retrieves the estimate mail template. + const message = await this.getEstimateMailTemplate.getMailTemplate( + tenantId, + saleEstimateId, + { + message: formattedOptions.message, + preview: formattedOptions.message, + } + ); + return { ...formattedOptions, message }; }; + /** + * Retrieves the formatted mail options. + * @param {number} tenantId + * @param {number} saleEstimateId + * @param {SaleEstimateMailOptionsDTO} messageOptions + * @returns + */ + public async getFormattedMailOptions( + tenantId: number, + saleEstimateId: number, + messageOptions: SaleEstimateMailOptionsDTO + ): Promise { + const defaultMessageOptions = await this.getMailOptions( + tenantId, + saleEstimateId + ); + const parsedMessageOptions = mergeAndValidateMailOptions( + defaultMessageOptions, + messageOptions + ); + return this.formatMailOptions( + tenantId, + saleEstimateId, + parsedMessageOptions + ); + } + /** * Sends the mail notification of the given sale estimate. * @param {number} tenantId @@ -147,20 +187,10 @@ export class SendSaleEstimateMail { saleEstimateId: number, messageOptions: SaleEstimateMailOptionsDTO ): Promise { - const localMessageOpts = await this.getMailOptions( - tenantId, - saleEstimateId - ); - // Overrides and validates the given mail options. - const parsedMessageOptions = mergeAndValidateMailOptions( - localMessageOpts, - messageOptions - ) as SaleEstimateMailOptions; - - const formattedOptions = await this.formatMailOptions( + const formattedOptions = await this.getFormattedMailOptions( tenantId, saleEstimateId, - parsedMessageOptions + messageOptions ); const mail = new Mail() .setSubject(formattedOptions.subject) @@ -182,7 +212,6 @@ export class SendSaleEstimateMail { }, ]); } - const eventPayload = { tenantId, saleEstimateId, diff --git a/packages/server/src/services/Sales/PaymentReceived/GetPaymentReceivedMailState.tsx b/packages/server/src/services/Sales/PaymentReceived/GetPaymentReceivedMailState.tsx index 7c6271c71..20107db01 100644 --- a/packages/server/src/services/Sales/PaymentReceived/GetPaymentReceivedMailState.tsx +++ b/packages/server/src/services/Sales/PaymentReceived/GetPaymentReceivedMailState.tsx @@ -4,6 +4,7 @@ import { GetPaymentReceivedMailStateTransformer } from './GetPaymentReceivedMail import { TransformerInjectable } from '@/lib/Transformer/TransformerInjectable'; import { Inject, Service } from 'typedi'; import { ContactMailNotification } from '@/services/MailNotification/ContactMailNotification'; +import { SendPaymentReceiveMailNotification } from './PaymentReceivedMailNotification'; @Service() export class GetPaymentReceivedMailState { @@ -11,7 +12,7 @@ export class GetPaymentReceivedMailState { private tenancy: HasTenancyService; @Inject() - private contactMailNotification: ContactMailNotification; + private paymentReceivedMail: SendPaymentReceiveMailNotification; @Inject() private transformer: TransformerInjectable; @@ -35,12 +36,10 @@ export class GetPaymentReceivedMailState { .withGraphFetched('pdfTemplate') .throwIfNotFound(); - const mailOptions = - await this.contactMailNotification.getDefaultMailOptions( - tenantId, - paymentReceive.customerId - ); - + const mailOptions = await this.paymentReceivedMail.getMailOptions( + tenantId, + paymentId + ); const transformed = await this.transformer.transform( tenantId, paymentReceive, diff --git a/packages/server/src/services/Sales/PaymentReceived/GetPaymentReceivedMailTemplate.ts b/packages/server/src/services/Sales/PaymentReceived/GetPaymentReceivedMailTemplate.ts new file mode 100644 index 000000000..8e5f1cf5c --- /dev/null +++ b/packages/server/src/services/Sales/PaymentReceived/GetPaymentReceivedMailTemplate.ts @@ -0,0 +1,75 @@ +import { Inject, Service } from 'typedi'; +import { TransformerInjectable } from '@/lib/Transformer/TransformerInjectable'; +import { GetPdfTemplate } from '@/services/PdfTemplate/GetPdfTemplate'; +import { GetPaymentReceived } from './GetPaymentReceived'; +import { GetPaymentReceivedMailTemplateAttrsTransformer } from './GetPaymentReceivedMailTemplateAttrsTransformer'; +import { + PaymentReceivedEmailTemplateProps, + renderPaymentReceivedEmailTemplate, +} from '@bigcapital/email-components'; + +@Service() +export class GetPaymentReceivedMailTemplate { + @Inject() + private getPaymentReceivedService: GetPaymentReceived; + + @Inject() + private getBrandingTemplate: GetPdfTemplate; + + @Inject() + private transformer: TransformerInjectable; + + /** + * Retrieves the mail template attributes of the given payment received. + * @param {number} tenantId - Tenant id. + * @param {number} paymentReceivedId - Payment received id. + * @returns {Promise} + */ + public async getMailTemplateAttributes( + tenantId: number, + paymentReceivedId: number + ): Promise { + const paymentReceived = + await this.getPaymentReceivedService.getPaymentReceive( + tenantId, + paymentReceivedId + ); + const brandingTemplate = await this.getBrandingTemplate.getPdfTemplate( + tenantId, + paymentReceived.pdfTemplateId + ); + const mailTemplateAttributes = await this.transformer.transform( + tenantId, + paymentReceived, + new GetPaymentReceivedMailTemplateAttrsTransformer(), + { + paymentReceived, + brandingTemplate, + } + ); + return mailTemplateAttributes; + } + + /** + * Retrieves the mail template html content. + * @param {number} tenantId + * @param {number} paymentReceivedId + * @param {Partial} overrideAttributes + * @returns + */ + public async getMailTemplate( + tenantId: number, + paymentReceivedId: number, + overrideAttributes?: Partial + ): Promise { + const mailTemplateAttributes = await this.getMailTemplateAttributes( + tenantId, + paymentReceivedId + ); + const mergedAttributes = { + ...mailTemplateAttributes, + ...overrideAttributes, + }; + return renderPaymentReceivedEmailTemplate(mergedAttributes); + } +} diff --git a/packages/server/src/services/Sales/PaymentReceived/GetPaymentReceivedMailTemplateAttrsTransformer.ts b/packages/server/src/services/Sales/PaymentReceived/GetPaymentReceivedMailTemplateAttrsTransformer.ts new file mode 100644 index 000000000..10d9059c8 --- /dev/null +++ b/packages/server/src/services/Sales/PaymentReceived/GetPaymentReceivedMailTemplateAttrsTransformer.ts @@ -0,0 +1,3 @@ +import { Transformer } from '@/lib/Transformer/Transformer'; + +export class GetPaymentReceivedMailTemplateAttrsTransformer extends Transformer {} diff --git a/packages/server/src/services/Sales/PaymentReceived/PaymentReceivedMailNotification.ts b/packages/server/src/services/Sales/PaymentReceived/PaymentReceivedMailNotification.ts index fbd2d236c..daaa43c8c 100644 --- a/packages/server/src/services/Sales/PaymentReceived/PaymentReceivedMailNotification.ts +++ b/packages/server/src/services/Sales/PaymentReceived/PaymentReceivedMailNotification.ts @@ -15,8 +15,9 @@ import { GetPaymentReceived } from './GetPaymentReceived'; import { ContactMailNotification } from '@/services/MailNotification/ContactMailNotification'; import { mergeAndValidateMailOptions } from '@/services/MailNotification/utils'; import { EventPublisher } from '@/lib/EventPublisher/EventPublisher'; -import events from '@/subscribers/events'; import { transformPaymentReceivedToMailDataArgs } from './utils'; +import { GetPaymentReceivedMailTemplate } from './GetPaymentReceivedMailTemplate'; +import events from '@/subscribers/events'; @Service() export class SendPaymentReceiveMailNotification { @@ -29,12 +30,15 @@ export class SendPaymentReceiveMailNotification { @Inject() private contactMailNotification: ContactMailNotification; - @Inject('agenda') - private agenda: any; - @Inject() private eventPublisher: EventPublisher; + @Inject() + private paymentMailTemplate: GetPaymentReceivedMailTemplate; + + @Inject('agenda') + private agenda: any; + /** * Sends the mail of the given payment receive. * @param {number} tenantId @@ -77,7 +81,82 @@ export class SendPaymentReceiveMailNotification { tenantId, invoiceId ); - return transformPaymentReceivedToMailDataArgs(payment); + const commonArgs = await this.contactMailNotification.getCommonFormatArgs( + tenantId + ); + const paymentArgs = transformPaymentReceivedToMailDataArgs(payment); + + return { + ...commonArgs, + ...paymentArgs, + }; + }; + + /** + * Retrieves the mail options of the given payment received. + * @param {number} tenantId - Tenant id. + * @param {number} paymentReceivedId - Payment received id. + * @param {string} defaultSubject - Default subject of the mail. + * @param {string} defaultContent - Default content of the mail. + * @returns + */ + public getMailOptions = async ( + tenantId: number, + paymentReceivedId: number, + defaultSubject: string = DEFAULT_PAYMENT_MAIL_SUBJECT, + defaultContent: string = DEFAULT_PAYMENT_MAIL_CONTENT + ): Promise => { + const { PaymentReceive } = this.tenancy.models(tenantId); + + const paymentReceived = await PaymentReceive.query().findById( + paymentReceivedId + ); + const formatArgs = await this.textFormatter(tenantId, paymentReceivedId); + + // Retrieves the default mail options. + const mailOptions = + await this.contactMailNotification.getDefaultMailOptions( + tenantId, + paymentReceived.customerId + ); + return { + ...mailOptions, + message: defaultContent, + subject: defaultSubject, + attachPdf: true, + formatArgs, + }; + }; + + /** + * Formats the mail options of the given payment receive. + * @param {number} tenantId + * @param {number} paymentReceiveId + * @param {PaymentReceiveMailOpts} mailOptions + * @returns {Promise} + */ + public formattedMailOptions = async ( + tenantId: number, + paymentReceiveId: number, + mailOptions: PaymentReceiveMailOpts + ): Promise => { + const formatterArgs = await this.textFormatter(tenantId, paymentReceiveId); + const formattedOptions = + await this.contactMailNotification.formatMailOptions( + tenantId, + mailOptions, + formatterArgs + ); + // Retrieves the mail template. + const message = await this.paymentMailTemplate.getMailTemplate( + tenantId, + paymentReceiveId, + { + message: formattedOptions.message, + preview: formattedOptions.message, + } + ); + return { ...formattedOptions, message }; }; /** @@ -105,10 +184,10 @@ export class SendPaymentReceiveMailNotification { messageDTO ); // Formats the message options. - return this.contactMailNotification.formatMailOptions( + return this.formattedMailOptions( tenantId, - parsedMessageOpts, - formatterArgs + paymentReceiveId, + parsedMessageOpts ); }; diff --git a/packages/server/src/services/Sales/Receipts/GetSaleReceiptMailTemplate.ts b/packages/server/src/services/Sales/Receipts/GetSaleReceiptMailTemplate.ts new file mode 100644 index 000000000..2a46e27c9 --- /dev/null +++ b/packages/server/src/services/Sales/Receipts/GetSaleReceiptMailTemplate.ts @@ -0,0 +1,75 @@ +import { + ReceiptEmailTemplateProps, + renderReceiptEmailTemplate, +} from '@bigcapital/email-components'; +import { Inject, Service } from 'typedi'; +import { GetSaleReceipt } from './GetSaleReceipt'; +import { GetPdfTemplate } from '@/services/PdfTemplate/GetPdfTemplate'; +import { TransformerInjectable } from '@/lib/Transformer/TransformerInjectable'; +import { GetSaleReceiptMailTemplateAttributesTransformer } from './GetSaleReceiptMailTemplateAttributesTransformer'; + +@Service() +export class GetSaleReceiptMailTemplate { + @Inject() + private getReceiptService: GetSaleReceipt; + + @Inject() + private transformer: TransformerInjectable; + + @Inject() + private getBrandingTemplate: GetPdfTemplate; + + /** + * Retrieves the mail template attributes of the given estimate. + * Estimate template attributes are composed of the estimate and branding template attributes. + * @param {number} tenantId + * @param {number} receiptId - Receipt id. + * @returns {Promise} + */ + public async getMailTemplateAttributes( + tenantId: number, + receiptId: number + ): Promise { + const receipt = await this.getReceiptService.getSaleReceipt( + tenantId, + receiptId + ); + const brandingTemplate = await this.getBrandingTemplate.getPdfTemplate( + tenantId, + receipt.pdfTemplateId + ); + const mailTemplateAttributes = await this.transformer.transform( + tenantId, + receipt, + new GetSaleReceiptMailTemplateAttributesTransformer(), + { + receipt, + brandingTemplate, + } + ); + return mailTemplateAttributes; + } + + /** + * Retrieves the mail template html content. + * @param {number} tenantId + * @param {number} estimateId + * @param overrideAttributes + * @returns + */ + public async getMailTemplate( + tenantId: number, + estimateId: number, + overrideAttributes?: Partial + ): Promise { + const attributes = await this.getMailTemplateAttributes( + tenantId, + estimateId + ); + const mergedAttributes = { + ...attributes, + ...overrideAttributes, + }; + return renderReceiptEmailTemplate(mergedAttributes); + } +} diff --git a/packages/server/src/services/Sales/Receipts/GetSaleReceiptMailTemplateAttributesTransformer.ts b/packages/server/src/services/Sales/Receipts/GetSaleReceiptMailTemplateAttributesTransformer.ts new file mode 100644 index 000000000..1c2ed9e6f --- /dev/null +++ b/packages/server/src/services/Sales/Receipts/GetSaleReceiptMailTemplateAttributesTransformer.ts @@ -0,0 +1,3 @@ +import { Transformer } from '@/lib/Transformer/Transformer'; + +export class GetSaleReceiptMailTemplateAttributesTransformer extends Transformer {} diff --git a/packages/server/src/services/Sales/Receipts/SaleReceiptMailNotification.ts b/packages/server/src/services/Sales/Receipts/SaleReceiptMailNotification.ts index 8fc1478d7..fa4a3f55b 100644 --- a/packages/server/src/services/Sales/Receipts/SaleReceiptMailNotification.ts +++ b/packages/server/src/services/Sales/Receipts/SaleReceiptMailNotification.ts @@ -17,6 +17,7 @@ import { mergeAndValidateMailOptions } from '@/services/MailNotification/utils'; import { EventPublisher } from '@/lib/EventPublisher/EventPublisher'; import events from '@/subscribers/events'; import { transformReceiptToMailDataArgs } from './utils'; +import { GetSaleReceiptMailTemplate } from './GetSaleReceiptMailTemplate'; @Service() export class SaleReceiptMailNotification { @@ -32,6 +33,9 @@ export class SaleReceiptMailNotification { @Inject() private contactMailNotification: ContactMailNotification; + @Inject() + private getReceiptMailTemplate: GetSaleReceiptMailTemplate; + @Inject() private eventPublisher: EventPublisher; @@ -133,7 +137,15 @@ export class SaleReceiptMailNotification { mailOptions, formatterArgs )) as SaleReceiptMailOpts; - return formattedOptions; + + const message = await this.getReceiptMailTemplate.getMailTemplate( + tenantId, + receiptId, + { + message: formattedOptions.message, + } + ); + return { ...formattedOptions, message }; } /** diff --git a/packages/webapp/src/containers/Sales/Estimates/EstimateSendMailDrawer/EstimateSendMailForm.tsx b/packages/webapp/src/containers/Sales/Estimates/EstimateSendMailDrawer/EstimateSendMailForm.tsx index 65b5f2fc9..b7ee0f592 100644 --- a/packages/webapp/src/containers/Sales/Estimates/EstimateSendMailDrawer/EstimateSendMailForm.tsx +++ b/packages/webapp/src/containers/Sales/Estimates/EstimateSendMailDrawer/EstimateSendMailForm.tsx @@ -40,7 +40,7 @@ export function EstimateSendMailForm({ children }: EstimateSendMailFormProps) { { setSubmitting }: FormikHelpers, ) => { setSubmitting(true); - sendEstimateMail({ id: estimateId, values: { ...values } }) + sendEstimateMail([estimateId, values]) .then(() => { AppToaster.show({ message: 'The invoice mail has been sent to the customer.', diff --git a/packages/webapp/src/containers/Sales/PaymentsReceived/PaymentReceivedMailDrawer/PaymentReceivedMailForm.tsx b/packages/webapp/src/containers/Sales/PaymentsReceived/PaymentReceivedMailDrawer/PaymentReceivedMailForm.tsx index a9ea4b330..02f6932ec 100644 --- a/packages/webapp/src/containers/Sales/PaymentsReceived/PaymentReceivedMailDrawer/PaymentReceivedMailForm.tsx +++ b/packages/webapp/src/containers/Sales/PaymentsReceived/PaymentReceivedMailDrawer/PaymentReceivedMailForm.tsx @@ -3,7 +3,7 @@ import { css } from '@emotion/css'; import { Intent } from '@blueprintjs/core'; import { PaymentReceivedSendMailFormSchema } from './_types'; import { AppToaster } from '@/components'; -import { useSendSaleInvoiceMail } from '@/hooks/query'; +import { useSendPaymentReceiveMail, } from '@/hooks/query'; import { usePaymentReceivedSendMailBoot } from './PaymentReceivedMailBoot'; import { useDrawerActions } from '@/hooks/state'; import { useDrawerContext } from '@/components/Drawer/DrawerProvider'; @@ -27,7 +27,7 @@ interface PaymentReceivedSendMailFormProps { export function PaymentReceivedSendMailForm({ children, }: PaymentReceivedSendMailFormProps) { - const { mutateAsync: sendInvoiceMail } = useSendSaleInvoiceMail(); + const { mutateAsync: sendPaymentMail } = useSendPaymentReceiveMail(); const { paymentReceivedId, paymentReceivedMailState } = usePaymentReceivedSendMailBoot(); @@ -43,7 +43,7 @@ export function PaymentReceivedSendMailForm({ { setSubmitting }: FormikHelpers, ) => { setSubmitting(true); - sendInvoiceMail({ id: paymentReceivedId, values: { ...values } }) + sendPaymentMail([paymentReceivedId, values]) .then(() => { AppToaster.show({ message: 'The invoice mail has been sent to the customer.', diff --git a/packages/webapp/src/containers/Sales/Receipts/ReceiptSendMailDrawer/ReceiptSendMailForm.tsx b/packages/webapp/src/containers/Sales/Receipts/ReceiptSendMailDrawer/ReceiptSendMailForm.tsx index f2935f542..65d2ee9e8 100644 --- a/packages/webapp/src/containers/Sales/Receipts/ReceiptSendMailDrawer/ReceiptSendMailForm.tsx +++ b/packages/webapp/src/containers/Sales/Receipts/ReceiptSendMailDrawer/ReceiptSendMailForm.tsx @@ -40,7 +40,7 @@ export function ReceiptSendMailForm({ children }: ReceiptSendMailFormProps) { { setSubmitting }: FormikHelpers, ) => { setSubmitting(true); - sendReceiptMail({ id: receiptId, values: { ...values } }) + sendReceiptMail([receiptId, values]) .then(() => { AppToaster.show({ message: 'The receipt mail has been sent to the customer.', diff --git a/packages/webapp/src/hooks/query/paymentReceives.tsx b/packages/webapp/src/hooks/query/paymentReceives.tsx index 017239f18..7000d4d3a 100644 --- a/packages/webapp/src/hooks/query/paymentReceives.tsx +++ b/packages/webapp/src/hooks/query/paymentReceives.tsx @@ -244,7 +244,7 @@ export function usePdfPaymentReceive(paymentReceiveId) { return useRequestPdf({ url: `sales/payment_receives/${paymentReceiveId}` }); } -export function useSendPaymentReceiveMail(props) { +export function useSendPaymentReceiveMail(props?: any) { const queryClient = useQueryClient(); const apiRequest = useApiRequest(); diff --git a/shared/email-components/src/lib/main.ts b/shared/email-components/src/lib/main.ts index aac012e31..8e2d68a7a 100644 --- a/shared/email-components/src/lib/main.ts +++ b/shared/email-components/src/lib/main.ts @@ -1 +1,5 @@ export * from './InvoicePaymentEmail'; +export * from './EstimatePaymentEmail'; +export * from './ReceiptPaymentEmail'; +export * from './CreditNoteEmailTemplate'; +export * from './PaymentReceivedEmailTemplate';