Skip to content

Commit 40f6c7e

Browse files
committed
feat: remove typing
feat: move common pdf processing functions to shared submissions.util feat: simplify getPdfResponsesData signatureDataPngUri passing feat: fix import ordering and unused feat: encapsulate mrf respondent copy email sending logic feat: move pdf generation to outer feat: pass pdf to mrf outcomes for sending feat: move admin email notif to post actions for encrypt feat: setup shared pdf generation feat: propagate isPaymentForm check up and only attach pdf if required fix: lint formatting feat: rename to submissionAttachment for clarity and move tcs to service fix: submission service tcs fix: encryption-submission.service.spec tests fix: mock generate pdf in mrf service spec fix: lint and fix tc fix: ts build errors and remove unused code fix: change to relative imports chore: update comment for bug fix: lint and fix sp tc chore: remove stray console logs fix: make responses data compatible with pdf chore: move function to mrf utils fix: lint issues chore: restore past naming feat: move pdf render data copy to common function fix: duplicate pdf due to mutation fix: duplicate pdf due to mutation fix: include fieldtype to remove answer for non signature for mrf fix: tc for field type fix: encapsulate pdf render data generation feat: add tc for generating pdf render data for signature and non signature fields feat: add tc for mail service feat: add payment enabled check feat: add tc for encrypt mode sending confirmation and pdf gen fix: missing fieldtype feat: add tc for new extractRespondentCopyEmailDatas function feat: add tc for workflow outcome pdf generation feat: add tc for respondent copy
1 parent a19dbd9 commit 40f6c7e

18 files changed

+2832
-851
lines changed

