From c3dc26a1e4a3637583baa0001e042abde5e04952 Mon Sep 17 00:00:00 2001 From: Ahmed Bouhuolia Date: Fri, 5 Dec 2025 00:07:26 +0200 Subject: [PATCH] fix: sending mail jobs --- ...ymentReceivedMailNotification.processor.ts | 11 +++--- .../SaleEstimates/SaleEstimates.module.ts | 2 ++ .../commands/SendSaleEstimateMail.ts | 13 ++++++- .../processes/SendSaleEstimateMail.process.ts | 30 +++++++++++++--- .../SaleInvoices/SaleInvoices.controller.ts | 3 +- .../commands/SendSaleInvoiceMail.ts | 10 ++++-- .../SendSaleInvoiceMail.processor.ts | 6 ++-- .../SaleReceipts/SaleReceipts.controller.ts | 14 +++++--- .../processes/SendSaleReceiptMail.process.ts | 34 ++++++++++++++----- .../SendInviteUserMail.processor.ts | 6 ++-- .../server/test/sale-invoices.e2e-spec.ts | 2 +- 11 files changed, 100 insertions(+), 31 deletions(-) diff --git a/packages/server/src/modules/PaymentReceived/processors/PaymentReceivedMailNotification.processor.ts b/packages/server/src/modules/PaymentReceived/processors/PaymentReceivedMailNotification.processor.ts index 5ca792e6a..3337529a3 100644 --- a/packages/server/src/modules/PaymentReceived/processors/PaymentReceivedMailNotification.processor.ts +++ b/packages/server/src/modules/PaymentReceived/processors/PaymentReceivedMailNotification.processor.ts @@ -1,12 +1,11 @@ import { JOB_REF, Process, Processor } from '@nestjs/bull'; import { Job } from 'bull'; +import { Inject, Scope } from '@nestjs/common'; +import { ClsService, UseCls } from 'nestjs-cls'; import { SEND_PAYMENT_RECEIVED_MAIL_JOB, SEND_PAYMENT_RECEIVED_MAIL_QUEUE, } from '../constants'; -import { Inject, Scope } from '@nestjs/common'; -import { REQUEST } from '@nestjs/core'; -import { ClsService } from 'nestjs-cls'; import { SendPaymentReceiveMailNotification } from '../commands/PaymentReceivedMailNotification'; import { SendPaymentReceivedMailPayload } from '../types/PaymentReceived.types'; @@ -21,9 +20,10 @@ export class SendPaymentReceivedMailProcessor { @Inject(JOB_REF) private readonly jobRef: Job, - ) {} + ) { } @Process(SEND_PAYMENT_RECEIVED_MAIL_JOB) + @UseCls() async handleSendMail() { const { messageOptions, paymentReceivedId, organizationId, userId } = this.jobRef.data; @@ -37,7 +37,8 @@ export class SendPaymentReceivedMailProcessor { messageOptions, ); } catch (error) { - console.log(error); + console.error('Failed to process payment received mail job:', error); + throw error; } } } diff --git a/packages/server/src/modules/SaleEstimates/SaleEstimates.module.ts b/packages/server/src/modules/SaleEstimates/SaleEstimates.module.ts index a19ea923e..0ed7b4c23 100644 --- a/packages/server/src/modules/SaleEstimates/SaleEstimates.module.ts +++ b/packages/server/src/modules/SaleEstimates/SaleEstimates.module.ts @@ -42,6 +42,7 @@ import { GetSaleEstimateMailTemplateService } from './queries/GetSaleEstimateMai import { SaleEstimateAutoIncrementSubscriber } from './subscribers/SaleEstimateAutoIncrementSubscriber'; import { BulkDeleteSaleEstimatesService } from './BulkDeleteSaleEstimates.service'; import { ValidateBulkDeleteSaleEstimatesService } from './ValidateBulkDeleteSaleEstimates.service'; +import { SendSaleEstimateMailProcess } from './processes/SendSaleEstimateMail.process'; @Module({ imports: [ @@ -89,6 +90,7 @@ import { ValidateBulkDeleteSaleEstimatesService } from './ValidateBulkDeleteSale SaleEstimateAutoIncrementSubscriber, BulkDeleteSaleEstimatesService, ValidateBulkDeleteSaleEstimatesService, + SendSaleEstimateMailProcess, ], exports: [ SaleEstimatesExportable, diff --git a/packages/server/src/modules/SaleEstimates/commands/SendSaleEstimateMail.ts b/packages/server/src/modules/SaleEstimates/commands/SendSaleEstimateMail.ts index 9e362f806..cc647430a 100644 --- a/packages/server/src/modules/SaleEstimates/commands/SendSaleEstimateMail.ts +++ b/packages/server/src/modules/SaleEstimates/commands/SendSaleEstimateMail.ts @@ -24,6 +24,7 @@ import { Mail } from '@/modules/Mail/Mail'; import { MailTransporter } from '@/modules/Mail/MailTransporter.service'; import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel'; import { GetSaleEstimateMailTemplateService } from '../queries/GetSaleEstimateMailTemplate.service'; +import { TenancyContext } from '@/modules/Tenancy/TenancyContext.service'; @Injectable() export class SendSaleEstimateMail { @@ -42,13 +43,14 @@ export class SendSaleEstimateMail { private readonly getEstimateMailTemplate: GetSaleEstimateMailTemplateService, private readonly eventPublisher: EventEmitter2, private readonly mailTransporter: MailTransporter, + private readonly tenancyContext: TenancyContext, @Inject(SaleEstimate.name) private readonly saleEstimateModel: TenantModelProxy, @InjectQueue(SendSaleEstimateMailQueue) private readonly sendEstimateMailQueue: Queue, - ) {} + ) { } /** * Triggers the reminder mail of the given sale estimate. @@ -60,10 +62,19 @@ export class SendSaleEstimateMail { saleEstimateId: number, messageOptions: SaleEstimateMailOptionsDTO, ): Promise { + const tenant = await this.tenancyContext.getTenant(); + const user = await this.tenancyContext.getSystemUser(); + + const organizationId = tenant.organizationId; + const userId = user.id; + const payload = { saleEstimateId, messageOptions, + userId, + organizationId, }; + await this.sendEstimateMailQueue.add(SendSaleEstimateMailJob, payload); // Triggers `onSaleEstimatePreMailSend` event. diff --git a/packages/server/src/modules/SaleEstimates/processes/SendSaleEstimateMail.process.ts b/packages/server/src/modules/SaleEstimates/processes/SendSaleEstimateMail.process.ts index 76c235b2c..6690c4b37 100644 --- a/packages/server/src/modules/SaleEstimates/processes/SendSaleEstimateMail.process.ts +++ b/packages/server/src/modules/SaleEstimates/processes/SendSaleEstimateMail.process.ts @@ -1,19 +1,39 @@ import { Process, Processor } from '@nestjs/bull'; import { Job } from 'bull'; +import { Inject, Scope } from '@nestjs/common'; +import { JOB_REF } from '@nestjs/bull'; import { SendSaleEstimateMailJob, SendSaleEstimateMailQueue, } from '../types/SaleEstimates.types'; import { SendSaleEstimateMail } from '../commands/SendSaleEstimateMail'; +import { ClsService, UseCls } from 'nestjs-cls'; -@Processor(SendSaleEstimateMailQueue) +@Processor({ + name: SendSaleEstimateMailQueue, + scope: Scope.REQUEST, +}) export class SendSaleEstimateMailProcess { - constructor(private readonly sendEstimateMailService: SendSaleEstimateMail) {} + constructor( + private readonly sendEstimateMailService: SendSaleEstimateMail, + private readonly clsService: ClsService, + @Inject(JOB_REF) + private readonly jobRef: Job, + ) { } @Process(SendSaleEstimateMailJob) - async handleSendMail(job: Job) { - const { saleEstimateId, messageOptions } = job.data; + @UseCls() + async handleSendMail() { + const { saleEstimateId, messageOptions, organizationId, userId } = this.jobRef.data; - await this.sendEstimateMailService.sendMail(saleEstimateId, messageOptions); + this.clsService.set('organizationId', organizationId); + this.clsService.set('userId', userId); + + try { + await this.sendEstimateMailService.sendMail(saleEstimateId, messageOptions); + } catch (error) { + console.error('Failed to process estimate mail job:', error); + throw error; + } } } diff --git a/packages/server/src/modules/SaleInvoices/SaleInvoices.controller.ts b/packages/server/src/modules/SaleInvoices/SaleInvoices.controller.ts index d206313a2..9d870758e 100644 --- a/packages/server/src/modules/SaleInvoices/SaleInvoices.controller.ts +++ b/packages/server/src/modules/SaleInvoices/SaleInvoices.controller.ts @@ -99,7 +99,8 @@ export class SaleInvoicesController { return this.saleInvoiceApplication.createSaleInvoice(saleInvoiceDTO); } - @Put(':id/mail') + @Post(':id/mail') + @HttpCode(200) @ApiOperation({ summary: 'Send the sale invoice mail.' }) @ApiResponse({ status: 200, diff --git a/packages/server/src/modules/SaleInvoices/commands/SendSaleInvoiceMail.ts b/packages/server/src/modules/SaleInvoices/commands/SendSaleInvoiceMail.ts index b5fee249b..1323a9bcf 100644 --- a/packages/server/src/modules/SaleInvoices/commands/SendSaleInvoiceMail.ts +++ b/packages/server/src/modules/SaleInvoices/commands/SendSaleInvoiceMail.ts @@ -33,7 +33,7 @@ export class SendSaleInvoiceMail { private readonly tenancyContect: TenancyContext, @InjectQueue(SendSaleInvoiceQueue) private readonly sendInvoiceQueue: Queue, - ) {} + ) { } /** * Sends the invoice mail of the given sale invoice. @@ -132,7 +132,13 @@ export class SendSaleInvoiceMail { events.saleInvoice.onMailSend, eventPayload, ); - await this.mailTransporter.send(mail); + + try { + await this.mailTransporter.send(mail); + } catch (error) { + console.error('Failed to send invoice mail:', error); + throw error; + } // Triggers the event `onSaleInvoiceSend`. await this.eventEmitter.emitAsync( diff --git a/packages/server/src/modules/SaleInvoices/processors/SendSaleInvoiceMail.processor.ts b/packages/server/src/modules/SaleInvoices/processors/SendSaleInvoiceMail.processor.ts index 69e366b6b..ed5149b01 100644 --- a/packages/server/src/modules/SaleInvoices/processors/SendSaleInvoiceMail.processor.ts +++ b/packages/server/src/modules/SaleInvoices/processors/SendSaleInvoiceMail.processor.ts @@ -18,9 +18,10 @@ export class SendSaleInvoiceMailProcessor { @Inject(JOB_REF) private readonly jobRef: Job, private readonly clsService: ClsService, - ) {} + ) { } @Process(SendSaleInvoiceMailJob) + @UseCls() async handleSendInvoice() { const { messageOptions, saleInvoiceId, organizationId, userId } = this.jobRef.data; @@ -31,7 +32,8 @@ export class SendSaleInvoiceMailProcessor { try { await this.sendSaleInvoiceMail.sendMail(saleInvoiceId, messageOptions); } catch (error) { - console.log(error); + console.error('Failed to process invoice mail job:', error); + throw error; } } } diff --git a/packages/server/src/modules/SaleReceipts/SaleReceipts.controller.ts b/packages/server/src/modules/SaleReceipts/SaleReceipts.controller.ts index 35b9495d0..7b73f6d76 100644 --- a/packages/server/src/modules/SaleReceipts/SaleReceipts.controller.ts +++ b/packages/server/src/modules/SaleReceipts/SaleReceipts.controller.ts @@ -25,7 +25,10 @@ import { CreateSaleReceiptDto, EditSaleReceiptDto, } from './dtos/SaleReceipt.dto'; -import { ISalesReceiptsFilter } from './types/SaleReceipts.types'; +import { + ISalesReceiptsFilter, + SaleReceiptMailOptsDTO, +} from './types/SaleReceipts.types'; import { AcceptType } from '@/constants/accept-type'; import { Response } from 'express'; import { SaleReceiptResponseDto } from './dtos/SaleReceiptResponse.dto'; @@ -87,7 +90,7 @@ export class SaleReceiptsController { return this.saleReceiptApplication.createSaleReceipt(saleReceiptDTO); } - @Put(':id/mail') + @Post(':id/mail') @HttpCode(200) @ApiOperation({ summary: 'Send the sale receipt mail.' }) @ApiParam({ @@ -96,8 +99,11 @@ export class SaleReceiptsController { type: Number, description: 'The sale receipt id', }) - sendSaleReceiptMail(@Param('id', ParseIntPipe) id: number) { - return this.saleReceiptApplication.getSaleReceiptMail(id); + sendSaleReceiptMail( + @Param('id', ParseIntPipe) id: number, + @Body() messageOpts: SaleReceiptMailOptsDTO, + ) { + return this.saleReceiptApplication.sendSaleReceiptMail(id, messageOpts); } @Get('state') diff --git a/packages/server/src/modules/SaleReceipts/processes/SendSaleReceiptMail.process.ts b/packages/server/src/modules/SaleReceipts/processes/SendSaleReceiptMail.process.ts index 4bd8accdc..96af47bd9 100644 --- a/packages/server/src/modules/SaleReceipts/processes/SendSaleReceiptMail.process.ts +++ b/packages/server/src/modules/SaleReceipts/processes/SendSaleReceiptMail.process.ts @@ -1,24 +1,42 @@ import { Process, Processor } from '@nestjs/bull'; import { Job } from 'bull'; -import { SendSaleReceiptMailQueue } from '../constants'; +import { Inject, Scope } from '@nestjs/common'; +import { JOB_REF } from '@nestjs/bull'; +import { SendSaleReceiptMailQueue, SendSaleReceiptMailJob } from '../constants'; import { SaleReceiptMailNotification } from '../commands/SaleReceiptMailNotification'; import { SaleReceiptSendMailPayload } from '../types/SaleReceipts.types'; -import { ClsService } from 'nestjs-cls'; +import { ClsService, UseCls } from 'nestjs-cls'; -@Processor(SendSaleReceiptMailQueue) +@Processor({ + name: SendSaleReceiptMailQueue, + scope: Scope.REQUEST, +}) export class SendSaleReceiptMailProcess { constructor( private readonly saleReceiptMailNotification: SaleReceiptMailNotification, private readonly clsService: ClsService, - ) {} - @Process(SendSaleReceiptMailQueue) - async handleSendMailJob(job: Job) { - const { messageOpts, saleReceiptId, organizationId, userId } = job.data; + @Inject(JOB_REF) + private readonly jobRef: Job, + ) { } + + @Process(SendSaleReceiptMailJob) + @UseCls() + async handleSendMailJob() { + const { messageOpts, saleReceiptId, organizationId, userId } = + this.jobRef.data; this.clsService.set('organizationId', organizationId); this.clsService.set('userId', userId); - await this.saleReceiptMailNotification.sendMail(saleReceiptId, messageOpts); + try { + await this.saleReceiptMailNotification.sendMail( + saleReceiptId, + messageOpts, + ); + } catch (error) { + console.error('Failed to process receipt mail job:', error); + throw error; + } } } diff --git a/packages/server/src/modules/UsersModule/processors/SendInviteUserMail.processor.ts b/packages/server/src/modules/UsersModule/processors/SendInviteUserMail.processor.ts index 57453ffda..6677beaf9 100644 --- a/packages/server/src/modules/UsersModule/processors/SendInviteUserMail.processor.ts +++ b/packages/server/src/modules/UsersModule/processors/SendInviteUserMail.processor.ts @@ -21,9 +21,10 @@ export class SendInviteUserMailProcessor { @Inject(JOB_REF) private readonly jobRef: Job, private readonly clsService: ClsService, - ) {} + ) { } @Process(SendInviteUserMailJob) + @UseCls() async handleSendInviteMail() { const { fromUser, invite, organizationId, userId } = this.jobRef.data; @@ -33,7 +34,8 @@ export class SendInviteUserMailProcessor { try { await this.sendInviteUsersMailService.sendInviteMail(fromUser, invite); } catch (error) { - console.log(error); + console.error('Failed to process invite user mail job:', error); + throw error; } } } diff --git a/packages/server/test/sale-invoices.e2e-spec.ts b/packages/server/test/sale-invoices.e2e-spec.ts index 701478cdc..d37c0d510 100644 --- a/packages/server/test/sale-invoices.e2e-spec.ts +++ b/packages/server/test/sale-invoices.e2e-spec.ts @@ -229,7 +229,7 @@ describe('Sale Invoices (e2e)', () => { .send(requestSaleInvoiceBody()); return request(app.getHttpServer()) - .put(`/sale-invoices/${response.body.id}/mail`) + .post(`/sale-invoices/${response.body.id}/mail`) .set('organization-id', orgainzationId) .set('Authorization', AuthorizationHeader) .send({