@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.
@@ -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.broadcast.getSucceededCount()).toBe(1);
106
- expect(await email_1.EmailMocker.broadcast.getFailedCount()).toBe(0); // never tried to send any failed emails (whitelist)
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.broadcast.getSucceededCount()).toBe(2);
157
- expect(await email_1.EmailMocker.broadcast.getFailedCount()).toBe(1); // One retry
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.broadcast.getSucceededCount()).toBe(0);
203
- expect(await email_1.EmailMocker.broadcast.getFailedCount()).toBe(0); // One retry
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.broadcast.getSucceededCount()).toBe(0);
237
- expect(await email_1.EmailMocker.broadcast.getFailedCount()).toBe(6); // Two retries for each recipient
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.broadcast.getSucceededCount()).toBe(1);
282
- expect(await email_1.EmailMocker.broadcast.getFailedCount()).toBe(0);
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.broadcast.getSucceededEmail(0).to).toEqual('example@domain.be');
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.broadcast.getSucceededCount()).toBe(1);
316
- expect(await email_1.EmailMocker.broadcast.getFailedCount()).toBe(0);
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.broadcast.getSucceededEmail(0).to).toEqual('"John Von Doe" <example@domain.be>');
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.broadcast.getSucceededCount()).toBe(0);
352
- expect(await email_1.EmailMocker.broadcast.getFailedCount()).toBe(0);
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.broadcast.getSucceededCount()).toBe(1);
396
- expect(await email_1.EmailMocker.broadcast.getFailedCount()).toBe(0);
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.broadcast.getSucceededCount()).toBe(1);
437
- expect(await email_1.EmailMocker.broadcast.getFailedCount()).toBe(0);
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.broadcast.getSucceededEmail(0)).toMatchObject({
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.broadcast.getSucceededCount()).toBe(1);
475
- expect(await email_1.EmailMocker.broadcast.getFailedCount()).toBe(0);
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.broadcast.getSucceededEmail(0)).toMatchObject({
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.broadcast.getSucceededCount()).toBe(1);
517
- expect(await email_1.EmailMocker.broadcast.getFailedCount()).toBe(0);
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.broadcast.getSucceededEmail(0)).toMatchObject({
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.broadcast.getSucceededCount()).toBe(1);
560
- expect(await email_1.EmailMocker.broadcast.getFailedCount()).toBe(0);
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.broadcast.getSucceededEmail(0)).toMatchObject({
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.broadcast.getSucceededCount()).toBe(1);
601
- expect(await email_1.EmailMocker.broadcast.getFailedCount()).toBe(0);
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.broadcast.getSucceededEmail(0)).toMatchObject({
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.broadcast.getSucceededCount()).toBe(1);
649
- expect(await email_1.EmailMocker.broadcast.getFailedCount()).toBe(0);
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.broadcast.getSucceededEmail(0)).toMatchObject({
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.broadcast.getSucceededCount()).toBe(1);
698
- expect(await email_1.EmailMocker.broadcast.getFailedCount()).toBe(0);
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.broadcast.getSucceededEmail(0)).toMatchObject({
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.broadcast.getSucceededCount()).toBe(1);
740
- expect(await email_1.EmailMocker.broadcast.getFailedCount()).toBe(0);
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.broadcast.getSucceededEmail(0)).toMatchObject({
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