src/app/modules/payments/payments.service.ts

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { GrowthBook } from '@growthbook/growthbook'
21
import { isEqual, omit } from 'lodash'
32
import moment from 'moment-timezone'
43
import mongoose, { Types } from 'mongoose'
@@ -209,7 +208,6 @@ export const confirmPaymentPendingSubmission = (
209208
*/
210209
export const performPaymentPostSubmissionActions = (
211210
paymentId: IPaymentSchema['_id'],
212-
growthbook: GrowthBook | undefined,
213211
): ResultAsync<
214212
void,
215213
| PaymentNotFoundError
@@ -244,7 +242,7 @@ export const performPaymentPostSubmissionActions = (
244242
performEncryptPostSubmissionActions({
245243
submission,
246244
responses: payment.responses,
247-
growthbook,
245+
emailFields: [], // TODO [EMAIL-CONFIRMATION-BUG]: Email confirmation email to email fields does not work for payment forms, this is an existing issue to be fixed.
248246
})
249247
.andThen(() =>
250248
// If successfully sent email confirmations, delete response data from payment document.

src/app/modules/payments/stripe.controller.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -304,10 +304,7 @@ export const reconcileAccount: ControllerHandler<
304304
meta: { ...logMeta, event },
305305
})
306306

307-
await StripeService.handleStripeEvent(
308-
event as Stripe.DiscriminatedEvent,
309-
req.growthbook,
310-
)
307+
await StripeService.handleStripeEvent(event as Stripe.DiscriminatedEvent)
311308
.andThen(() => {
312309
logger.warn({
313310
message:

src/app/modules/payments/stripe.events.controller.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ const _handleStripeEventUpdates: ControllerHandler<
8989

9090
// Step 3: Process the event
9191
return (
92-
StripeService.handleStripeEvent(event, req.growthbook)
92+
StripeService.handleStripeEvent(event)
9393
// Step 4: Return response to Stripe based on result
9494
.match(
9595
() => res.sendStatus(StatusCodes.OK),

src/app/modules/payments/stripe.service.ts

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
// Use 'stripe-event-types' for better type discrimination.
22
/// <reference types="stripe-event-types" />
3-
import { GrowthBook } from '@growthbook/growthbook'
43
import cuid from 'cuid'
54
import mongoose from 'mongoose'
65
import { errAsync, ok, okAsync, ResultAsync } from 'neverthrow'
@@ -451,7 +450,6 @@ type HandleStripeEventResultError =
451450
*/
452451
export const handleStripeEvent = (
453452
event: Stripe.DiscriminatedEvent,
454-
growthbook: GrowthBook | undefined,
455453
): ResultAsync<void, HandleStripeEventResultError> => {
456454
const logMeta = {
457455
action: 'handleStripeEvent',
@@ -498,7 +496,6 @@ export const handleStripeEvent = (
498496

499497
return PaymentsService.performPaymentPostSubmissionActions(
500498
paymentId,
501-
growthbook,
502499
)
503500
.andThen(() => okAsync(undefined))
504501
.orElse((e) => {

src/app/modules/submission/__tests__/submission.service.spec.ts

Lines changed: 139 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ const MOCK_AUTOREPLY_DATA = [
9292
question: 'Email',
9393
answerTemplate: ['[email protected]'],
9494
fieldType: BasicField.Email,
95+
fieldType: BasicField.Email,
9596
},
9697
]
9798
const AUTOREPLY_OPTIONS_1: AutoReplyOptions = {
@@ -455,7 +456,9 @@ describe('submission.service', () => {
455456
form: mockForm,
456457
recipientData,
457458
submission: MOCK_SUBMISSION,
458-
attachments: MOCK_ATTACHMENTS,
459+
submissionAttachments: MOCK_ATTACHMENTS,
460+
pdfAttachment: undefined,
461+
isPaymentEnabled: false,
459462
responsesData: MOCK_AUTOREPLY_DATA,
460463
isUseLambdaOutput: false,
461464
})
@@ -468,7 +471,9 @@ describe('submission.service', () => {
468471
expect(MockMailService.sendAutoReplyEmails).toHaveBeenCalledWith({
469472
form: mockForm,
470473
submission: MOCK_SUBMISSION,
471-
attachments: MOCK_ATTACHMENTS,
474+
submissionAttachments: MOCK_ATTACHMENTS,
475+
pdfAttachment: undefined,
476+
isPaymentEnabled: false,
472477
responsesData: MOCK_AUTOREPLY_DATA,
473478
autoReplyMailDatas: expectedAutoReplyData,
474479
})
@@ -497,7 +502,9 @@ describe('submission.service', () => {
497502
form: mockForm,
498503
recipientData,
499504
submission: MOCK_SUBMISSION,
500-
attachments: MOCK_ATTACHMENTS,
505+
submissionAttachments: MOCK_ATTACHMENTS,
506+
pdfAttachment: undefined,
507+
isPaymentEnabled: false,
501508
responsesData: MOCK_AUTOREPLY_DATA,
502509
isUseLambdaOutput: false,
503510
})
@@ -543,7 +550,9 @@ describe('submission.service', () => {
543550
form: mockForm,
544551
recipientData,
545552
submission: MOCK_SUBMISSION,
546-
attachments: MOCK_ATTACHMENTS,
553+
submissionAttachments: MOCK_ATTACHMENTS,
554+
pdfAttachment: undefined,
555+
isPaymentEnabled: false,
547556
responsesData: MOCK_AUTOREPLY_DATA,
548557
isUseLambdaOutput: false,
549558
})
@@ -595,7 +604,9 @@ describe('submission.service', () => {
595604
form: mockForm,
596605
recipientData,
597606
submission: MOCK_SUBMISSION,
598-
attachments: MOCK_ATTACHMENTS,
607+
submissionAttachments: MOCK_ATTACHMENTS,
608+
pdfAttachment: undefined,
609+
isPaymentEnabled: false,
599610
responsesData: MOCK_AUTOREPLY_DATA,
600611
isUseLambdaOutput: false,
601612
})
@@ -605,7 +616,9 @@ describe('submission.service', () => {
605616
expect(MockMailService.sendAutoReplyEmails).toHaveBeenCalledWith({
606617
form: mockForm,
607618
submission: MOCK_SUBMISSION,
608-
attachments: MOCK_ATTACHMENTS,
619+
submissionAttachments: MOCK_ATTACHMENTS,
620+
pdfAttachment: undefined,
621+
isPaymentEnabled: false,
609622
responsesData: MOCK_AUTOREPLY_DATA,
610623
autoReplyMailDatas: expectedAutoReplyData,
611624
})
@@ -659,9 +672,10 @@ describe('submission.service', () => {
659672
form: mockForm,
660673
recipientData,
661674
submission: MOCK_SUBMISSION,
662-
attachments: MOCK_ATTACHMENTS,
663-
responsesData: undefined,
664-
isUseLambdaOutput: false,
675+
submissionAttachments: MOCK_ATTACHMENTS,
676+
pdfAttachment: undefined,
677+
isPaymentEnabled: false,
678+
responsesData: [],
665679
})
666680

667681
const expectedAutoReplyData = [
@@ -672,14 +686,16 @@ describe('submission.service', () => {
672686
expect(MockMailService.sendAutoReplyEmails).toHaveBeenCalledWith({
673687
form: mockForm,
674688
submission: MOCK_SUBMISSION,
675-
attachments: MOCK_ATTACHMENTS,
689+
submissionAttachments: MOCK_ATTACHMENTS,
676690
responsesData: [],
677691
autoReplyMailDatas: expectedAutoReplyData,
692+
pdfAttachment: undefined,
693+
isPaymentEnabled: false,
678694
})
679695
expect(result._unsafeUnwrap()).toBe(true)
680696
})
681697

682-
it('should call mail service with attachments undefined when there are no attachments', async () => {
698+
it('should call mail service with pdfAttachment when a pdfAttachment is provided', async () => {
683699
const mockForm = {
684700
_id: MOCK_FORM_ID,
685701
form_fields: [
@@ -722,13 +738,19 @@ describe('submission.service', () => {
722738
responses,
723739
mockForm.form_fields,
724740
)
741+
742+
const MOCK_PDF_ATTACHMENT = {
743+
content: Buffer.from('mock pdf buffer'),
744+
filename: 'response.pdf',
745+
}
725746
const result = await SubmissionService.sendEmailConfirmations({
726747
form: mockForm,
727748
recipientData,
728749
submission: MOCK_SUBMISSION,
729-
attachments: undefined,
750+
submissionAttachments: undefined,
730751
responsesData: MOCK_AUTOREPLY_DATA,
731-
isUseLambdaOutput: false,
752+
isPaymentEnabled: false,
753+
pdfAttachment: MOCK_PDF_ATTACHMENT,
732754
})
733755

734756
const expectedAutoReplyData = [
@@ -739,13 +761,93 @@ describe('submission.service', () => {
739761
expect(MockMailService.sendAutoReplyEmails).toHaveBeenCalledWith({
740762
form: mockForm,
741763
submission: MOCK_SUBMISSION,
742-
attachments: undefined,
764+
submissionAttachments: undefined,
765+
pdfAttachment: MOCK_PDF_ATTACHMENT,
766+
isPaymentEnabled: false,
743767
responsesData: MOCK_AUTOREPLY_DATA,
744768
autoReplyMailDatas: expectedAutoReplyData,
745769
})
746770
expect(result._unsafeUnwrap()).toBe(true)
747771
})
748772

773+
it('should call mail service with submissionAttachments undefined and pdfAttachment undefined when there are no submissionAttachments or pdfAttachment', async () => {
774+
const mockForm = {
775+
_id: MOCK_FORM_ID,
776+
form_fields: [
777+
{
778+
...generateDefaultField(BasicField.Email),
779+
autoReplyOptions: AUTOREPLY_OPTIONS_1,
780+
},
781+
{
782+
...generateDefaultField(BasicField.Email),
783+
autoReplyOptions: AUTOREPLY_OPTIONS_2,
784+
},
785+
],
786+
} as unknown as IPopulatedForm
787+
MockMailService.sendAutoReplyEmails.mockResolvedValueOnce([
788+
{
789+
status: 'fulfilled',
790+
value: ok(true),
791+
},
792+
{
793+
status: 'fulfilled',
794+
value: ok(true),
795+
},
796+
])
797+
798+
const responses = [
799+
{
800+
...generateNewSingleAnswerResponse(BasicField.Email, {
801+
_id: mockForm.form_fields![0]._id,
802+
answer: MOCK_EMAIL_1,
803+
}),
804+
},
805+
{
806+
...generateNewSingleAnswerResponse(BasicField.Email, {
807+
_id: mockForm.form_fields![1]._id,
808+
answer: MOCK_EMAIL_2,
809+
}),
810+
},
811+
]
812+
const recipientData = extractEmailConfirmationData(
813+
responses,
814+
mockForm.form_fields,
815+
)
816+
const result = await SubmissionService.sendEmailConfirmations({
817+
form: mockForm,
818+
recipientData,
819+
submission: MOCK_SUBMISSION,
820+
submissionAttachments: undefined,
821+
responsesData: MOCK_AUTOREPLY_DATA,
822+
isPaymentEnabled: false,
823+
pdfAttachment: undefined,
824+
})
825+
826+
const expectedAutoReplyData = [
827+
EXPECTED_AUTOREPLY_DATA_1,
828+
EXPECTED_AUTOREPLY_DATA_2,
829+
]
830+
831+
expect(MockMailService.sendAutoReplyEmails).toHaveBeenCalledWith({
832+
form: mockForm,
833+
submission: MOCK_SUBMISSION,
834+
submissionAttachments: undefined,
835+
pdfAttachment: undefined,
836+
isPaymentEnabled: false,
837+
responsesData: MOCK_AUTOREPLY_DATA,
838+
autoReplyMailDatas: expectedAutoReplyData,
839+
})
840+
expect(result._unsafeUnwrap()).toBe(true)
841+
})
842+
843+
it('should generate pdfAttachment when form summary for respondent is enabled', async () => {})
844+
845+
it('should not generate pdfAttachment for payment form', () => {})
846+
847+
it('should generate pdfAttachment for admin email notification', () => {})
848+
849+
it('should return pdf generation error when pdf generation fails', () => {})
850+
749851
it('should return SendEmailConfirmationError when mail service errors', async () => {
750852
const mockForm = {
751853
_id: MOCK_FORM_ID,
@@ -786,9 +888,10 @@ describe('submission.service', () => {
786888
form: mockForm,
787889
recipientData,
788890
submission: MOCK_SUBMISSION,
789-
attachments: MOCK_ATTACHMENTS,
891+
submissionAttachments: MOCK_ATTACHMENTS,
790892
responsesData: MOCK_AUTOREPLY_DATA,
791-
isUseLambdaOutput: false,
893+
isPaymentEnabled: false,
894+
pdfAttachment: undefined,
792895
})
793896

794897
const expectedAutoReplyData = [
@@ -799,7 +902,9 @@ describe('submission.service', () => {
799902
expect(MockMailService.sendAutoReplyEmails).toHaveBeenCalledWith({
800903
form: mockForm,
801904
submission: MOCK_SUBMISSION,
802-
attachments: MOCK_ATTACHMENTS,
905+
submissionAttachments: MOCK_ATTACHMENTS,
906+
pdfAttachment: undefined,
907+
isPaymentEnabled: false,
803908
responsesData: MOCK_AUTOREPLY_DATA,
804909
autoReplyMailDatas: expectedAutoReplyData,
805910
})
@@ -856,9 +961,10 @@ describe('submission.service', () => {
856961
form: mockForm,
857962
recipientData,
858963
submission: MOCK_SUBMISSION,
859-
attachments: MOCK_ATTACHMENTS,
964+
submissionAttachments: MOCK_ATTACHMENTS,
860965
responsesData: MOCK_AUTOREPLY_DATA,
861-
isUseLambdaOutput: false,
966+
isPaymentEnabled: false,
967+
pdfAttachment: undefined,
862968
})
863969

864970
const expectedAutoReplyData = [
@@ -869,9 +975,11 @@ describe('submission.service', () => {
869975
expect(MockMailService.sendAutoReplyEmails).toHaveBeenCalledWith({
870976
form: mockForm,
871977
submission: MOCK_SUBMISSION,
872-
attachments: MOCK_ATTACHMENTS,
978+
submissionAttachments: MOCK_ATTACHMENTS,
873979
responsesData: MOCK_AUTOREPLY_DATA,
874980
autoReplyMailDatas: expectedAutoReplyData,
981+
pdfAttachment: undefined,
982+
isPaymentEnabled: false,
875983
})
876984
expect(result._unsafeUnwrapErr()).toEqual(
877985
new SendEmailConfirmationError(),
@@ -2755,7 +2863,7 @@ describe('submission.service', () => {
27552863

27562864
// Act
27572865
// empty string for version id to simulate failure
2758-
const actualResult = await downloadCleanFile('invalid-key', '')
2866+
const actualResult = await downloadCleanFile('invalid-key', '', 'mock-bucket-name')
27592867

27602868
// Assert
27612869
expect(awsSpy).not.toHaveBeenCalled()
@@ -2769,7 +2877,11 @@ describe('submission.service', () => {
27692877

27702878
// Act
27712879
// empty string for version id to simulate failure
2772-
const actualResult = await downloadCleanFile(MOCK_VALID_UUID, '')
2880+
const actualResult = await downloadCleanFile(
2881+
MOCK_VALID_UUID,
2882+
'',
2883+
'mock-bucket-name',
2884+
)
27732885

27742886
// Assert
27752887
expect(awsSpy).toHaveBeenCalledOnce()
@@ -2804,7 +2916,11 @@ describe('submission.service', () => {
28042916

28052917
// Act
28062918
// empty strings for invalid keys and version ids
2807-
const actualResult = await downloadCleanFile(MOCK_VALID_UUID, versionId)
2919+
const actualResult = await downloadCleanFile(
2920+
MOCK_VALID_UUID,
2921+
versionId,
2922+
'mock-bucket-name',
2923+
)
28082924

28092925
// Assert
28102926
expect(awsSpy).toHaveBeenCalledOnce()

0 commit comments

Comments
 (0)