@stamhoofd/models 2.92.0 → 2.94.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.
Files changed (56) hide show
  1. package/dist/src/factories/RegistrationPeriodFactory.d.ts +1 -0
  2. package/dist/src/factories/RegistrationPeriodFactory.d.ts.map +1 -1
  3. package/dist/src/factories/RegistrationPeriodFactory.js +4 -0
  4. package/dist/src/factories/RegistrationPeriodFactory.js.map +1 -1
  5. package/dist/src/helpers/EmailBuilder.d.ts +1 -0
  6. package/dist/src/helpers/EmailBuilder.d.ts.map +1 -1
  7. package/dist/src/helpers/EmailBuilder.js +5 -3
  8. package/dist/src/helpers/EmailBuilder.js.map +1 -1
  9. package/dist/src/migrations/1755789797-email-counts-errors.sql +7 -0
  10. package/dist/src/migrations/1755789798-email-recipient-errors.sql +2 -0
  11. package/dist/src/migrations/1756115313-email-recipient-ids-and-errors.sql +10 -0
  12. package/dist/src/migrations/1756115314-email-recipient-email-optional.sql +2 -0
  13. package/dist/src/migrations/1756115315-email-recipients-count.sql +3 -0
  14. package/dist/src/migrations/1756115316-email-cached-counts.sql +4 -0
  15. package/dist/src/migrations/1756115317-email-deleted-at.sql +2 -0
  16. package/dist/src/migrations/1756293494-registration-period-next-period-id.sql +3 -0
  17. package/dist/src/migrations/1756293495-platform-next-period-id.sql +3 -0
  18. package/dist/src/models/Email.d.ts +62 -2
  19. package/dist/src/models/Email.d.ts.map +1 -1
  20. package/dist/src/models/Email.js +544 -198
  21. package/dist/src/models/Email.js.map +1 -1
  22. package/dist/src/models/Email.test.js +151 -43
  23. package/dist/src/models/Email.test.js.map +1 -1
  24. package/dist/src/models/EmailRecipient.d.ts +31 -1
  25. package/dist/src/models/EmailRecipient.d.ts.map +1 -1
  26. package/dist/src/models/EmailRecipient.js +53 -2
  27. package/dist/src/models/EmailRecipient.js.map +1 -1
  28. package/dist/src/models/Event.d.ts.map +1 -1
  29. package/dist/src/models/Event.js +2 -0
  30. package/dist/src/models/Event.js.map +1 -1
  31. package/dist/src/models/Platform.d.ts +1 -0
  32. package/dist/src/models/Platform.d.ts.map +1 -1
  33. package/dist/src/models/Platform.js +5 -0
  34. package/dist/src/models/Platform.js.map +1 -1
  35. package/dist/src/models/RegistrationPeriod.d.ts +3 -1
  36. package/dist/src/models/RegistrationPeriod.d.ts.map +1 -1
  37. package/dist/src/models/RegistrationPeriod.js +28 -7
  38. package/dist/src/models/RegistrationPeriod.js.map +1 -1
  39. package/package.json +2 -2
  40. package/src/factories/RegistrationPeriodFactory.ts +4 -0
  41. package/src/helpers/EmailBuilder.ts +6 -3
  42. package/src/migrations/1755789797-email-counts-errors.sql +7 -0
  43. package/src/migrations/1755789798-email-recipient-errors.sql +2 -0
  44. package/src/migrations/1756115313-email-recipient-ids-and-errors.sql +10 -0
  45. package/src/migrations/1756115314-email-recipient-email-optional.sql +2 -0
  46. package/src/migrations/1756115315-email-recipients-count.sql +3 -0
  47. package/src/migrations/1756115316-email-cached-counts.sql +4 -0
  48. package/src/migrations/1756115317-email-deleted-at.sql +2 -0
  49. package/src/migrations/1756293494-registration-period-next-period-id.sql +3 -0
  50. package/src/migrations/1756293495-platform-next-period-id.sql +3 -0
  51. package/src/models/Email.test.ts +165 -44
  52. package/src/models/Email.ts +620 -212
  53. package/src/models/EmailRecipient.ts +46 -2
  54. package/src/models/Event.ts +2 -0
  55. package/src/models/Platform.ts +4 -0
  56. package/src/models/RegistrationPeriod.ts +29 -7
@@ -4,6 +4,7 @@ import { v4 as uuidv4 } from 'uuid';
4
4
 
5
5
  import { ArrayDecoder } from '@simonbackx/simple-encoding';
6
6
  import { QueryableModel } from '@stamhoofd/sql';
7
+ import { SimpleErrors } from '@simonbackx/simple-errors';
7
8
 
