@stamhoofd/models 2.121.0 → 2.122.1

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 (241) hide show
  1. package/dist/factories/GroupFactory.d.ts.map +1 -1
  2. package/dist/factories/GroupFactory.js +1 -1
  3. package/dist/factories/GroupFactory.js.map +1 -1
  4. package/dist/factories/OrganizationFactory.d.ts +2 -1
  5. package/dist/factories/OrganizationFactory.d.ts.map +1 -1
  6. package/dist/factories/OrganizationFactory.js +9 -1
  7. package/dist/factories/OrganizationFactory.js.map +1 -1
  8. package/dist/factories/STPackageFactory.js.map +1 -1
  9. package/dist/factories/UserFactory.d.ts.map +1 -1
  10. package/dist/factories/UserFactory.js +2 -2
  11. package/dist/factories/UserFactory.js.map +1 -1
  12. package/dist/helpers/EmailBuilder.d.ts.map +1 -1
  13. package/dist/helpers/EmailBuilder.js +8 -8
  14. package/dist/helpers/EmailBuilder.js.map +1 -1
  15. package/dist/helpers/Handlebars.d.ts.map +1 -1
  16. package/dist/helpers/Handlebars.js +7 -1
  17. package/dist/helpers/Handlebars.js.map +1 -1
  18. package/dist/index.d.ts +0 -1
  19. package/dist/index.d.ts.map +1 -1
  20. package/dist/index.js +0 -1
  21. package/dist/index.js.map +1 -1
  22. package/dist/migrations/1605262045-import-postcodes.d.ts.map +1 -1
  23. package/dist/migrations/1605262045-import-postcodes.js +58 -24
  24. package/dist/migrations/1605262045-import-postcodes.js.map +1 -1
  25. package/dist/migrations/1605262046-import-postcodes-nl.d.ts.map +1 -1
  26. package/dist/migrations/1605262046-import-postcodes-nl.js +54 -17
  27. package/dist/migrations/1605262046-import-postcodes-nl.js.map +1 -1
  28. package/dist/migrations/1719567881-organization-periodId.sql +2 -0
  29. package/dist/migrations/1719567882-groups-periodId.sql +2 -0
  30. package/dist/migrations/1720080975-convert-charset.d.ts +4 -0
  31. package/dist/migrations/1720080975-convert-charset.d.ts.map +1 -0
  32. package/dist/migrations/1720080975-convert-charset.js +26 -0
  33. package/dist/migrations/1720080975-convert-charset.js.map +1 -0
  34. package/dist/migrations/1720080976-convert-charset-leads.d.ts.map +1 -1
  35. package/dist/migrations/1720080976-convert-charset-leads.js +11 -10
  36. package/dist/migrations/1720080976-convert-charset-leads.js.map +1 -1
  37. package/dist/migrations/1721400546-users-memberId.sql +2 -0
  38. package/dist/migrations/1722269236-group-waitinglist-id.sql +2 -1
  39. package/dist/migrations/1722525785-balance-item-paying-organization-id.sql +2 -0
  40. package/dist/migrations/1722525787-depending-balance-item.sql +2 -0
  41. package/dist/migrations/1722963554-registration-group-price-and-options.sql +1 -1
  42. package/dist/migrations/1723652797-payments-paying-organization-id-fk.sql +2 -0
  43. package/dist/migrations/1733317908-added-missing-organization-fk-on-registrations.sql +2 -0
  44. package/dist/migrations/1733317910-paying-organization-id-fk.sql +2 -0
  45. package/dist/migrations/1733504881-negative-invoice-id.sql +6 -0
  46. package/dist/migrations/1733994455-balance-item-status-open.d.ts +4 -0
  47. package/dist/migrations/1733994455-balance-item-status-open.d.ts.map +1 -0
  48. package/dist/migrations/1733994455-balance-item-status-open.js +28 -0
  49. package/dist/migrations/1733994455-balance-item-status-open.js.map +1 -0
  50. package/dist/migrations/1769087808-corrected-invoice-user-agent.sql +2 -0
  51. package/dist/migrations/1769087809-payments-invoice-id.sql +2 -0
  52. package/dist/migrations/1772033555-balance-item-package-id.sql +2 -0
  53. package/dist/migrations/1778796615-payments-reversing-payment-id.sql +2 -0
  54. package/dist/migrations/1779443446-transfer-fees.sql +3 -0
  55. package/dist/migrations/1779709174-used-register-code-balance-item-id.sql +5 -0
  56. package/dist/migrations/1779968328-payments-admin-user-id.sql +5 -0
  57. package/dist/migrations/1779970611-payments-refunded-amount.sql +2 -0
  58. package/dist/migrations/1779972640-balance-items-failed-at.sql +2 -0
  59. package/dist/migrations/1780328285-document-template-locked.sql +2 -0
  60. package/dist/migrations/1780328286-document-locked.sql +2 -0
  61. package/dist/migrations/1780412083-documents-set-locked.d.ts +4 -0
  62. package/dist/migrations/1780412083-documents-set-locked.d.ts.map +1 -0
  63. package/dist/migrations/1780412083-documents-set-locked.js +14 -0
  64. package/dist/migrations/1780412083-documents-set-locked.js.map +1 -0
  65. package/dist/migrations/1780928401-v1-groups-migration-data.d.ts +4 -0
  66. package/dist/migrations/1780928401-v1-groups-migration-data.d.ts.map +1 -0
  67. package/dist/migrations/1780928401-v1-groups-migration-data.js +44 -0
  68. package/dist/migrations/1780928401-v1-groups-migration-data.js.map +1 -0
  69. package/dist/models/BalanceItem.d.ts +7 -2
  70. package/dist/models/BalanceItem.d.ts.map +1 -1
  71. package/dist/models/BalanceItem.js +41 -38
  72. package/dist/models/BalanceItem.js.map +1 -1
  73. package/dist/models/CachedBalance.d.ts +6 -1
  74. package/dist/models/CachedBalance.d.ts.map +1 -1
  75. package/dist/models/CachedBalance.js +3 -2
  76. package/dist/models/CachedBalance.js.map +1 -1
  77. package/dist/models/Document.d.ts +4 -0
  78. package/dist/models/Document.d.ts.map +1 -1
  79. package/dist/models/Document.js +26 -3
  80. package/dist/models/Document.js.map +1 -1
  81. package/dist/models/DocumentTemplate.d.ts +4 -0
  82. package/dist/models/DocumentTemplate.d.ts.map +1 -1
  83. package/dist/models/DocumentTemplate.js +37 -1
  84. package/dist/models/DocumentTemplate.js.map +1 -1
  85. package/dist/models/Email.d.ts.map +1 -1
  86. package/dist/models/Email.js +1 -1
  87. package/dist/models/Email.js.map +1 -1
  88. package/dist/models/EmailVerificationCode.d.ts.map +1 -1
  89. package/dist/models/EmailVerificationCode.js +3 -13
  90. package/dist/models/EmailVerificationCode.js.map +1 -1
  91. package/dist/models/Event.d.ts +2 -1
  92. package/dist/models/Event.d.ts.map +1 -1
  93. package/dist/models/Event.js +3 -0
  94. package/dist/models/Event.js.map +1 -1
  95. package/dist/models/EventNotification.d.ts.map +1 -1
  96. package/dist/models/EventNotification.js +5 -5
  97. package/dist/models/EventNotification.js.map +1 -1
  98. package/dist/models/Invoice.d.ts +1 -0
  99. package/dist/models/Invoice.d.ts.map +1 -1
  100. package/dist/models/Invoice.js +8 -0
  101. package/dist/models/Invoice.js.map +1 -1
  102. package/dist/models/MemberPlatformMembership.d.ts.map +1 -1
  103. package/dist/models/MemberPlatformMembership.js +9 -0
  104. package/dist/models/MemberPlatformMembership.js.map +1 -1
  105. package/dist/models/Order.d.ts.map +1 -1
  106. package/dist/models/Order.js +1 -0
  107. package/dist/models/Order.js.map +1 -1
  108. package/dist/models/Organization.d.ts +23 -25
  109. package/dist/models/Organization.d.ts.map +1 -1
  110. package/dist/models/Organization.js +92 -64
  111. package/dist/models/Organization.js.map +1 -1
  112. package/dist/models/PasswordToken.d.ts +5 -1
  113. package/dist/models/PasswordToken.d.ts.map +1 -1
  114. package/dist/models/PasswordToken.js +18 -17
  115. package/dist/models/PasswordToken.js.map +1 -1
  116. package/dist/models/Payment.d.ts +21 -2
  117. package/dist/models/Payment.d.ts.map +1 -1
  118. package/dist/models/Payment.js +43 -2
  119. package/dist/models/Payment.js.map +1 -1
  120. package/dist/models/Registration.d.ts.map +1 -1
  121. package/dist/models/Registration.js +3 -3
  122. package/dist/models/Registration.js.map +1 -1
  123. package/dist/models/STCredit.d.ts +4 -0
  124. package/dist/models/STCredit.d.ts.map +1 -1
  125. package/dist/models/STCredit.js +28 -0
  126. package/dist/models/STCredit.js.map +1 -1
  127. package/dist/models/STInvoice.d.ts +7 -1
  128. package/dist/models/STInvoice.d.ts.map +1 -1
  129. package/dist/models/STInvoice.js +9 -0
  130. package/dist/models/STInvoice.js.map +1 -1
  131. package/dist/models/STPackage.d.ts +4 -0
  132. package/dist/models/STPackage.d.ts.map +1 -1
  133. package/dist/models/STPackage.js +12 -1
  134. package/dist/models/STPackage.js.map +1 -1
  135. package/dist/models/UsedRegisterCode.d.ts +9 -0
  136. package/dist/models/UsedRegisterCode.d.ts.map +1 -1
  137. package/dist/models/UsedRegisterCode.js +31 -0
  138. package/dist/models/UsedRegisterCode.js.map +1 -1
  139. package/dist/models/_relations.js +25 -0
  140. package/dist/models/_relations.js.map +1 -1
  141. package/dist/models/addresses/City.d.ts +4 -4
  142. package/dist/models/addresses/City.d.ts.map +1 -1
  143. package/dist/models/addresses/City.js +6 -6
  144. package/dist/models/addresses/City.js.map +1 -1
  145. package/dist/models/addresses/PostalCode.d.ts +2 -2
  146. package/dist/models/addresses/PostalCode.d.ts.map +1 -1
  147. package/dist/models/addresses/PostalCode.js +4 -3
  148. package/dist/models/addresses/PostalCode.js.map +1 -1
  149. package/dist/models/addresses/Street.d.ts +3 -3
  150. package/dist/models/addresses/Street.d.ts.map +1 -1
  151. package/dist/models/addresses/Street.js +4 -4
  152. package/dist/models/addresses/Street.js.map +1 -1
  153. package/dist/models/index.d.ts +1 -0
  154. package/dist/models/index.d.ts.map +1 -1
  155. package/dist/models/index.js +1 -0
  156. package/dist/models/index.js.map +1 -1
  157. package/dist/models/v1GroupMigrationData.d.ts +22 -0
  158. package/dist/models/v1GroupMigrationData.d.ts.map +1 -0
  159. package/dist/models/v1GroupMigrationData.js +48 -0
  160. package/dist/models/v1GroupMigrationData.js.map +1 -0
  161. package/package.json +32 -13
  162. package/src/factories/GroupFactory.ts +4 -6
  163. package/src/factories/OrganizationFactory.ts +12 -4
  164. package/src/factories/STPackageFactory.ts +2 -2
  165. package/src/factories/UserFactory.ts +4 -5
  166. package/src/helpers/EmailBuilder.ts +19 -28
  167. package/src/helpers/Handlebars.ts +6 -1
  168. package/src/index.ts +0 -1
  169. package/src/migrations/1605262045-import-postcodes.ts +62 -25
  170. package/src/migrations/1605262046-import-postcodes-nl.ts +58 -17
  171. package/src/migrations/1719567881-organization-periodId.sql +2 -0
  172. package/src/migrations/1719567882-groups-periodId.sql +2 -0
  173. package/src/migrations/1720080975-convert-charset.ts +34 -0
  174. package/src/migrations/1720080976-convert-charset-leads.ts +16 -13
  175. package/src/migrations/1721400546-users-memberId.sql +2 -0
  176. package/src/migrations/1722269236-group-waitinglist-id.sql +2 -1
  177. package/src/migrations/1722525785-balance-item-paying-organization-id.sql +2 -0
  178. package/src/migrations/1722525787-depending-balance-item.sql +2 -0
  179. package/src/migrations/1722963554-registration-group-price-and-options.sql +1 -1
  180. package/src/migrations/1723652797-payments-paying-organization-id-fk.sql +2 -0
  181. package/src/migrations/1733317908-added-missing-organization-fk-on-registrations.sql +2 -0
  182. package/src/migrations/1733317910-paying-organization-id-fk.sql +2 -0
  183. package/src/migrations/1733504881-negative-invoice-id.sql +6 -0
  184. package/src/migrations/1733994455-balance-item-status-open.ts +30 -0
  185. package/src/migrations/1769087808-corrected-invoice-user-agent.sql +2 -0
  186. package/src/migrations/1769087809-payments-invoice-id.sql +2 -0
  187. package/src/migrations/1772033555-balance-item-package-id.sql +2 -0
  188. package/src/migrations/1778796615-payments-reversing-payment-id.sql +2 -0
  189. package/src/migrations/1779443446-transfer-fees.sql +3 -0
  190. package/src/migrations/1779709174-used-register-code-balance-item-id.sql +5 -0
  191. package/src/migrations/1779968328-payments-admin-user-id.sql +5 -0
  192. package/src/migrations/1779970611-payments-refunded-amount.sql +2 -0
  193. package/src/migrations/1779972640-balance-items-failed-at.sql +2 -0
  194. package/src/migrations/1780328285-document-template-locked.sql +2 -0
  195. package/src/migrations/1780328286-document-locked.sql +2 -0
  196. package/src/migrations/1780412083-documents-set-locked.ts +18 -0
  197. package/src/migrations/1780928401-v1-groups-migration-data.ts +50 -0
  198. package/src/models/BalanceItem.ts +44 -43
  199. package/src/models/CachedBalance.test.ts +46 -46
  200. package/src/models/CachedBalance.ts +7 -7
  201. package/src/models/Document.ts +34 -13
  202. package/src/models/DocumentTemplate.ts +56 -17
  203. package/src/models/Email.test.ts +3 -3
  204. package/src/models/Email.ts +28 -49
  205. package/src/models/EmailVerificationCode.ts +8 -22
  206. package/src/models/Event.ts +6 -4
  207. package/src/models/EventNotification.ts +6 -6
  208. package/src/models/Invoice.ts +9 -0
  209. package/src/models/MemberPlatformMembership.test.ts +70 -0
  210. package/src/models/MemberPlatformMembership.ts +16 -12
  211. package/src/models/Order.ts +14 -26
  212. package/src/models/Organization.ts +122 -93
  213. package/src/models/PasswordToken.ts +21 -21
  214. package/src/models/Payment.ts +42 -4
  215. package/src/models/Registration.ts +3 -3
  216. package/src/models/STCredit.ts +32 -0
  217. package/src/models/STInvoice.ts +11 -5
  218. package/src/models/STPackage.ts +19 -14
  219. package/src/models/UsedRegisterCode.ts +34 -0
  220. package/src/models/_relations.ts +29 -0
  221. package/src/models/addresses/City.ts +8 -6
  222. package/src/models/addresses/PostalCode.test.ts +1 -0
  223. package/src/models/addresses/PostalCode.ts +5 -3
  224. package/src/models/addresses/Street.ts +6 -4
  225. package/src/models/index.ts +2 -0
  226. package/src/models/v1GroupMigrationData.ts +43 -0
  227. package/dist/helpers/MemberMerger.d.ts +0 -14
  228. package/dist/helpers/MemberMerger.d.ts.map +0 -1
  229. package/dist/helpers/MemberMerger.js +0 -364
  230. package/dist/helpers/MemberMerger.js.map +0 -1
  231. package/dist/migrations/1720080975-convert-charset.sql +0 -85
  232. package/dist/migrations/1723202126-member-number-index.sql +0 -2
  233. package/dist/models/OneTimeToken.d.ts +0 -38
  234. package/dist/models/OneTimeToken.d.ts.map +0 -1
  235. package/dist/models/OneTimeToken.js +0 -125
  236. package/dist/models/OneTimeToken.js.map +0 -1
  237. package/src/helpers/MemberMerger.test.ts +0 -782
  238. package/src/helpers/MemberMerger.ts +0 -577
  239. package/src/migrations/1720080975-convert-charset.sql +0 -85
  240. package/src/migrations/1723202126-member-number-index.sql +0 -2
  241. package/src/models/OneTimeToken.ts +0 -133
