From 0311fed96007d78d212233b46c84feea0c46ccde Mon Sep 17 00:00:00 2001 From: Yoganandan Pandiyan Date: Fri, 31 Oct 2025 13:27:55 +0100 Subject: [PATCH] fix: usaged of outdated invite object resulted in PI not being able to receive notification on invite accept --- .../email/essEmailHandler.spec.ts | 36 +++++++++++++++++++ .../eventHandlers/email/essEmailHandler.ts | 4 --- apps/backend/src/mutations/InviteMutations.ts | 9 +++-- 3 files changed, 40 insertions(+), 9 deletions(-) diff --git a/apps/backend/src/eventHandlers/email/essEmailHandler.spec.ts b/apps/backend/src/eventHandlers/email/essEmailHandler.spec.ts index 95dca29597..84d5df2edf 100644 --- a/apps/backend/src/eventHandlers/email/essEmailHandler.spec.ts +++ b/apps/backend/src/eventHandlers/email/essEmailHandler.spec.ts @@ -277,6 +277,42 @@ describe('essEmailHandler co-proposer invites', () => { ); }); + it('should send mail when co-proposer invite is accepted', async () => { + const mockInvite = new Invite( + 1, + faker.string.alphanumeric(8), + dummyUser.email, + new Date(), + dummyUser.id, + new Date(), + dummyUser.id, + false, + null, + EmailTemplateId.CO_PROPOSER_INVITE_ACCEPTED + ); + + // Mock userDataSource.getUser to return dummyUser for principal investigator but null for claimer + const getUserMock = jest.spyOn(userDataSourceMock, 'getUser'); + getUserMock + .mockResolvedValueOnce(dummyUser) // First call for principal investigator + .mockResolvedValueOnce(dummyUser); // Second call for claimer + + const event: ApplicationEvent = { + type: Event.PROPOSAL_CO_PROPOSER_INVITE_ACCEPTED, + invite: mockInvite, + key: 'invite', + loggedInUserId: 3, + isRejection: false, + proposalPKey: 1, + }; + + const sendMailsSpy = jest.spyOn(mockMailService, 'sendMail'); + + await essEmailHandler(event); + + expect(sendMailsSpy).toHaveBeenCalled(); + }); + describe('handling PROPOSAL_SUBMITTED event', () => { it('Should have PI and CoProposals in the payload', async () => { const event: ApplicationEvent = { diff --git a/apps/backend/src/eventHandlers/email/essEmailHandler.ts b/apps/backend/src/eventHandlers/email/essEmailHandler.ts index 9d1b64cdbe..addff8f45e 100644 --- a/apps/backend/src/eventHandlers/email/essEmailHandler.ts +++ b/apps/backend/src/eventHandlers/email/essEmailHandler.ts @@ -47,10 +47,6 @@ export async function essEmailHandler(event: ApplicationEvent) { Tokens.CoProposerClaimDataSource ); - const inviteDataSource = container.resolve( - Tokens.InviteDataSource - ); - const callDataSource = container.resolve( Tokens.CallDataSource ); diff --git a/apps/backend/src/mutations/InviteMutations.ts b/apps/backend/src/mutations/InviteMutations.ts index 65fb8385e2..8f0c63e061 100644 --- a/apps/backend/src/mutations/InviteMutations.ts +++ b/apps/backend/src/mutations/InviteMutations.ts @@ -69,16 +69,16 @@ export default class InviteMutations { return rejection('Invite code has expired', { invite: code }); } - await this.processAcceptedRoleClaims(agent!.id, invite); - await this.processAcceptedCoProposerClaims(agent!.id, invite); - await this.processAcceptedVisitRegistrationClaims(agent!.id, invite); - const updatedInvite = await this.inviteDataSource.update({ id: invite.id, claimedAt: new Date(), claimedByUserId: agent!.id, }); + await this.processAcceptedRoleClaims(agent!.id, updatedInvite); + await this.processAcceptedCoProposerClaims(agent!.id, updatedInvite); + await this.processAcceptedVisitRegistrationClaims(agent!.id, updatedInvite); + return updatedInvite; } @@ -282,7 +282,6 @@ export default class InviteMutations { if (proposalHasUser) { return; } - await this.proposalDataSource.addProposalUser( claim.proposalPk, claimerUserId