@stamhoofd/models 2.96.2 → 2.97.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/src/factories/BalanceItemFactory.d.ts +1 -0
- package/dist/src/factories/BalanceItemFactory.d.ts.map +1 -1
- package/dist/src/factories/BalanceItemFactory.js +2 -0
- package/dist/src/factories/BalanceItemFactory.js.map +1 -1
- package/dist/src/factories/UserFactory.d.ts +1 -1
- package/dist/src/factories/UserFactory.d.ts.map +1 -1
- package/dist/src/factories/UserFactory.js +4 -1
- package/dist/src/factories/UserFactory.js.map +1 -1
- package/dist/src/helpers/EmailBuilder.d.ts +5 -5
- package/dist/src/helpers/EmailBuilder.d.ts.map +1 -1
- package/dist/src/helpers/EmailBuilder.js +41 -16
- package/dist/src/helpers/EmailBuilder.js.map +1 -1
- package/dist/src/migrations/1756821154-email-send-as-email.sql +3 -0
- package/dist/src/models/Email.d.ts +14 -0
- package/dist/src/models/Email.d.ts.map +1 -1
- package/dist/src/models/Email.js +269 -196
- package/dist/src/models/Email.js.map +1 -1
- package/dist/src/models/Email.test.js +332 -46
- package/dist/src/models/Email.test.js.map +1 -1
- package/package.json +2 -2
- package/src/factories/BalanceItemFactory.ts +2 -0
- package/src/factories/UserFactory.ts +4 -1
- package/src/helpers/EmailBuilder.ts +52 -26
- package/src/migrations/1756821154-email-send-as-email.sql +3 -0
- package/src/models/Email.test.ts +401 -47
- package/src/models/Email.ts +277 -201
|
@@ -7,6 +7,9 @@ const email_1 = require("@stamhoofd/email");
|
|
|
7
7
|
const test_utils_1 = require("@stamhoofd/test-utils");
|
|
8
8
|
const OrganizationFactory_1 = require("../factories/OrganizationFactory");
|
|
9
9
|
const Platform_1 = require("./Platform");
|
|
10
|
+
const factories_1 = require("../factories");
|
|
11
|
+
const CachedBalance_1 = require("./CachedBalance");
|
|
12
|
+
const utility_1 = require("@stamhoofd/utility");
|
|
10
13
|
async function buildEmail(data) {
|
|
11
14
|
Email_1.Email.recipientLoaders.set(structures_1.EmailRecipientFilterType.Members, {
|
|
12
15
|
fetch: async (query) => {
|
|
@@ -31,13 +34,14 @@ async function buildEmail(data) {
|
|
|
31
34
|
],
|
|
32
35
|
});
|
|
33
36
|
model.subject = data.subject ?? 'This is a test email';
|
|
34
|
-
model.html = data.html ?? '<p>This is a test email</p>';
|
|
35
|
-
model.text = data.text ?? 'This is a test email';
|
|
37
|
+
model.html = data.html ?? '<p>This is a test email</p> {{unsubscribeUrl}}';
|
|
38
|
+
model.text = data.text ?? 'This is a test email {{unsubscribeUrl}}';
|
|
36
39
|
model.json = data.json ?? {};
|
|
37
40
|
model.status = data.status ?? structures_1.EmailStatus.Draft;
|
|
38
41
|
model.attachments = [];
|
|
39
42
|
model.fromAddress = data.fromAddress ?? 'test@stamhoofd.be';
|
|
40
43
|
model.fromName = data.fromName ?? null;
|
|
44
|
+
model.emailType = data.emailType ?? null;
|
|
41
45
|
await model.save();
|
|
42
46
|
return model;
|
|
43
47
|
}
|
|
@@ -65,13 +69,14 @@ async function buildFailEmail(data) {
|
|
|
65
69
|
],
|
|
66
70
|
});
|
|
67
71
|
model.subject = data.subject ?? 'This is a test email';
|
|
68
|
-
model.html = data.html ?? '<p>This is a test email</p>';
|
|
69
|
-
model.text = data.text ?? 'This is a test email';
|
|
72
|
+
model.html = data.html ?? '<p>This is a test email</p> {{unsubscribeUrl}}';
|
|
73
|
+
model.text = data.text ?? 'This is a test email {{unsubscribeUrl}}';
|
|
70
74
|
model.json = data.json ?? {};
|
|
71
75
|
model.status = data.status ?? structures_1.EmailStatus.Draft;
|
|
72
76
|
model.attachments = [];
|
|
73
77
|
model.fromAddress = data.fromAddress ?? 'test@stamhoofd.be';
|
|
74
78
|
model.fromName = data.fromName ?? null;
|
|
79
|
+
model.emailType = data.emailType ?? null;
|
|
75
80
|
await model.save();
|
|
76
81
|
return model;
|
|
77
82
|
}
|
|
@@ -102,8 +107,8 @@ describe('Model.Email', () => {
|
|
|
102
107
|
expect(model.emailErrors).toBe(null);
|
|
103
108
|
expect(model.recipientsErrors).toBe(null);
|
|
104
109
|
expect(model.status).toBe(structures_1.EmailStatus.Sent);
|
|
105
|
-
expect(await email_1.EmailMocker.
|
|
106
|
-
expect(await email_1.EmailMocker.
|
|
110
|
+
expect(await email_1.EmailMocker.getSucceededCount()).toBe(1);
|
|
111
|
+
expect(await email_1.EmailMocker.getFailedCount()).toBe(0); // never tried to send any failed emails (whitelist)
|
|
107
112
|
// Load recipietns
|
|
108
113
|
const recipients = await EmailRecipient_1.EmailRecipient.select().where('emailId', model.id).fetch();
|
|
109
114
|
expect(recipients).toIncludeSameMembers([
|
|
@@ -153,8 +158,8 @@ describe('Model.Email', () => {
|
|
|
153
158
|
expect(model.failedCount).toBe(0);
|
|
154
159
|
expect(model.softFailedCount).toBe(0);
|
|
155
160
|
// Both have succeeded
|
|
156
|
-
expect(await email_1.EmailMocker.
|
|
157
|
-
expect(await email_1.EmailMocker.
|
|
161
|
+
expect(await email_1.EmailMocker.getSucceededCount()).toBe(2);
|
|
162
|
+
expect(await email_1.EmailMocker.getFailedCount()).toBe(1); // One retry
|
|
158
163
|
// Load recipietns
|
|
159
164
|
const recipients = await EmailRecipient_1.EmailRecipient.select().where('emailId', model.id).fetch();
|
|
160
165
|
expect(recipients).toIncludeSameMembers([
|
|
@@ -199,8 +204,8 @@ describe('Model.Email', () => {
|
|
|
199
204
|
expect(model.failedCount).toBe(0);
|
|
200
205
|
expect(model.softFailedCount).toBe(0);
|
|
201
206
|
// Both have succeeded
|
|
202
|
-
expect(await email_1.EmailMocker.
|
|
203
|
-
expect(await email_1.EmailMocker.
|
|
207
|
+
expect(await email_1.EmailMocker.getSucceededCount()).toBe(0);
|
|
208
|
+
expect(await email_1.EmailMocker.getFailedCount()).toBe(0); // One retry
|
|
204
209
|
}, 15_000);
|
|
205
210
|
it('Marks email recipient as failed if fails three times', async () => {
|
|
206
211
|
const model = await buildEmail({
|
|
@@ -233,8 +238,8 @@ describe('Model.Email', () => {
|
|
|
233
238
|
expect(model.failedCount).toBe(2);
|
|
234
239
|
expect(model.softFailedCount).toBe(0);
|
|
235
240
|
// Both have succeeded
|
|
236
|
-
expect(await email_1.EmailMocker.
|
|
237
|
-
expect(await email_1.EmailMocker.
|
|
241
|
+
expect(await email_1.EmailMocker.getSucceededCount()).toBe(0);
|
|
242
|
+
expect(await email_1.EmailMocker.getFailedCount()).toBe(6); // Two retries for each recipient
|
|
238
243
|
// Load recipietns
|
|
239
244
|
const recipients = await EmailRecipient_1.EmailRecipient.select().where('emailId', model.id).fetch();
|
|
240
245
|
expect(recipients).toIncludeSameMembers([
|
|
@@ -278,8 +283,8 @@ describe('Model.Email', () => {
|
|
|
278
283
|
expect(model.failedCount).toBe(0);
|
|
279
284
|
expect(model.softFailedCount).toBe(0);
|
|
280
285
|
// Both have succeeded
|
|
281
|
-
expect(await email_1.EmailMocker.
|
|
282
|
-
expect(await email_1.EmailMocker.
|
|
286
|
+
expect(await email_1.EmailMocker.getSucceededCount()).toBe(1);
|
|
287
|
+
expect(await email_1.EmailMocker.getFailedCount()).toBe(0);
|
|
283
288
|
// Load recipietns
|
|
284
289
|
const recipients = await EmailRecipient_1.EmailRecipient.select().where('emailId', model.id).fetch();
|
|
285
290
|
expect(recipients).toIncludeSameMembers([
|
|
@@ -290,7 +295,7 @@ describe('Model.Email', () => {
|
|
|
290
295
|
}),
|
|
291
296
|
]);
|
|
292
297
|
// Check to header
|
|
293
|
-
expect(email_1.EmailMocker.
|
|
298
|
+
expect(email_1.EmailMocker.getSucceededEmail(0).to).toEqual('example@domain.be');
|
|
294
299
|
}, 15_000);
|
|
295
300
|
it('Includes recipient names in mail header', async () => {
|
|
296
301
|
const model = await buildEmail({
|
|
@@ -312,8 +317,8 @@ describe('Model.Email', () => {
|
|
|
312
317
|
expect(model.failedCount).toBe(0);
|
|
313
318
|
expect(model.softFailedCount).toBe(0);
|
|
314
319
|
// Both have succeeded
|
|
315
|
-
expect(await email_1.EmailMocker.
|
|
316
|
-
expect(await email_1.EmailMocker.
|
|
320
|
+
expect(await email_1.EmailMocker.getSucceededCount()).toBe(1);
|
|
321
|
+
expect(await email_1.EmailMocker.getFailedCount()).toBe(0);
|
|
317
322
|
// Load recipietns
|
|
318
323
|
const recipients = await EmailRecipient_1.EmailRecipient.select().where('emailId', model.id).fetch();
|
|
319
324
|
expect(recipients).toIncludeSameMembers([
|
|
@@ -326,7 +331,7 @@ describe('Model.Email', () => {
|
|
|
326
331
|
}),
|
|
327
332
|
]);
|
|
328
333
|
// Check to header
|
|
329
|
-
expect(email_1.EmailMocker.
|
|
334
|
+
expect(email_1.EmailMocker.getSucceededEmail(0).to).toEqual('"John Von Doe" <example@domain.be>');
|
|
330
335
|
}, 15_000);
|
|
331
336
|
it('Skips invalid email addresses', async () => {
|
|
332
337
|
const model = await buildEmail({
|
|
@@ -348,8 +353,8 @@ describe('Model.Email', () => {
|
|
|
348
353
|
expect(model.failedCount).toBe(1);
|
|
349
354
|
expect(model.softFailedCount).toBe(0);
|
|
350
355
|
// Both have succeeded
|
|
351
|
-
expect(await email_1.EmailMocker.
|
|
352
|
-
expect(await email_1.EmailMocker.
|
|
356
|
+
expect(await email_1.EmailMocker.getSucceededCount()).toBe(0);
|
|
357
|
+
expect(await email_1.EmailMocker.getFailedCount()).toBe(0);
|
|
353
358
|
// Load recipietns
|
|
354
359
|
const recipients = await EmailRecipient_1.EmailRecipient.select().where('emailId', model.id).fetch();
|
|
355
360
|
expect(recipients).toIncludeSameMembers([
|
|
@@ -392,8 +397,8 @@ describe('Model.Email', () => {
|
|
|
392
397
|
expect(model.failedCount).toBe(0);
|
|
393
398
|
expect(model.softFailedCount).toBe(0);
|
|
394
399
|
// Both have succeeded
|
|
395
|
-
expect(await email_1.EmailMocker.
|
|
396
|
-
expect(await email_1.EmailMocker.
|
|
400
|
+
expect(await email_1.EmailMocker.getSucceededCount()).toBe(1);
|
|
401
|
+
expect(await email_1.EmailMocker.getFailedCount()).toBe(0);
|
|
397
402
|
// Load recipietns
|
|
398
403
|
const recipients = await EmailRecipient_1.EmailRecipient.select().where('emailId', model.id).fetch();
|
|
399
404
|
expect(recipients).toIncludeSameMembers([
|
|
@@ -433,10 +438,10 @@ describe('Model.Email', () => {
|
|
|
433
438
|
expect(model.failedCount).toBe(0);
|
|
434
439
|
expect(model.softFailedCount).toBe(0);
|
|
435
440
|
// Both have succeeded
|
|
436
|
-
expect(await email_1.EmailMocker.
|
|
437
|
-
expect(await email_1.EmailMocker.
|
|
441
|
+
expect(await email_1.EmailMocker.getSucceededCount()).toBe(1);
|
|
442
|
+
expect(await email_1.EmailMocker.getFailedCount()).toBe(0);
|
|
438
443
|
// Check to header
|
|
439
|
-
expect(email_1.EmailMocker.
|
|
444
|
+
expect(email_1.EmailMocker.getSucceededEmail(0)).toMatchObject({
|
|
440
445
|
to: 'example@domain.be',
|
|
441
446
|
from: '"My Platform" <info@my-platform.com>',
|
|
442
447
|
replyTo: undefined,
|
|
@@ -471,10 +476,10 @@ describe('Model.Email', () => {
|
|
|
471
476
|
expect(model.failedCount).toBe(0);
|
|
472
477
|
expect(model.softFailedCount).toBe(0);
|
|
473
478
|
// Both have succeeded
|
|
474
|
-
expect(await email_1.EmailMocker.
|
|
475
|
-
expect(await email_1.EmailMocker.
|
|
479
|
+
expect(await email_1.EmailMocker.getSucceededCount()).toBe(1);
|
|
480
|
+
expect(await email_1.EmailMocker.getFailedCount()).toBe(0);
|
|
476
481
|
// Check to header
|
|
477
|
-
expect(email_1.EmailMocker.
|
|
482
|
+
expect(email_1.EmailMocker.getSucceededEmail(0)).toMatchObject({
|
|
478
483
|
to: 'example@domain.be',
|
|
479
484
|
from: '"My Platform" <noreply@broadcast.my-platform.com>', // domain has changed here
|
|
480
485
|
replyTo: '"My Platform" <info@other-platform.com>', // Reply to should be set
|
|
@@ -513,10 +518,10 @@ describe('Model.Email', () => {
|
|
|
513
518
|
expect(model.failedCount).toBe(0);
|
|
514
519
|
expect(model.softFailedCount).toBe(0);
|
|
515
520
|
// Both have succeeded
|
|
516
|
-
expect(await email_1.EmailMocker.
|
|
517
|
-
expect(await email_1.EmailMocker.
|
|
521
|
+
expect(await email_1.EmailMocker.getSucceededCount()).toBe(1);
|
|
522
|
+
expect(await email_1.EmailMocker.getFailedCount()).toBe(0);
|
|
518
523
|
// Check to header
|
|
519
|
-
expect(email_1.EmailMocker.
|
|
524
|
+
expect(email_1.EmailMocker.getSucceededEmail(0)).toMatchObject({
|
|
520
525
|
to: 'example@domain.be',
|
|
521
526
|
from: '"My Platform" <noreply-uritest@broadcast.my-platform.com>', // domain has changed here
|
|
522
527
|
replyTo: '"My Platform" <info@my-platform.com>', // Reply to should be set
|
|
@@ -556,10 +561,10 @@ describe('Model.Email', () => {
|
|
|
556
561
|
expect(model.failedCount).toBe(0);
|
|
557
562
|
expect(model.softFailedCount).toBe(0);
|
|
558
563
|
// Both have succeeded
|
|
559
|
-
expect(await email_1.EmailMocker.
|
|
560
|
-
expect(await email_1.EmailMocker.
|
|
564
|
+
expect(await email_1.EmailMocker.getSucceededCount()).toBe(1);
|
|
565
|
+
expect(await email_1.EmailMocker.getFailedCount()).toBe(0);
|
|
561
566
|
// Check to header
|
|
562
|
-
expect(email_1.EmailMocker.
|
|
567
|
+
expect(email_1.EmailMocker.getSucceededEmail(0)).toMatchObject({
|
|
563
568
|
to: 'example@domain.be',
|
|
564
569
|
from: '"My Platform" <info@my-platform.com>', // domain has changed here
|
|
565
570
|
replyTo: undefined,
|
|
@@ -589,6 +594,7 @@ describe('Model.Email', () => {
|
|
|
589
594
|
html: '{{fromAddress}}',
|
|
590
595
|
text: '{{fromAddress}}',
|
|
591
596
|
subject: '{{fromAddress}}',
|
|
597
|
+
emailType: 'system-test', // Makes sure we don't need to include unsubscribeUrl
|
|
592
598
|
});
|
|
593
599
|
await model.queueForSending(true);
|
|
594
600
|
await model.refresh();
|
|
@@ -597,10 +603,10 @@ describe('Model.Email', () => {
|
|
|
597
603
|
expect(model.emailRecipientsCount).toBe(1);
|
|
598
604
|
expect(model.status).toBe(structures_1.EmailStatus.Sent);
|
|
599
605
|
// Both have succeeded
|
|
600
|
-
expect(await email_1.EmailMocker.
|
|
601
|
-
expect(await email_1.EmailMocker.
|
|
606
|
+
expect(await email_1.EmailMocker.getSucceededCount()).toBe(1);
|
|
607
|
+
expect(await email_1.EmailMocker.getFailedCount()).toBe(0);
|
|
602
608
|
// Check to header
|
|
603
|
-
expect(email_1.EmailMocker.
|
|
609
|
+
expect(email_1.EmailMocker.getSucceededEmail(0)).toMatchObject({
|
|
604
610
|
to: 'example@domain.be',
|
|
605
611
|
from: '"Custom Name" <noreply-' + organization.uri + '@broadcast.my-platform.com>',
|
|
606
612
|
replyTo: '"Custom Name" <custom@customdomain.com>', // domain has changed here
|
|
@@ -637,6 +643,7 @@ describe('Model.Email', () => {
|
|
|
637
643
|
html: '{{primaryColor}};{{primaryColorContrast}};{{organizationName}};{{fromName}}',
|
|
638
644
|
text: '{{primaryColor}};{{primaryColorContrast}};{{organizationName}};{{fromName}}',
|
|
639
645
|
subject: '{{primaryColor}};{{primaryColorContrast}};{{organizationName}};{{fromName}}',
|
|
646
|
+
emailType: 'system-test', // Makes sure we don't need to include unsubscribeUrl
|
|
640
647
|
});
|
|
641
648
|
await model.queueForSending(true);
|
|
642
649
|
await model.refresh();
|
|
@@ -645,10 +652,10 @@ describe('Model.Email', () => {
|
|
|
645
652
|
expect(model.emailRecipientsCount).toBe(1);
|
|
646
653
|
expect(model.status).toBe(structures_1.EmailStatus.Sent);
|
|
647
654
|
// Both have succeeded
|
|
648
|
-
expect(await email_1.EmailMocker.
|
|
649
|
-
expect(await email_1.EmailMocker.
|
|
655
|
+
expect(await email_1.EmailMocker.getSucceededCount()).toBe(1);
|
|
656
|
+
expect(await email_1.EmailMocker.getFailedCount()).toBe(0);
|
|
650
657
|
// Check to header
|
|
651
|
-
expect(email_1.EmailMocker.
|
|
658
|
+
expect(email_1.EmailMocker.getSucceededEmail(0)).toMatchObject({
|
|
652
659
|
subject: `${brightYellow};${expectedContrastColor};${organization.name};${organization.name}`,
|
|
653
660
|
html: `${brightYellow};${expectedContrastColor};${organization.name};${organization.name}`,
|
|
654
661
|
text: `${brightYellow};${expectedContrastColor};${organization.name};${organization.name}`,
|
|
@@ -686,6 +693,7 @@ describe('Model.Email', () => {
|
|
|
686
693
|
html: '{{primaryColor}};{{primaryColorContrast}};{{organizationName}};{{fromName}}',
|
|
687
694
|
text: '{{primaryColor}};{{primaryColorContrast}};{{organizationName}};{{fromName}}',
|
|
688
695
|
subject: '{{primaryColor}};{{primaryColorContrast}};{{organizationName}};{{fromName}}',
|
|
696
|
+
emailType: 'system-test', // Makes sure we don't need to include unsubscribeUrl
|
|
689
697
|
});
|
|
690
698
|
await model.queueForSending(true);
|
|
691
699
|
await model.refresh();
|
|
@@ -694,10 +702,10 @@ describe('Model.Email', () => {
|
|
|
694
702
|
expect(model.emailRecipientsCount).toBe(1);
|
|
695
703
|
expect(model.status).toBe(structures_1.EmailStatus.Sent);
|
|
696
704
|
// Both have succeeded
|
|
697
|
-
expect(await email_1.EmailMocker.
|
|
698
|
-
expect(await email_1.EmailMocker.
|
|
705
|
+
expect(await email_1.EmailMocker.getSucceededCount()).toBe(1);
|
|
706
|
+
expect(await email_1.EmailMocker.getFailedCount()).toBe(0);
|
|
699
707
|
// Check to header
|
|
700
|
-
expect(email_1.EmailMocker.
|
|
708
|
+
expect(email_1.EmailMocker.getSucceededEmail(0)).toMatchObject({
|
|
701
709
|
subject: `${brightBlue};${expectedContrastColor};${organization.name};Custom Name`,
|
|
702
710
|
html: `${brightBlue};${expectedContrastColor};${organization.name};Custom Name`,
|
|
703
711
|
text: `${brightBlue};${expectedContrastColor};${organization.name};Custom Name`,
|
|
@@ -728,6 +736,7 @@ describe('Model.Email', () => {
|
|
|
728
736
|
html: '{{primaryColor}};{{primaryColorContrast}};{{organizationName}};{{fromName}}',
|
|
729
737
|
text: '{{primaryColor}};{{primaryColorContrast}};{{organizationName}};{{fromName}}',
|
|
730
738
|
subject: '{{primaryColor}};{{primaryColorContrast}};{{organizationName}};{{fromName}}',
|
|
739
|
+
emailType: 'system-test', // Makes sure we don't need to include unsubscribeUrl
|
|
731
740
|
});
|
|
732
741
|
await model.queueForSending(true);
|
|
733
742
|
await model.refresh();
|
|
@@ -736,15 +745,292 @@ describe('Model.Email', () => {
|
|
|
736
745
|
expect(model.emailRecipientsCount).toBe(1);
|
|
737
746
|
expect(model.status).toBe(structures_1.EmailStatus.Sent);
|
|
738
747
|
// Both have succeeded
|
|
739
|
-
expect(await email_1.EmailMocker.
|
|
740
|
-
expect(await email_1.EmailMocker.
|
|
748
|
+
expect(await email_1.EmailMocker.getSucceededCount()).toBe(1);
|
|
749
|
+
expect(await email_1.EmailMocker.getFailedCount()).toBe(0);
|
|
741
750
|
// Check to header
|
|
742
|
-
expect(email_1.EmailMocker.
|
|
751
|
+
expect(email_1.EmailMocker.getSucceededEmail(0)).toMatchObject({
|
|
743
752
|
subject: `${darkRed};${expectedContrastColor};${platform.config.name};${platform.config.name}`,
|
|
744
753
|
html: `${darkRed};${expectedContrastColor};${platform.config.name};${platform.config.name}`,
|
|
745
754
|
text: `${darkRed};${expectedContrastColor};${platform.config.name};${platform.config.name}`,
|
|
746
755
|
});
|
|
747
756
|
}, 15_000);
|
|
757
|
+
describe('User based replacements', () => {
|
|
758
|
+
it('The balance is added for existing users', async () => {
|
|
759
|
+
test_utils_1.TestUtils.setEnvironment('domains', {
|
|
760
|
+
...STAMHOOFD.domains,
|
|
761
|
+
defaultTransactionalEmail: {
|
|
762
|
+
'': 'my-platform.com',
|
|
763
|
+
},
|
|
764
|
+
defaultBroadcastEmail: {
|
|
765
|
+
'': 'broadcast.my-platform.com',
|
|
766
|
+
},
|
|
767
|
+
});
|
|
768
|
+
const organization = await new OrganizationFactory_1.OrganizationFactory({}).create();
|
|
769
|
+
const existingUser = await new factories_1.UserFactory({
|
|
770
|
+
organization,
|
|
771
|
+
}).create();
|
|
772
|
+
// Add outstanding balance items for this user
|
|
773
|
+
const balanceItem = await new factories_1.BalanceItemFactory({
|
|
774
|
+
userId: existingUser.id,
|
|
775
|
+
organizationId: organization.id,
|
|
776
|
+
type: structures_1.BalanceItemType.Other,
|
|
777
|
+
amount: 2,
|
|
778
|
+
unitPrice: 12_99,
|
|
779
|
+
description: 'Test balance item',
|
|
780
|
+
}).create();
|
|
781
|
+
await CachedBalance_1.CachedBalance.updateForUsers(organization.id, [existingUser.id]);
|
|
782
|
+
const model = await buildEmail({
|
|
783
|
+
organizationId: organization.id,
|
|
784
|
+
recipients: [
|
|
785
|
+
structures_1.EmailRecipient.create({
|
|
786
|
+
email: existingUser.email,
|
|
787
|
+
userId: existingUser.id,
|
|
788
|
+
}),
|
|
789
|
+
],
|
|
790
|
+
fromAddress: 'custom@customdomain.com',
|
|
791
|
+
html: '<p>{{outstandingBalance}}</p>{{balanceTable}}',
|
|
792
|
+
subject: '{{outstandingBalance}}',
|
|
793
|
+
emailType: 'system-test', // Makes sure we don't need to include unsubscribeUrl
|
|
794
|
+
});
|
|
795
|
+
await model.queueForSending(true);
|
|
796
|
+
await model.refresh();
|
|
797
|
+
// Check if it was sent correctly
|
|
798
|
+
expect(model.recipientsStatus).toBe(structures_1.EmailRecipientsStatus.Created);
|
|
799
|
+
expect(model.emailRecipientsCount).toBe(1);
|
|
800
|
+
expect(model.status).toBe(structures_1.EmailStatus.Sent);
|
|
801
|
+
// Both have succeeded
|
|
802
|
+
expect(await email_1.EmailMocker.getSucceededCount()).toBe(1);
|
|
803
|
+
expect(await email_1.EmailMocker.getFailedCount()).toBe(0);
|
|
804
|
+
const expectedAmount = utility_1.Formatter.price(balanceItem.unitPrice * balanceItem.amount);
|
|
805
|
+
// Check to header
|
|
806
|
+
expect(email_1.EmailMocker.getSucceededEmail(0)).toMatchObject({
|
|
807
|
+
subject: `${expectedAmount}`,
|
|
808
|
+
});
|
|
809
|
+
expect(email_1.EmailMocker.getSucceededEmail(0).html).toInclude('<p>' + expectedAmount + '</p>');
|
|
810
|
+
expect(email_1.EmailMocker.getSucceededEmail(0).text).toInclude(expectedAmount);
|
|
811
|
+
// Check if the table is correct
|
|
812
|
+
expect(email_1.EmailMocker.getSucceededEmail(0).html).toInclude('<table');
|
|
813
|
+
expect(email_1.EmailMocker.getSucceededEmail(0).html).toInclude('2 x '); // amount
|
|
814
|
+
expect(email_1.EmailMocker.getSucceededEmail(0).html).toInclude(utility_1.Formatter.price(12_99)); // unit price
|
|
815
|
+
expect(email_1.EmailMocker.getSucceededEmail(0).html).toInclude('<td>' + expectedAmount); // total price in table
|
|
816
|
+
expect(email_1.EmailMocker.getSucceededEmail(0).html).toInclude('Test balance item'); // description
|
|
817
|
+
expect(email_1.EmailMocker.getSucceededEmail(0).text).toInclude('2 x '); // amount
|
|
818
|
+
expect(email_1.EmailMocker.getSucceededEmail(0).text).toInclude(utility_1.Formatter.price(12_99)); // unit price
|
|
819
|
+
expect(email_1.EmailMocker.getSucceededEmail(0).text).toInclude(expectedAmount); // total price in table
|
|
820
|
+
expect(email_1.EmailMocker.getSucceededEmail(0).text?.toLowerCase()).toInclude('test balance item'); // description
|
|
821
|
+
}, 15_000);
|
|
822
|
+
it('The balance is zero for unknown users', async () => {
|
|
823
|
+
test_utils_1.TestUtils.setEnvironment('domains', {
|
|
824
|
+
...STAMHOOFD.domains,
|
|
825
|
+
defaultTransactionalEmail: {
|
|
826
|
+
'': 'my-platform.com',
|
|
827
|
+
},
|
|
828
|
+
defaultBroadcastEmail: {
|
|
829
|
+
'': 'broadcast.my-platform.com',
|
|
830
|
+
},
|
|
831
|
+
});
|
|
832
|
+
const organization = await new OrganizationFactory_1.OrganizationFactory({}).create();
|
|
833
|
+
const model = await buildEmail({
|
|
834
|
+
organizationId: organization.id,
|
|
835
|
+
recipients: [
|
|
836
|
+
structures_1.EmailRecipient.create({
|
|
837
|
+
email: 'unknown-user@example.com',
|
|
838
|
+
}),
|
|
839
|
+
],
|
|
840
|
+
fromAddress: 'custom@customdomain.com',
|
|
841
|
+
html: '<p>{{outstandingBalance}}</p>{{balanceTable}}',
|
|
842
|
+
subject: '{{outstandingBalance}}',
|
|
843
|
+
emailType: 'system-test', // Makes sure we don't need to include unsubscribeUrl
|
|
844
|
+
});
|
|
845
|
+
await model.queueForSending(true);
|
|
846
|
+
await model.refresh();
|
|
847
|
+
// Check if it was sent correctly
|
|
848
|
+
expect(model.recipientsStatus).toBe(structures_1.EmailRecipientsStatus.Created);
|
|
849
|
+
expect(model.emailRecipientsCount).toBe(1);
|
|
850
|
+
expect(model.status).toBe(structures_1.EmailStatus.Sent);
|
|
851
|
+
// Both have succeeded
|
|
852
|
+
expect(await email_1.EmailMocker.getSucceededCount()).toBe(1);
|
|
853
|
+
expect(await email_1.EmailMocker.getFailedCount()).toBe(0);
|
|
854
|
+
const expectedAmount = utility_1.Formatter.price(0);
|
|
855
|
+
// Check to header
|
|
856
|
+
expect(email_1.EmailMocker.getSucceededEmail(0)).toMatchObject({
|
|
857
|
+
subject: `${expectedAmount}`,
|
|
858
|
+
});
|
|
859
|
+
expect(email_1.EmailMocker.getSucceededEmail(0).html).toInclude('<p>' + expectedAmount + '</p>');
|
|
860
|
+
expect(email_1.EmailMocker.getSucceededEmail(0).text).toInclude(expectedAmount);
|
|
861
|
+
// Check if the table is correct
|
|
862
|
+
expect(email_1.EmailMocker.getSucceededEmail(0).html).not.toInclude('<table');
|
|
863
|
+
expect(email_1.EmailMocker.getSucceededEmail(0).html).not.toInclude(' x '); // amount
|
|
864
|
+
expect(email_1.EmailMocker.getSucceededEmail(0).html).toInclude('<p class="description">' + $t('4c4f6571-f7b5-469d-a16f-b1547b43a610') + '</p>');
|
|
865
|
+
expect(email_1.EmailMocker.getSucceededEmail(0).text).not.toInclude(' x '); // amount
|
|
866
|
+
expect(email_1.EmailMocker.getSucceededEmail(0).text?.toLowerCase()).toInclude($t('4c4f6571-f7b5-469d-a16f-b1547b43a610').toLowerCase());
|
|
867
|
+
}, 15_000);
|
|
868
|
+
it('loginDetails are added for existing users without password', async () => {
|
|
869
|
+
test_utils_1.TestUtils.setEnvironment('domains', {
|
|
870
|
+
...STAMHOOFD.domains,
|
|
871
|
+
defaultTransactionalEmail: {
|
|
872
|
+
'': 'my-platform.com',
|
|
873
|
+
},
|
|
874
|
+
defaultBroadcastEmail: {
|
|
875
|
+
'': 'broadcast.my-platform.com',
|
|
876
|
+
},
|
|
877
|
+
});
|
|
878
|
+
const organization = await new OrganizationFactory_1.OrganizationFactory({}).create();
|
|
879
|
+
const existingUser = await new factories_1.UserFactory({
|
|
880
|
+
organization,
|
|
881
|
+
password: null,
|
|
882
|
+
}).create();
|
|
883
|
+
const model = await buildEmail({
|
|
884
|
+
organizationId: organization.id,
|
|
885
|
+
recipients: [
|
|
886
|
+
structures_1.EmailRecipient.create({
|
|
887
|
+
email: existingUser.email,
|
|
888
|
+
userId: existingUser.id,
|
|
889
|
+
}),
|
|
890
|
+
],
|
|
891
|
+
fromAddress: 'custom@customdomain.com',
|
|
892
|
+
html: '{{loginDetails}}',
|
|
893
|
+
emailType: 'system-test', // Makes sure we don't need to include unsubscribeUrl
|
|
894
|
+
});
|
|
895
|
+
await model.queueForSending(true);
|
|
896
|
+
await model.refresh();
|
|
897
|
+
// Check if it was sent correctly
|
|
898
|
+
expect(model.recipientsStatus).toBe(structures_1.EmailRecipientsStatus.Created);
|
|
899
|
+
expect(model.emailRecipientsCount).toBe(1);
|
|
900
|
+
expect(model.status).toBe(structures_1.EmailStatus.Sent);
|
|
901
|
+
// Both have succeeded
|
|
902
|
+
expect(await email_1.EmailMocker.getSucceededCount()).toBe(1);
|
|
903
|
+
expect(await email_1.EmailMocker.getFailedCount()).toBe(0);
|
|
904
|
+
expect(email_1.EmailMocker.getSucceededEmail(0).html).toInclude($t('3ab6ddc1-7ddc-4671-95d2-64994a5d36cc', { email: existingUser.email }));
|
|
905
|
+
expect(email_1.EmailMocker.getSucceededEmail(0).text).toInclude($t('3ab6ddc1-7ddc-4671-95d2-64994a5d36cc', { email: existingUser.email }));
|
|
906
|
+
}, 15_000);
|
|
907
|
+
it('loginDetails are added for inexisting users', async () => {
|
|
908
|
+
test_utils_1.TestUtils.setEnvironment('domains', {
|
|
909
|
+
...STAMHOOFD.domains,
|
|
910
|
+
defaultTransactionalEmail: {
|
|
911
|
+
'': 'my-platform.com',
|
|
912
|
+
},
|
|
913
|
+
defaultBroadcastEmail: {
|
|
914
|
+
'': 'broadcast.my-platform.com',
|
|
915
|
+
},
|
|
916
|
+
});
|
|
917
|
+
const organization = await new OrganizationFactory_1.OrganizationFactory({}).create();
|
|
918
|
+
const model = await buildEmail({
|
|
919
|
+
organizationId: organization.id,
|
|
920
|
+
recipients: [
|
|
921
|
+
structures_1.EmailRecipient.create({
|
|
922
|
+
email: 'unknown@example.com',
|
|
923
|
+
}),
|
|
924
|
+
],
|
|
925
|
+
fromAddress: 'custom@customdomain.com',
|
|
926
|
+
html: '{{loginDetails}}',
|
|
927
|
+
emailType: 'system-test', // Makes sure we don't need to include unsubscribeUrl
|
|
928
|
+
});
|
|
929
|
+
await model.queueForSending(true);
|
|
930
|
+
await model.refresh();
|
|
931
|
+
// Check if it was sent correctly
|
|
932
|
+
expect(model.recipientsStatus).toBe(structures_1.EmailRecipientsStatus.Created);
|
|
933
|
+
expect(model.emailRecipientsCount).toBe(1);
|
|
934
|
+
expect(model.status).toBe(structures_1.EmailStatus.Sent);
|
|
935
|
+
// Both have succeeded
|
|
936
|
+
expect(await email_1.EmailMocker.getSucceededCount()).toBe(1);
|
|
937
|
+
expect(await email_1.EmailMocker.getFailedCount()).toBe(0);
|
|
938
|
+
expect(email_1.EmailMocker.getSucceededEmail(0).html).toInclude($t('3ab6ddc1-7ddc-4671-95d2-64994a5d36cc', { email: 'unknown@example.com' }));
|
|
939
|
+
expect(email_1.EmailMocker.getSucceededEmail(0).text).toInclude($t('3ab6ddc1-7ddc-4671-95d2-64994a5d36cc', { email: 'unknown@example.com' }));
|
|
940
|
+
}, 15_000);
|
|
941
|
+
it('loginDetails are added for existing users with password', async () => {
|
|
942
|
+
test_utils_1.TestUtils.setEnvironment('domains', {
|
|
943
|
+
...STAMHOOFD.domains,
|
|
944
|
+
defaultTransactionalEmail: {
|
|
945
|
+
'': 'my-platform.com',
|
|
946
|
+
},
|
|
947
|
+
defaultBroadcastEmail: {
|
|
948
|
+
'': 'broadcast.my-platform.com',
|
|
949
|
+
},
|
|
950
|
+
});
|
|
951
|
+
const organization = await new OrganizationFactory_1.OrganizationFactory({}).create();
|
|
952
|
+
const existingUser = await new factories_1.UserFactory({
|
|
953
|
+
organization,
|
|
954
|
+
password: 'existing',
|
|
955
|
+
}).create();
|
|
956
|
+
const model = await buildEmail({
|
|
957
|
+
organizationId: organization.id,
|
|
958
|
+
recipients: [
|
|
959
|
+
structures_1.EmailRecipient.create({
|
|
960
|
+
email: existingUser.email,
|
|
961
|
+
userId: existingUser.id,
|
|
962
|
+
}),
|
|
963
|
+
],
|
|
964
|
+
fromAddress: 'custom@customdomain.com',
|
|
965
|
+
html: '{{loginDetails}}',
|
|
966
|
+
emailType: 'system-test', // Makes sure we don't need to include unsubscribeUrl
|
|
967
|
+
});
|
|
968
|
+
await model.queueForSending(true);
|
|
969
|
+
await model.refresh();
|
|
970
|
+
// Check if it was sent correctly
|
|
971
|
+
expect(model.recipientsStatus).toBe(structures_1.EmailRecipientsStatus.Created);
|
|
972
|
+
expect(model.emailRecipientsCount).toBe(1);
|
|
973
|
+
expect(model.status).toBe(structures_1.EmailStatus.Sent);
|
|
974
|
+
// Both have succeeded
|
|
975
|
+
expect(await email_1.EmailMocker.getSucceededCount()).toBe(1);
|
|
976
|
+
expect(await email_1.EmailMocker.getFailedCount()).toBe(0);
|
|
977
|
+
expect(email_1.EmailMocker.getSucceededEmail(0).html).toInclude($t('5403b466-98fe-48ac-beff-38acf7c9734d', { email: existingUser.email }));
|
|
978
|
+
expect(email_1.EmailMocker.getSucceededEmail(0).text).toInclude($t('5403b466-98fe-48ac-beff-38acf7c9734d', { email: existingUser.email }));
|
|
979
|
+
}, 15_000);
|
|
980
|
+
it('loginDetails include member security keys for existing users without password', async () => {
|
|
981
|
+
test_utils_1.TestUtils.setEnvironment('userMode', 'platform');
|
|
982
|
+
test_utils_1.TestUtils.setEnvironment('domains', {
|
|
983
|
+
...STAMHOOFD.domains,
|
|
984
|
+
defaultTransactionalEmail: {
|
|
985
|
+
'': 'my-platform.com',
|
|
986
|
+
},
|
|
987
|
+
defaultBroadcastEmail: {
|
|
988
|
+
'': 'broadcast.my-platform.com',
|
|
989
|
+
},
|
|
990
|
+
});
|
|
991
|
+
const organization = await new OrganizationFactory_1.OrganizationFactory({}).create();
|
|
992
|
+
const existingUser = await new factories_1.UserFactory({
|
|
993
|
+
organization,
|
|
994
|
+
password: null,
|
|
995
|
+
}).create();
|
|
996
|
+
const member = await new factories_1.MemberFactory({
|
|
997
|
+
organization,
|
|
998
|
+
user: existingUser,
|
|
999
|
+
}).create();
|
|
1000
|
+
member.details.securityCode = '123456790123456'; // 16 chars
|
|
1001
|
+
await member.save();
|
|
1002
|
+
// Add a linked member
|
|
1003
|
+
const model = await buildEmail({
|
|
1004
|
+
organizationId: organization.id,
|
|
1005
|
+
recipients: [
|
|
1006
|
+
structures_1.EmailRecipient.create({
|
|
1007
|
+
email: existingUser.email,
|
|
1008
|
+
userId: existingUser.id,
|
|
1009
|
+
}),
|
|
1010
|
+
],
|
|
1011
|
+
fromAddress: 'custom@customdomain.com',
|
|
1012
|
+
html: '{{loginDetails}}',
|
|
1013
|
+
emailType: 'system-test', // Makes sure we don't need to include unsubscribeUrl
|
|
1014
|
+
});
|
|
1015
|
+
await model.queueForSending(true);
|
|
1016
|
+
await model.refresh();
|
|
1017
|
+
// Check if it was sent correctly
|
|
1018
|
+
expect(model.recipientsStatus).toBe(structures_1.EmailRecipientsStatus.Created);
|
|
1019
|
+
expect(model.emailRecipientsCount).toBe(1);
|
|
1020
|
+
expect(model.status).toBe(structures_1.EmailStatus.Sent);
|
|
1021
|
+
// Both have succeeded
|
|
1022
|
+
expect(await email_1.EmailMocker.getSucceededCount()).toBe(1);
|
|
1023
|
+
expect(await email_1.EmailMocker.getFailedCount()).toBe(0);
|
|
1024
|
+
expect(email_1.EmailMocker.getSucceededEmail(0).html).toInclude($t('e2519632-c495-4629-9ddb-334a4f00e272', {
|
|
1025
|
+
firstName: utility_1.Formatter.escapeHtml(member.firstName),
|
|
1026
|
+
securityCode: `<span class="style-inline-code">${utility_1.Formatter.escapeHtml(utility_1.Formatter.spaceString(member.details.securityCode ?? '', 4, '-'))}</span>`,
|
|
1027
|
+
}));
|
|
1028
|
+
expect(email_1.EmailMocker.getSucceededEmail(0).text).toInclude($t('e2519632-c495-4629-9ddb-334a4f00e272', {
|
|
1029
|
+
firstName: member.firstName,
|
|
1030
|
+
securityCode: utility_1.Formatter.spaceString(member.details.securityCode ?? '', 4, '-'),
|
|
1031
|
+
}));
|
|
1032
|
+
}, 15_000);
|
|
1033
|
+
});
|
|
748
1034
|
});
|
|
749
1035
|
});
|
|
750
1036
|
//# sourceMappingURL=Email.test.js.map
|