@@ -1,7 +1,7 @@
1
1
  import type { EmailBuilder, EmailInterfaceRecipient } from '@stamhoofd/email';
2
2
  import { Email, EmailAddress } from '@stamhoofd/email';
3
- import type { EmailRecipient as EmailRecipientStruct, EmailTemplateType, OrganizationEmail, Platform as PlatformStruct, Recipient} from '@stamhoofd/structures';
4
- import { BalanceItem as BalanceItemStruct, ReceivableBalanceType, replaceEmailHtml, replaceEmailText, Replacement } from '@stamhoofd/structures';
3
+ import type { EmailRecipient as EmailRecipientStruct, EmailTemplateType, OrganizationEmail, Platform as PlatformStruct, Recipient } from '@stamhoofd/structures';
4
+ import { BalanceItem as BalanceItemStruct, getAppHost, ReceivableBalanceType, replaceEmailHtml, replaceEmailText, Replacement } from '@stamhoofd/structures';
5
5
  import { Formatter } from '@stamhoofd/utility';
6
6
 
7
7
  import { SimpleError } from '@simonbackx/simple-errors';
@@ -13,7 +13,7 @@ import type { Group } from '../models/Group.js';
13
13
  import type { Organization } from '../models/Organization.js';
14
14
  import { Platform } from '../models/Platform.js';