8
9
  export class EmailRecipient extends QueryableModel {
9
10
  static table = 'email_recipients';
@@ -38,15 +39,58 @@ export class EmailRecipient extends QueryableModel {
38
39
  @column({ type: 'string', nullable: true })
39
40
  lastName: string | null = null;
40
41
 
41
- @column({ type: 'string' })
42
- email: string;
42
+ @column({ type: 'string', nullable: true })
43
+ email: string | null = null;
43
44
 
44
45
  @column({ type: 'json', decoder: new ArrayDecoder(Replacement) })
45
46
  replacements: Replacement[] = [];
46
47
 
48
+ /**
49
+ * @deprecated
50
+ * Legacy field
51
+ */
47
52
  @column({ type: 'string', nullable: true })
48
53
  failErrorMessage: string | null = null;
49
54
 
55
+ @column({ type: 'json', nullable: true, decoder: SimpleErrors })
56
+ failError: SimpleErrors | null = null;
57
+
58
+ @column({ type: 'string', nullable: true })
59
+ organizationId: string | null = null;
60
+
61
+ /**
62
+ * When set, the member will be ablse to see this message in the member portal.
63
+ */
64
+ @column({ type: 'string', nullable: true })
65
+ memberId: string | null = null;
66
+
67
+ /**
68
+ * When set, the user will be able to see this message in the member portal.
69
+ */
70
+ @column({ type: 'string', nullable: true })
71
+ userId: string | null = null;
72
+
73
+ /**
74
+ * Set when the email was send, but we received a hard bounce for this specific email
75
+ * Contains the full output we received in the bounce
76
+ */
77
+ @column({ type: 'string', nullable: true })
78
+ hardBounceError: string | null = null;
79
+
80
+ /**
81
+ * Set when the email was send, but we received a soft bounce for this specific email
82
+ * Contains the full output we received in the bounce
83
+ */
84
+ @column({ type: 'string', nullable: true })
85
+ softBounceError: string | null = null;
86
+
87
+ /**
88
+ * Set when the email was send, but was marked as spam.
89
+ * The error message contains any relevant info we received from our provider. E.g. type of spam (virus, fraud, abuse...)
90
+ */
91
+ @column({ type: 'string', nullable: true })
92
+ spamComplaintError: string | null = null;
93
+
50
94
  @column({ type: 'integer' })
51
95
  failCount = 0;
52
96
 
@@ -87,6 +87,8 @@ export class Event extends QueryableModel {
87
87
  group.settings.requireGroupIds = this.meta.groups?.map(g => g.id) ?? [];
88
88
  group.settings.startDate = this.startDate;
89
89
  group.settings.endDate = this.endDate;
90
+ group.settings.minAge = this.meta.minAge ?? null;
91
+ group.settings.maxAge = this.meta.maxAge ?? null;
90
92
 
91
93
  if (group.type === GroupType.EventRegistration) {
92
94
  // Don't change the name of the waiting list
@@ -25,6 +25,9 @@ export class Platform extends QueryableModel {
25
25
  @column({ type: 'string', nullable: true })
26
26
  previousPeriodId: string | null = null;
27
27
 
28
+ @column({ type: 'string', nullable: true })
29
+ nextPeriodId: string | null = null;
30
+
28
31
  @column({ type: 'string', nullable: true })
29
32
  membershipOrganizationId: string | null = null;
30
33
 
@@ -56,6 +59,7 @@ export class Platform extends QueryableModel {
56
59
  async setPreviousPeriodId() {
57
60
  const period = await RegistrationPeriod.getByID(this.periodId);
58
61
  this.previousPeriodId = period?.previousPeriodId ?? null;
62
+ this.nextPeriodId = period?.nextPeriodId ?? null;
59
63
  }
60
64
 
61
65
  static async getSharedPrivateStruct(): Promise<PlatformStruct & { privateConfig: PlatformPrivateConfig }> {
@@ -16,6 +16,9 @@ export class RegistrationPeriod extends QueryableModel {
16
16
  @column({ type: 'string', nullable: true })
17
17
  previousPeriodId: string | null = null;
18
18
 
19
+ @column({ type: 'string', nullable: true })
20
+ nextPeriodId: string | null = null;
21
+
19
22
  @column({ type: 'string', nullable: true })
20
23
  organizationId: string | null = null;
21
24
 
@@ -74,12 +77,25 @@ export class RegistrationPeriod extends QueryableModel {
74
77
  return RegistrationPeriod.fromRow(result[this.table]) ?? null;
75
78
  }
76
79
 
77
- async setPreviousPeriodId() {
78
- const allPeriods = await RegistrationPeriod.where({ organizationId: this.organizationId });
80
+ async updatePreviousNextPeriods() {
81
+ return await RegistrationPeriod.updatePreviousNextPeriods(this.organizationId, this);
82
+ }
83
+
84
+ static async updatePreviousNextPeriods(organizationId: string | null, existingReference?: RegistrationPeriod) {
85
+ const allPeriods = await RegistrationPeriod.select().where('organizationId', organizationId).fetch();
79
86
 
80
87
  // Include self if not yet in database
81
- if (!this.existsInDatabase) {
82
- allPeriods.push(this);
88
+ if (existingReference) {
89
+ if (!existingReference.existsInDatabase) {
90
+ allPeriods.push(existingReference);
91
+ }
92
+ else {
93
+ // Replace self with this
94
+ const index = allPeriods.findIndex(p => p.id === existingReference.id);
95
+ if (index !== -1) {
96
+ allPeriods[index] = existingReference;
97
+ }
98
+ }
83
99
  }
84
100
 
85
101
  // Sort by start date
@@ -89,12 +105,18 @@ export class RegistrationPeriod extends QueryableModel {
89
105
  let previousPeriod: RegistrationPeriod | null = null;
90
106
 
91
107
  for (const period of allPeriods) {
92
- if (period.id === this.id) {
93
- break;
108
+ period.previousPeriodId = previousPeriod?.id ?? null;
109
+ period.nextPeriodId = null;
110
+
111
+ if (previousPeriod) {
112
+ previousPeriod.nextPeriodId = period.id;
94
113
  }
95
114
  previousPeriod = period;
96
115
  }
97
116
 
98
- this.previousPeriodId = previousPeriod?.id ?? null;
117
+ // Save all
118
+ for (const period of allPeriods) {
119
+ await period.save();
120
+ }
99
121
  }
100
122
  }