15
15
  import { User } from '../models/User.js';
16
- import type {Webshop} from '../models/Webshop.js';
16
+ import type { Webshop } from '../models/Webshop.js';
17
17
 
18
18
  export type EmailTemplateOptions = {
19
19
  type: EmailTemplateType;
@@ -314,8 +314,7 @@ export async function getEmailBuilder(organization: Organization | null, email:
314
314
  'List-Unsubscribe-Post': 'List-Unsubscribe=One-Click',
315
315
  };
316
316
  cleaned.push(recipient);
317
- }
318
- catch (e) {
317
+ } catch (e) {
319
318
  console.error(e);
320
319
  }
321
320
  }
@@ -499,14 +498,14 @@ export function stripSensitiveRecipientReplacements(recipient: Recipient | Email
499
498
  }
500
499
 
501
500
  // Add dummy unsubscribeUrl
502
- const dummyUnsubscribeUrl = 'https://' + (organization && STAMHOOFD.userMode === 'organization' ? organization.getHost() : STAMHOOFD.domains.dashboard) + '/unsubscribe?token=example';
501
+ const dummyUnsubscribeUrl = 'https://' + (organization && STAMHOOFD.userMode === 'organization' ? getAppHost('registration', organization, false) : STAMHOOFD.domains.dashboard) + '/unsubscribe?token=example';
503
502
  recipient.replacements.push(Replacement.create({
504
503
  token: 'unsubscribeUrl',
505
504
  value: dummyUnsubscribeUrl,
506
505
  }));
507
506
 
508
507
  // dummy signInUrl
509
- const dummySignInUrl = 'https://' + (organization && STAMHOOFD.userMode === 'organization' ? organization.getHost() : STAMHOOFD.domains.dashboard) + '/login';
508
+ const dummySignInUrl = 'https://' + (organization && STAMHOOFD.userMode === 'organization' ? getAppHost('registration', organization, false) : STAMHOOFD.domains.dashboard) + '/login';
510
509
  recipient.replacements.push(Replacement.create({
511
510
  token: 'signInUrl',
512
511
  value: dummySignInUrl,
@@ -536,7 +535,7 @@ export function stripRecipientReplacementsForWebDisplay(recipient: Recipient | E
536
535
  recipient.replacements = recipient.replacements.filter(r => r.token !== 'unsubscribeUrl' && r.token !== 'loginDetails' && r.token !== 'greeting');
537
536
 
538
537
  // Add dummy unsubscribeUrl
539
- const dummyUnsubscribeUrl = 'https://' + (organization && STAMHOOFD.userMode === 'organization' ? organization.getHost() : STAMHOOFD.domains.dashboard);
538
+ const dummyUnsubscribeUrl = 'https://' + (organization && STAMHOOFD.userMode === 'organization' ? getAppHost('registration', organization, false) : STAMHOOFD.domains.dashboard);
540
539
  recipient.replacements.push(Replacement.create({
541
540
  token: 'unsubscribeUrl',
542
541
  value: dummyUnsubscribeUrl,
@@ -575,7 +574,7 @@ export async function fillRecipientReplacements(recipient: Recipient | EmailReci
575
574
  }
576
575
 
577
576
  if (!recipient.email && !recipient.userId) {
578
- const signInUrl = 'https://' + (organization && STAMHOOFD.userMode === 'organization' ? organization.getHost() : STAMHOOFD.domains.dashboard) + '/login';
577
+ const signInUrl = 'https://' + (organization && STAMHOOFD.userMode === 'organization' ? getAppHost('registration', organization, false) : STAMHOOFD.domains.dashboard) + '/login';
579
578
  recipient.replacements.push(Replacement.create({
580
579
  token: 'signInUrl',
581
580
  value: signInUrl,
@@ -587,8 +586,7 @@ export async function fillRecipientReplacements(recipient: Recipient | EmailReci
587
586
  value: '',
588
587
  }));
589
588
  }
590
- }
591
- else {
589
+ } else {
592
590
  // Default signInUrl
593
591
  recipientUser = recipient.userId ? await User.select().where('id', recipient.userId).first(false) : await User.getForAuthentication(organization?.id ?? null, recipient.email!, { allowWithoutAccount: true });
594
592
  if (STAMHOOFD.userMode !== 'platform' && recipientUser && recipientUser.organizationId && recipientUser.organizationId !== (organization?.id ?? null)) {
@@ -600,14 +598,12 @@ export async function fillRecipientReplacements(recipient: Recipient | EmailReci
600
598
  if (!recipientUser || !recipientUser.hasAccount()) {
601
599
  // We can create a special token
602
600
  if (recipientUser) {
603
- signInUrl = 'https://' + (organization && STAMHOOFD.userMode === 'organization' ? organization.getHost() : STAMHOOFD.domains.dashboard) + '/account-aanmaken?email=' + encodeURIComponent(recipientUser?.email);
604
- }
605
- else {
606
- signInUrl = 'https://' + (organization && STAMHOOFD.userMode === 'organization' ? organization.getHost() : STAMHOOFD.domains.dashboard) + '/account-aanmaken';
601
+ signInUrl = 'https://' + (organization && STAMHOOFD.userMode === 'organization' ? getAppHost('registration', organization, false) : STAMHOOFD.domains.dashboard) + '/account-aanmaken?email=' + encodeURIComponent(recipientUser?.email);
602
+ } else {
603
+ signInUrl = 'https://' + (organization && STAMHOOFD.userMode === 'organization' ? getAppHost('registration', organization, false) : STAMHOOFD.domains.dashboard) + '/account-aanmaken';
607
604
  }
608
- }
609
- else {
610
- signInUrl = 'https://' + (organization && STAMHOOFD.userMode === 'organization' ? organization.getHost() : STAMHOOFD.domains.dashboard) + '/login?email=' + encodeURIComponent(recipientUser.email);
605
+ } else {
606
+ signInUrl = 'https://' + (organization && STAMHOOFD.userMode === 'organization' ? getAppHost('registration', organization, false) : STAMHOOFD.domains.dashboard) + '/login?email=' + encodeURIComponent(recipientUser.email);
611
607
  }
612
608
 
613
609
  recipient.replacements.push(Replacement.create({
@@ -638,8 +634,7 @@ export async function fillRecipientReplacements(recipient: Recipient | EmailReci
638
634
  }),
639
635
  );
640
636
  }
641
- }
642
- else {
637
+ } else {
643
638
  console.log('No member found for user', recipientUser.id);
644
639
  }
645
640
  }
@@ -653,8 +648,7 @@ export async function fillRecipientReplacements(recipient: Recipient | EmailReci
653
648
  : `<p class="description"><em>${$t('%1EB', { email: emailEscaped })}${suffix}</em></p>`,
654
649
  }),
655
650
  );
656
- }
657
- else {
651
+ } else {
658
652
  if (recipient.email) {
659
653
  const emailEscaped = `<strong>${Formatter.escapeHtml(recipient.email)}</strong>`;
660
654
  console.log('No user found for email', recipient.email);
@@ -665,8 +659,7 @@ export async function fillRecipientReplacements(recipient: Recipient | EmailReci
665
659
  html: `<p class="description"><em>${$t('%1EB', { email: emailEscaped })}</em></p>`,
666
660
  }),
667
661
  );
668
- }
669
- else {
662
+ } else {
670
663
  recipient.replacements.push(
671
664
  Replacement.create({
672
665
  token: 'loginDetails',
@@ -702,8 +695,7 @@ export async function fillRecipientReplacements(recipient: Recipient | EmailReci
702
695
  html: BalanceItemStruct.getDetailsHTMLTable(balanceItems),
703
696
  }),
704
697
  );
705
- }
706
- else {
698
+ } else {
707
699
  recipient.replacements.push(
708
700
  Replacement.create({
709
701
  token: 'outstandingBalance',
@@ -739,8 +731,7 @@ export async function fillRecipientReplacements(recipient: Recipient | EmailReci
739
731
 
740
732
  if (recipient instanceof EmailRecipient) {
741
733
  recipient.replacements.push(...recipient.getRecipient().getDefaultReplacements());
742
- }
743
- else {
734
+ } else {
744
735
  recipient.replacements.push(...recipient.getDefaultReplacements());
745
736
  }
746
737
 
@@ -50,7 +50,12 @@ class AsyncResolver {
50
50
 
51
51
  Handlebars.registerHelper('eq', (a, b) => a == b);
52
52
  Handlebars.registerHelper('neq', (a, b) => a !== b);
53
- Handlebars.registerHelper('formatPrice', a => typeof a === 'number' ? Formatter.price(a) : a);
53
+ Handlebars.registerHelper('formatPrice', (a, options) => {
54
+ if (typeof a !== 'number') return a;
55
+ // round=true rounds to nearest cent (100 units = 1 cent, where 10000 units = €1)
56
+ const value = options?.hash?.round ? Math.round(a / 100) * 100 : a;
57
+ return Formatter.price(value);
58
+ });
54
59
  Handlebars.registerHelper('formatDate', (a, options) => {
55
60
  if (!(a instanceof Date)) {
56
61
  return '';
package/src/index.ts CHANGED
@@ -1,6 +1,5 @@
1
1
  // Helpers
2
2
  export * from './helpers/EmailBuilder.js';
3
- export * from './helpers/MemberMerger.js';
4
3
  export * from './helpers/RateLimiter.js';
5
4
  export * from './helpers/WebshopCounter.js';
6
5
 
@@ -1,7 +1,8 @@
1
- import { column, Migration } from '@simonbackx/simple-database';
1
+ import { column, Database, Migration } from '@simonbackx/simple-database';
2
2
  import { QueryableModel } from '@stamhoofd/sql';
3
3
  import { Country } from '@stamhoofd/types/Country';
4
4
  import { StringCompare } from '@stamhoofd/utility';
5
+ import { v4 as uuidv4 } from 'uuid';
5
6
  import { City } from '../models/addresses/City.js';
6
7
  import { PostalCode } from '../models/addresses/PostalCode.js';
7
8
  import { Province } from '../models/addresses/Province.js';
@@ -33,16 +34,17 @@ export class Gemeente extends QueryableModel {
33
34
  city!: City;
34
35
  }
35
36
 
36
- async function getProvince(name: string, provinces: Province[]): Promise<Province> {
37
+ function getProvince(name: string, provinces: Province[], provinceRows: string[][]): Province {
37
38
  const p = provinces.find(p => StringCompare.typoCount(p.name, name) < 2 && p.country == Country.Belgium);
38
39
  if (p) {
39
40
  return p;
40
41
  }
41
42
  const province = new Province();
43
+ province.id = uuidv4();
42
44
  province.country = Country.Belgium;
43
45
  province.name = name.trim();
44
- await province.save();
45
46
  provinces.push(province);
47
+ provinceRows.push([province.id, province.name, province.country]);
46
48
  return province;
47
49
  }
48
50
 
@@ -54,42 +56,38 @@ export default new Migration(async () => {
54
56
  // Loop all gemeenten
55
57
  const provinces = await Province.all();
56
58
  const gemeenten = await Gemeente.all();
57
- const cities: City[] = [];
59
+ const citiesByNameAndProvince = new Map<string, City>();
60
+ const provinceRows: string[][] = [];
61
+ const cityRows: unknown[][] = [];
62
+ const postalCodeRows: string[][] = [];
63
+ const parentCityUpdates = new Map<string, string>();
58
64
 
59
65
  for (const gemeente of gemeenten) {
60
- const province = await getProvince(gemeente.provincie, provinces);
66
+ const province = getProvince(gemeente.provincie, provinces, provinceRows);
61
67
 
62
68
  // Some cities have the same name
63
- const found = cities.find(c => c.name.trim() == gemeente.gemeente.trim() && c.provinceId == province.id);
69
+ const found = citiesByNameAndProvince.get(cityKey(gemeente.gemeente, province.id));
64
70
 
65
71
  if (!found) {
66
72
  // Create the city
67
73
  const city = new City();
74
+ city.id = uuidv4();
68
75
  city.name = gemeente.gemeente.trim();
69
76
  city.country = Country.Belgium;
70
77
  city.provinceId = province.id;
71
-
72
- await city.save();
78
+ cityRows.push([city.id, city.name, city.provinceId, city.parentCityId, city.country]);
73
79
 
74
80
  // Also add postal code already
75
- const postalCode = new PostalCode();
76
- postalCode.postalCode = gemeente.postcode;
77
- postalCode.cityId = city.id;
78
- postalCode.country = Country.Belgium;
79
- await postalCode.save();
81
+ postalCodeRows.push([uuidv4(), gemeente.postcode, city.id, Country.Belgium]);
80
82
 
81
83
  gemeente.city = city;
82
- cities.push(city);
84
+ citiesByNameAndProvince.set(cityKey(city.name, city.provinceId), city);
83
85
  }
84
86
  else {
85
87
  gemeente.city = found;
86
88
 
87
89
  // Also add postal code already
88
- const postalCode = new PostalCode();
89
- postalCode.postalCode = gemeente.postcode;
90
- postalCode.cityId = found.id;
91
- postalCode.country = Country.Belgium;
92
- await postalCode.save();
90
+ postalCodeRows.push([uuidv4(), gemeente.postcode, found.id, Country.Belgium]);
93
91
  }
94
92
  }
95
93
 
@@ -98,28 +96,67 @@ export default new Migration(async () => {
98
96
  continue;
99
97
  }
100
98
 
101
- const hoofd = cities.find(c => c.name.trim() == gemeente.hoofdgemeente.trim() && c.provinceId == gemeente.city.provinceId);
99
+ const hoofd = citiesByNameAndProvince.get(cityKey(gemeente.hoofdgemeente, gemeente.city.provinceId));
102
100
  if (!hoofd) {
103
101
  // Create the city
104
102
  const city = new City();
103
+ city.id = uuidv4();
105
104
  city.name = gemeente.hoofdgemeente.trim();
106
105
  city.country = Country.Belgium;
107
106
 
108
- const province = await getProvince(gemeente.provincie, provinces);
107
+ const province = getProvince(gemeente.provincie, provinces, provinceRows);
109
108
  city.provinceId = province.id;
110
- await city.save();
109
+ cityRows.push([city.id, city.name, city.provinceId, city.parentCityId, city.country]);
111
110
 
112
- cities.push(city);
111
+ citiesByNameAndProvince.set(cityKey(city.name, city.provinceId), city);
113
112
  // do not create a postal code here, these don't have one
114
113
 
115
114
  // console.log('Assigning ' + gemeente.gemeente + ' to ' + city.name);
116
115
  gemeente.city.parentCityId = city.id;
117
- await gemeente.city.save();
116
+ parentCityUpdates.set(gemeente.city.id, city.id);
118
117
  }
119
118
  else {
120
119
  // console.log('Assigning ' + gemeente.gemeente + ' to ' + hoofd.name);
121
120
  gemeente.city.parentCityId = hoofd.id;
122
- await gemeente.city.save();
121
+ parentCityUpdates.set(gemeente.city.id, hoofd.id);
123
122
  }
124
123
  }
124
+
125
+ await insertRows(Province.table, ['id', 'name', 'country'], provinceRows);
126
+ await insertRows(City.table, ['id', 'name', 'provinceId', 'parentCityId', 'country'], cityRows);
127
+ await insertRows(PostalCode.table, ['id', 'postalCode', 'cityId', 'country'], postalCodeRows);
128
+ await updateParentCityIds([...parentCityUpdates.entries()]);
125
129
  });
130
+ function cityKey(name: string, provinceId: string): string {
131
+ return `${name.trim()}\0${provinceId}`;
132
+ }
133
+
134
+ async function insertRows(table: string, columns: string[], rows: unknown[][]): Promise<void> {
135
+ for (const chunk of chunks(rows, 1000)) {
136
+ if (chunk.length === 0) {
137
+ continue;
138
+ }
139
+ await Database.insert(`INSERT INTO \`${table}\` (${columns.map(column => `\`${column}\``).join(', ')}) VALUES ?`, [chunk]);
140
+ }
141
+ }
142
+
143
+ async function updateParentCityIds(rows: string[][]): Promise<void> {
144
+ for (const chunk of chunks(rows, 1000)) {
145
+ if (chunk.length === 0) {
146
+ continue;
147
+ }
148
+ const cases = chunk.map(() => 'WHEN ? THEN ?').join(' ');
149
+ await Database.statement(`UPDATE \`${City.table}\` SET \`parentCityId\` = CASE \`id\` ${cases} END WHERE \`id\` IN (?)`, [
150
+ ...chunk.flatMap(([cityId, parentCityId]) => [cityId, parentCityId]),
151
+ chunk.map(([cityId]) => cityId),
152
+ ]);
153
+ }
154
+ }
155
+
156
+ function chunks<T>(values: T[], size: number): T[][] {
157
+ const result: T[][] = [];
158
+ for (let index = 0; index < values.length; index += size) {
159
+ result.push(values.slice(index, index + size));
160
+ }
161
+ return result;
162
+ }
@@ -1,39 +1,42 @@
1
- import { Migration } from '@simonbackx/simple-database';
1
+ import { Database, Migration } from '@simonbackx/simple-database';
2
2
  import { Country } from '@stamhoofd/types/Country';
3
3
  import { StringCompare } from '@stamhoofd/utility';
4
4
  import fs from 'fs';
5
5
  import readline from 'readline';
6
+ import { v4 as uuidv4 } from 'uuid';
6
7
 
7
8
  import { City } from '../models/addresses/City.js';
8
9
  import { PostalCode } from '../models/addresses/PostalCode.js';
9
10
  import { Province } from '../models/addresses/Province.js';
10
11
 
11
- async function getProvince(name: string, provinces: Province[]): Promise<Province> {
12
+ function getProvince(name: string, provinces: Province[], provinceRows: string[][]): Province {
12
13
  const p = provinces.find(p => StringCompare.typoCount(p.name, name) == 0 && p.country == Country.Netherlands);
13
14
  if (p) {
14
15
  return p;
15
16
  }
16
17
  const province = new Province();
18
+ province.id = uuidv4();
17
19
  province.country = Country.Netherlands;
18
20
  province.name = name;
19
- await province.save();
20
21
 
21
22
  provinces.push(province);
23
+ provinceRows.push([province.id, province.name, province.country]);
22
24
  return province;
23
25
  }
24
26
 
25
- async function getCity(name: string, provinceId: string, cities: City[]): Promise<City> {
26
- const p = cities.find(p => StringCompare.typoCount(p.name, name) == 0 && p.country == Country.Netherlands);
27
+ function getCity(name: string, provinceId: string, citiesByName: Map<string, City>, cityRows: unknown[][]): City {
28
+ const p = citiesByName.get(normalizeCityName(name));
27
29
  if (p) {
28
30
  return p;
29
31
  }
30
32
  const city = new City();
33
+ city.id = uuidv4();
31
34
  city.name = name;
32
35
  city.country = Country.Netherlands;
33
36
  city.provinceId = provinceId;
34
- await city.save();
37
+ cityRows.push([city.id, city.name, city.provinceId, city.parentCityId, city.country]);
35
38
 
36
- cities.push(city);
39
+ citiesByName.set(normalizeCityName(city.name), city);
37
40
  return city;
38
41
  }
39
42
 
@@ -52,11 +55,15 @@ export default new Migration(async () => {
52
55
  });
53
56
 
54
57
  const allProvinces = await Province.where({ country: Country.Netherlands });
58
+ const provinceRows: string[][] = [];
59
+ const cityRows: unknown[][] = [];
60
+ const postalCodeRows: string[][] = [];
61
+ const parentCityUpdates: string[][] = [];
55
62
 
56
63
  for (const p of provinces) {
57
64
  // console.log(p.name);
58
65
 
59
- const province = await getProvince(p.name.trim(), allProvinces);
66
+ const province = getProvince(p.name.trim(), allProvinces, provinceRows);
60
67
 
61
68
  // const cities = await fs.readFile(p.path, { encoding: "utf-8" });
62
69
 
@@ -64,7 +71,7 @@ export default new Migration(async () => {
64
71
  input: fs.createReadStream(p.path, { encoding: 'utf-8' }),
65
72
  });
66
73
 
67
- const cities: City[] = [];
74
+ const citiesByName = new Map<string, City>();
68
75
 
69
76
  for await (const line of lineReader) {
70
77
  const splitted = line.split('\t');
@@ -77,19 +84,53 @@ export default new Migration(async () => {
77
84
  const plaats = splitted[2].trim();
78
85
 
79
86
  // Check plaats and gemeente
80
- const city = await getCity(plaats, province.id, cities);
81
- const city2 = await getCity(gemeente, province.id, cities); // might be the same as city
87
+ const city = getCity(plaats, province.id, citiesByName, cityRows);
88
+ const city2 = getCity(gemeente, province.id, citiesByName, cityRows); // might be the same as city
82
89
  if (city2.id !== city.id && city.parentCityId === null) {
83
90
  city.parentCityId = city2.id;
84
- await city.save();
91
+ parentCityUpdates.push([city.id, city2.id]);
85
92
  }
86
93
 
87
94
  // Also add postal code already
88
- const postalCode = new PostalCode();
89
- postalCode.postalCode = postcode;
90
- postalCode.cityId = city.id;
91
- postalCode.country = Country.Netherlands;
92
- await postalCode.save();
95
+ postalCodeRows.push([uuidv4(), postcode, city.id, Country.Netherlands]);
93
96
  }
94
97
  }
98
+
99
+ await insertRows(Province.table, ['id', 'name', 'country'], provinceRows);
100
+ await insertRows(City.table, ['id', 'name', 'provinceId', 'parentCityId', 'country'], cityRows);
101
+ await insertRows(PostalCode.table, ['id', 'postalCode', 'cityId', 'country'], postalCodeRows);
102
+ await updateParentCityIds(parentCityUpdates);
95
103
  });
104
+ function normalizeCityName(name: string): string {
105
+ return name.normalize('NFD').replace(/[\u0300-\u036f]/g, '').toLowerCase().replace(/\s+/, ' ').trim();
106
+ }
107
+
108
+ async function insertRows(table: string, columns: string[], rows: unknown[][]): Promise<void> {
109
+ for (const chunk of chunks(rows, 1000)) {
110
+ if (chunk.length === 0) {
111
+ continue;
112
+ }
113
+ await Database.insert(`INSERT INTO \`${table}\` (${columns.map(column => `\`${column}\``).join(', ')}) VALUES ?`, [chunk]);
114
+ }
115
+ }
116
+
117
+ async function updateParentCityIds(rows: string[][]): Promise<void> {
118
+ for (const chunk of chunks(rows, 1000)) {
119
+ if (chunk.length === 0) {
120
+ continue;
121
+ }
122
+ const cases = chunk.map(() => 'WHEN ? THEN ?').join(' ');
123
+ await Database.statement(`UPDATE \`${City.table}\` SET \`parentCityId\` = CASE \`id\` ${cases} END WHERE \`id\` IN (?)`, [
124
+ ...chunk.flatMap(([cityId, parentCityId]) => [cityId, parentCityId]),
125
+ chunk.map(([cityId]) => cityId),
126
+ ]);
127
+ }
128
+ }
129
+
130
+ function chunks<T>(values: T[], size: number): T[][] {
131
+ const result: T[][] = [];
132
+ for (let index = 0; index < values.length; index += size) {
133
+ result.push(values.slice(index, index + size));
134
+ }
135
+ return result;
136
+ }
@@ -1,2 +1,4 @@
1
+ SET FOREIGN_KEY_CHECKS=0;
1
2
  ALTER TABLE `organizations` ADD COLUMN `periodId` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL;
2
3
  ALTER TABLE `organizations` ADD FOREIGN KEY (`periodId`) REFERENCES `registration_periods` (`id`) ON UPDATE CASCADE ON DELETE RESTRICT;
4
+ SET FOREIGN_KEY_CHECKS=1;
@@ -1,2 +1,4 @@
1
+ SET FOREIGN_KEY_CHECKS=0;
1
2
  ALTER TABLE `groups` ADD COLUMN `periodId` varchar(36) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NULL;
2
3
  ALTER TABLE `groups` ADD FOREIGN KEY (`periodId`) REFERENCES `registration_periods` (`id`) ON UPDATE CASCADE ON DELETE RESTRICT;
4
+ SET FOREIGN_KEY_CHECKS=1;
@@ -0,0 +1,34 @@
1
+ import { Database, Migration } from '@simonbackx/simple-database';
2
+ import { LoggingTools } from '@stamhoofd/utility';
3
+
4
+ export default new Migration(async () => {
5
+ process.stdout.write('\n');
6
+
7
+ if (STAMHOOFD.userMode === 'platform' && (STAMHOOFD.environment === 'production' || STAMHOOFD.environment === 'staging')) {
8
+ console.log('Skipped convert charset for userMode platform in production.');
9
+ return;
10
+ }
11
+
12
+ const tables = ['_members_users', 'balance_item_payments', 'balance_items', 'buckaroo_payments', 'cities', 'document_templates', 'documents', 'email_templates', 'email_verification_codes', 'groups', 'images', 'members', 'migrations', 'mollie_payments', 'mollie_tokens', 'organization_registration_periods', 'organizations', 'password_tokens', 'payconiq_payments', 'payments', 'platform', 'postal_codes', 'provinces', 'register_codes', 'registration_periods', 'registrations', 'stamhoofd_credits', 'stamhoofd_invoices', 'stamhoofd_packages', 'stamhoofd_pending_invoices', 'streets', 'stripe_accounts', 'stripe_checkout_sessions', 'stripe_payment_intents', 'tokens', 'used_register_codes', 'users', 'webshop_discount_codes', 'webshop_orders', 'webshop_tickets', 'webshops'];
13
+
14
+ const progressLogger = LoggingTools.createProgressLogger(tables.length, { tag: 'convert tables charset' });
15
+
16
+ for (const table of tables) {
17
+ await convertTable(table);
18
+ progressLogger.update();
19
+ }
20
+
21
+ console.log('Start set database charset.');
22
+ await Database.statement('ALTER DATABASE CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;');
23
+ });
24
+
25
+ async function convertTable(name: string): Promise<void> {
26
+ await Database.beginTransaction(async () => {
27
+ await Database.statement('set foreign_key_checks=0;');
28
+
29
+ console.log('Start converting charset of table: ' + name);
30
+ await Database.statement('ALTER TABLE `' + name + '` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;');
31
+
32
+ await Database.statement('set foreign_key_checks=1;');
33
+ });
34
+ }
@@ -3,14 +3,14 @@ import { Database, Migration } from '@simonbackx/simple-database';
3
3
  /**
4
4
  * If the charset of the leads table is not converted this results
5
5
  * in foreign keys constraint errors in other migrations.
6
- *
6
+ *
7
7
  * todo: will we keep the leads table after the migration?
8
8
  */
9
9
  export default new Migration(async () => {
10
10
  process.stdout.write('\n');
11
11
 
12
- if (STAMHOOFD.userMode === 'platform') {
13
- console.log('Skipped update leads charset for userMode platform.')
12
+ if (STAMHOOFD.userMode === 'platform' && (STAMHOOFD.environment === 'production' || STAMHOOFD.environment === 'staging')) {
13
+ console.log('Skipped update leads charset for userMode platform in production.');
14
14
  return Promise.resolve();
15
15
  }
16
16
 
@@ -18,15 +18,7 @@ export default new Migration(async () => {
18
18
  console.log('Has leads table: ' + hasTable);
19
19
 
20
20
  if (hasTable) {
21
- const sqlStatement: string = [
22
- 'set foreign_key_checks=0;',
23
- 'ALTER TABLE `leads` CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;',
24
- 'ALTER TABLE `leads` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;',
25
- 'set foreign_key_checks=1;'
26
- ].join('');
27
-
28
- console.log('Start updating charset of leads table.');
29
- await Database.statement(sqlStatement);
21
+ await convertTable('leads');
30
22
  }
31
23
 
32
24
  return Promise.resolve();
@@ -40,7 +32,7 @@ async function tableExists(tableName: string): Promise<boolean> {
40
32
  WHERE table_schema = DATABASE()
41
33
  AND table_name = ?
42
34
  `,
43
- [tableName]
35
+ [tableName],
44
36
  );
45
37
 
46
38
  const count = rows[0]['']['count'];
@@ -51,3 +43,14 @@ async function tableExists(tableName: string): Promise<boolean> {
51
43
 
52
44
  return count > 0;
53
45
  }
46
+
47
+ async function convertTable(name: string): Promise<void> {
48
+ await Database.beginTransaction(async () => {
49
+ await Database.statement('set foreign_key_checks=0;');
50
+
51
+ console.log('Start converting charset of table: ' + name);
52
+ await Database.statement('ALTER TABLE `' + name + '` CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;');
53
+
54
+ await Database.statement('set foreign_key_checks=1;');
55
+ });
56
+ }
@@ -1,3 +1,5 @@
1
+ SET FOREIGN_KEY_CHECKS=0;
1
2
  ALTER TABLE `users`
2
3
  ADD COLUMN `memberId` varchar(36) NULL AFTER `id`;
3
4
  ALTER TABLE `users` ADD FOREIGN KEY (`memberId`) REFERENCES `members` (`id`) ON UPDATE CASCADE ON DELETE SET NULL;
5
+ SET FOREIGN_KEY_CHECKS=1;
@@ -1,4 +1,5 @@
1
+ SET FOREIGN_KEY_CHECKS=0;
1
2
  ALTER TABLE `groups`
2
3
  ADD COLUMN `waitingListId` varchar(36) NULL AFTER `defaultAgeGroupId`;
3
-
4
4
  ALTER TABLE `groups` ADD FOREIGN KEY (`waitingListId`) REFERENCES `groups` (`id`) ON UPDATE CASCADE ON DELETE SET NULL;
5
+ SET FOREIGN_KEY_CHECKS=1;
@@ -1,2 +1,4 @@
1
+ SET FOREIGN_KEY_CHECKS=0;
1
2
  ALTER TABLE `balance_items` ADD COLUMN `payingOrganizationId` varchar(36) NULL;
2
3
  ALTER TABLE `balance_items` ADD FOREIGN KEY (`payingOrganizationId`) REFERENCES `organizations` (`id`) ON UPDATE CASCADE ON DELETE SET NULL;
4
+ SET FOREIGN_KEY_CHECKS=1;
@@ -1,2 +1,4 @@
1
+ SET FOREIGN_KEY_CHECKS=0;
1
2
  ALTER TABLE `balance_items` ADD COLUMN `dependingBalanceItemId` varchar(36) NULL;
2
3
  ALTER TABLE `balance_items` ADD FOREIGN KEY (`dependingBalanceItemId`) REFERENCES `balance_items` (`id`) ON UPDATE CASCADE ON DELETE SET NULL;
4
+ SET FOREIGN_KEY_CHECKS=1;
@@ -1,3 +1,3 @@
1
1
  ALTER TABLE `registrations`
2
2
  ADD COLUMN `options` json NOT NULL DEFAULT ('{"value": [], "version": 0}') AFTER `price`,
3
- ADD COLUMN `groupPrice` json NOT NULL DEFAULT ('{"value": {"id": "unknown", "name": "Onbekend", "price": {"price": 0, "reducedPrice": null}}, "version": 0}') AFTER `price`;
3
+ ADD COLUMN `groupPrice` json NOT NULL DEFAULT ('{"value": {"id": "unknown", "name": "Standaardtarief", "price": {"price": 0, "reducedPrice": null}}, "version": 0}') AFTER `price`;
@@ -1,2 +1,4 @@
1
1
 
2
+ SET FOREIGN_KEY_CHECKS=0;
2
3
  ALTER TABLE `payments` ADD FOREIGN KEY (`payingOrganizationId`) REFERENCES `organizations` (`id`) ON UPDATE CASCADE ON DELETE SET NULL;
4
+ SET FOREIGN_KEY_CHECKS=1;
@@ -1 +1,3 @@
1
+ SET FOREIGN_KEY_CHECKS=0;
1
2
  ALTER TABLE `registrations` ADD FOREIGN KEY (`organizationId`) REFERENCES `organizations` (`id`) ON UPDATE CASCADE ON DELETE CASCADE;
3
+ SET FOREIGN_KEY_CHECKS=1;
@@ -1 +1,3 @@
1
+ SET FOREIGN_KEY_CHECKS=0;
1
2
  ALTER TABLE `registrations` ADD FOREIGN KEY (`payingOrganizationId`) REFERENCES `organizations` (`id`) ON UPDATE CASCADE ON DELETE SET NULL;
3
+ SET FOREIGN_KEY_CHECKS=1;
@@ -0,0 +1,6 @@
1
+ ALTER TABLE
2
+ `stamhoofd_invoices`
3
+ ADD
4
+ COLUMN `negativeInvoiceId` varchar(36) NULL,
5
+ ADD
6
+ FOREIGN KEY (`negativeInvoiceId`) REFERENCES `stamhoofd_invoices` (`id`) ON UPDATE CASCADE ON DELETE SET NULL;