@stamhoofd/models 2.1.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 (481) hide show
  1. package/dist/src/assets/Metropolis-Black.woff2 +0 -0
  2. package/dist/src/assets/Metropolis-BlackItalic.woff2 +0 -0
  3. package/dist/src/assets/Metropolis-Bold.woff2 +0 -0
  4. package/dist/src/assets/Metropolis-BoldItalic.woff2 +0 -0
  5. package/dist/src/assets/Metropolis-ExtraBold.woff2 +0 -0
  6. package/dist/src/assets/Metropolis-ExtraBoldItalic.woff2 +0 -0
  7. package/dist/src/assets/Metropolis-ExtraLight.woff2 +0 -0
  8. package/dist/src/assets/Metropolis-ExtraLightItalic.woff2 +0 -0
  9. package/dist/src/assets/Metropolis-Light.woff2 +0 -0
  10. package/dist/src/assets/Metropolis-LightItalic.woff2 +0 -0
  11. package/dist/src/assets/Metropolis-Medium.woff2 +0 -0
  12. package/dist/src/assets/Metropolis-MediumItalic.woff2 +0 -0
  13. package/dist/src/assets/Metropolis-Regular.woff2 +0 -0
  14. package/dist/src/assets/Metropolis-RegularItalic.woff2 +0 -0
  15. package/dist/src/assets/Metropolis-SemiBold.woff2 +0 -0
  16. package/dist/src/assets/Metropolis-SemiBoldItalic.woff2 +0 -0
  17. package/dist/src/assets/Metropolis-Thin.woff2 +0 -0
  18. package/dist/src/assets/Metropolis-ThinItalic.woff2 +0 -0
  19. package/dist/src/assets/assets/Metropolis-Black.woff2 +0 -0
  20. package/dist/src/assets/assets/Metropolis-BlackItalic.woff2 +0 -0
  21. package/dist/src/assets/assets/Metropolis-Bold.woff2 +0 -0
  22. package/dist/src/assets/assets/Metropolis-BoldItalic.woff2 +0 -0
  23. package/dist/src/assets/assets/Metropolis-ExtraBold.woff2 +0 -0
  24. package/dist/src/assets/assets/Metropolis-ExtraBoldItalic.woff2 +0 -0
  25. package/dist/src/assets/assets/Metropolis-ExtraLight.woff2 +0 -0
  26. package/dist/src/assets/assets/Metropolis-ExtraLightItalic.woff2 +0 -0
  27. package/dist/src/assets/assets/Metropolis-Light.woff2 +0 -0
  28. package/dist/src/assets/assets/Metropolis-LightItalic.woff2 +0 -0
  29. package/dist/src/assets/assets/Metropolis-Medium.woff2 +0 -0
  30. package/dist/src/assets/assets/Metropolis-MediumItalic.woff2 +0 -0
  31. package/dist/src/assets/assets/Metropolis-Regular.woff2 +0 -0
  32. package/dist/src/assets/assets/Metropolis-RegularItalic.woff2 +0 -0
  33. package/dist/src/assets/assets/Metropolis-SemiBold.woff2 +0 -0
  34. package/dist/src/assets/assets/Metropolis-SemiBoldItalic.woff2 +0 -0
  35. package/dist/src/assets/assets/Metropolis-Thin.woff2 +0 -0
  36. package/dist/src/assets/assets/Metropolis-ThinItalic.woff2 +0 -0
  37. package/dist/src/assets/assets/logo.png +0 -0
  38. package/dist/src/assets/logo.png +0 -0
  39. package/dist/src/factories/AddressFactory.d.ts +10 -0
  40. package/dist/src/factories/AddressFactory.d.ts.map +1 -0
  41. package/dist/src/factories/AddressFactory.js +42 -0
  42. package/dist/src/factories/AddressFactory.js.map +1 -0
  43. package/dist/src/factories/EmergencyContactFactory.d.ts +9 -0
  44. package/dist/src/factories/EmergencyContactFactory.d.ts.map +1 -0
  45. package/dist/src/factories/EmergencyContactFactory.js +42 -0
  46. package/dist/src/factories/EmergencyContactFactory.js.map +1 -0
  47. package/dist/src/factories/GroupFactory.d.ts +19 -0
  48. package/dist/src/factories/GroupFactory.d.ts.map +1 -0
  49. package/dist/src/factories/GroupFactory.js +52 -0
  50. package/dist/src/factories/GroupFactory.js.map +1 -0
  51. package/dist/src/factories/MemberFactory.d.ts +16 -0
  52. package/dist/src/factories/MemberFactory.d.ts.map +1 -0
  53. package/dist/src/factories/MemberFactory.js +98 -0
  54. package/dist/src/factories/MemberFactory.js.map +1 -0
  55. package/dist/src/factories/OrganizationFactory.d.ts +16 -0
  56. package/dist/src/factories/OrganizationFactory.d.ts.map +1 -0
  57. package/dist/src/factories/OrganizationFactory.js +40 -0
  58. package/dist/src/factories/OrganizationFactory.js.map +1 -0
  59. package/dist/src/factories/ParentFactory.d.ts +10 -0
  60. package/dist/src/factories/ParentFactory.d.ts.map +1 -0
  61. package/dist/src/factories/ParentFactory.js +44 -0
  62. package/dist/src/factories/ParentFactory.js.map +1 -0
  63. package/dist/src/factories/RecordFactory.d.ts +10 -0
  64. package/dist/src/factories/RecordFactory.d.ts.map +1 -0
  65. package/dist/src/factories/RecordFactory.js +14 -0
  66. package/dist/src/factories/RecordFactory.js.map +1 -0
  67. package/dist/src/factories/RegisterCodeFactory.d.ts +18 -0
  68. package/dist/src/factories/RegisterCodeFactory.d.ts.map +1 -0
  69. package/dist/src/factories/RegisterCodeFactory.js +19 -0
  70. package/dist/src/factories/RegisterCodeFactory.js.map +1 -0
  71. package/dist/src/factories/RegistrationFactory.d.ts +14 -0
  72. package/dist/src/factories/RegistrationFactory.d.ts.map +1 -0
  73. package/dist/src/factories/RegistrationFactory.js +26 -0
  74. package/dist/src/factories/RegistrationFactory.js.map +1 -0
  75. package/dist/src/factories/UserFactory.d.ts +21 -0
  76. package/dist/src/factories/UserFactory.d.ts.map +1 -0
  77. package/dist/src/factories/UserFactory.js +41 -0
  78. package/dist/src/factories/UserFactory.js.map +1 -0
  79. package/dist/src/factories/WebshopFactory.d.ts +16 -0
  80. package/dist/src/factories/WebshopFactory.d.ts.map +1 -0
  81. package/dist/src/factories/WebshopFactory.js +35 -0
  82. package/dist/src/factories/WebshopFactory.js.map +1 -0
  83. package/dist/src/helpers/DNSValidator.d.ts +6 -0
  84. package/dist/src/helpers/DNSValidator.d.ts.map +1 -0
  85. package/dist/src/helpers/DNSValidator.js +144 -0
  86. package/dist/src/helpers/DNSValidator.js.map +1 -0
  87. package/dist/src/helpers/EmailBuilder.d.ts +22 -0
  88. package/dist/src/helpers/EmailBuilder.d.ts.map +1 -0
  89. package/dist/src/helpers/EmailBuilder.js +100 -0
  90. package/dist/src/helpers/EmailBuilder.js.map +1 -0
  91. package/dist/src/helpers/GroupBuilder.d.ts +9 -0
  92. package/dist/src/helpers/GroupBuilder.d.ts.map +1 -0
  93. package/dist/src/helpers/GroupBuilder.js +382 -0
  94. package/dist/src/helpers/GroupBuilder.js.map +1 -0
  95. package/dist/src/helpers/Handlebars.d.ts +2 -0
  96. package/dist/src/helpers/Handlebars.d.ts.map +1 -0
  97. package/dist/src/helpers/Handlebars.js +192 -0
  98. package/dist/src/helpers/Handlebars.js.map +1 -0
  99. package/dist/src/helpers/InvoiceBuilder.d.ts +29 -0
  100. package/dist/src/helpers/InvoiceBuilder.d.ts.map +1 -0
  101. package/dist/src/helpers/InvoiceBuilder.js +406 -0
  102. package/dist/src/helpers/InvoiceBuilder.js.map +1 -0
  103. package/dist/src/helpers/InvoiceBuilder.test.d.ts +2 -0
  104. package/dist/src/helpers/InvoiceBuilder.test.d.ts.map +1 -0
  105. package/dist/src/helpers/InvoiceBuilder.test.js +52 -0
  106. package/dist/src/helpers/InvoiceBuilder.test.js.map +1 -0
  107. package/dist/src/helpers/RateLimiter.d.ts +27 -0
  108. package/dist/src/helpers/RateLimiter.d.ts.map +1 -0
  109. package/dist/src/helpers/RateLimiter.js +57 -0
  110. package/dist/src/helpers/RateLimiter.js.map +1 -0
  111. package/dist/src/helpers/WebshopCounter.d.ts +6 -0
  112. package/dist/src/helpers/WebshopCounter.d.ts.map +1 -0
  113. package/dist/src/helpers/WebshopCounter.js +36 -0
  114. package/dist/src/helpers/WebshopCounter.js.map +1 -0
  115. package/dist/src/helpers/WebshopCounter.test.d.ts +2 -0
  116. package/dist/src/helpers/WebshopCounter.test.d.ts.map +1 -0
  117. package/dist/src/helpers/WebshopCounter.test.js +17 -0
  118. package/dist/src/helpers/WebshopCounter.test.js.map +1 -0
  119. package/dist/src/index.d.ts +18 -0
  120. package/dist/src/index.d.ts.map +1 -0
  121. package/dist/src/index.js +23 -0
  122. package/dist/src/index.js.map +1 -0
  123. package/dist/src/migrations/1593773929-create-initial-tables.sql +634 -0
  124. package/dist/src/migrations/1605261999-gemeenten-tmp.sql +2820 -0
  125. package/dist/src/migrations/1605262045-import-postcodes.d.ts +16 -0
  126. package/dist/src/migrations/1605262045-import-postcodes.d.ts.map +1 -0
  127. package/dist/src/migrations/1605262045-import-postcodes.js +116 -0
  128. package/dist/src/migrations/1605262045-import-postcodes.js.map +1 -0
  129. package/dist/src/migrations/1605262046-import-postcodes-nl.d.ts +4 -0
  130. package/dist/src/migrations/1605262046-import-postcodes-nl.d.ts.map +1 -0
  131. package/dist/src/migrations/1605262046-import-postcodes-nl.js +83 -0
  132. package/dist/src/migrations/1605262046-import-postcodes-nl.js.map +1 -0
  133. package/dist/src/migrations/1605279038-drop-gemeenten-tmp.sql +1 -0
  134. package/dist/src/migrations/1648392491-default-templates.sql +9 -0
  135. package/dist/src/migrations/1651245707-default-templates-reminders.sql +6 -0
  136. package/dist/src/migrations/1708607340-tickets-deleted-at.sql +1 -0
  137. package/dist/src/migrations/1710459176-register-code-invoices.sql +3 -0
  138. package/dist/src/migrations/1712158247-discount-codes.sql +17 -0
  139. package/dist/src/migrations/1713178665-drop-invites.sql +1 -0
  140. package/dist/src/migrations/1713178666-drop-keychain.sql +1 -0
  141. package/dist/src/migrations/1713178667-drop-challenges.sql +1 -0
  142. package/dist/src/migrations/1713178668-drop-user-keys.sql +7 -0
  143. package/dist/src/migrations/1713178669-drop-organization-key.sql +2 -0
  144. package/dist/src/migrations/data/postcodes/nl/Drenthe +291 -0
  145. package/dist/src/migrations/data/postcodes/nl/Flevoland +107 -0
  146. package/dist/src/migrations/data/postcodes/nl/Friesland +518 -0
  147. package/dist/src/migrations/data/postcodes/nl/Gelderland +601 -0
  148. package/dist/src/migrations/data/postcodes/nl/Groningen +279 -0
  149. package/dist/src/migrations/data/postcodes/nl/Limburg +324 -0
  150. package/dist/src/migrations/data/postcodes/nl/Noord-Brabant +620 -0
  151. package/dist/src/migrations/data/postcodes/nl/Noord-Holland +566 -0
  152. package/dist/src/migrations/data/postcodes/nl/Overrijsel +344 -0
  153. package/dist/src/migrations/data/postcodes/nl/Utrecht +278 -0
  154. package/dist/src/migrations/data/postcodes/nl/Zeeland +179 -0
  155. package/dist/src/migrations/data/postcodes/nl/Zuid-Holland +662 -0
  156. package/dist/src/models/BalanceItem.d.ts +57 -0
  157. package/dist/src/models/BalanceItem.d.ts.map +1 -0
  158. package/dist/src/models/BalanceItem.js +346 -0
  159. package/dist/src/models/BalanceItem.js.map +1 -0
  160. package/dist/src/models/BalanceItemPayment.d.ts +31 -0
  161. package/dist/src/models/BalanceItemPayment.d.ts.map +1 -0
  162. package/dist/src/models/BalanceItemPayment.js +101 -0
  163. package/dist/src/models/BalanceItemPayment.js.map +1 -0
  164. package/dist/src/models/BuckarooPayment.d.ts +8 -0
  165. package/dist/src/models/BuckarooPayment.d.ts.map +1 -0
  166. package/dist/src/models/BuckarooPayment.js +24 -0
  167. package/dist/src/models/BuckarooPayment.js.map +1 -0
  168. package/dist/src/models/Document.d.ts +44 -0
  169. package/dist/src/models/Document.d.ts.map +1 -0
  170. package/dist/src/models/Document.js +194 -0
  171. package/dist/src/models/Document.js.map +1 -0
  172. package/dist/src/models/DocumentTemplate.d.ts +45 -0
  173. package/dist/src/models/DocumentTemplate.d.ts.map +1 -0
  174. package/dist/src/models/DocumentTemplate.js +533 -0
  175. package/dist/src/models/DocumentTemplate.js.map +1 -0
  176. package/dist/src/models/EmailTemplate.d.ts +22 -0
  177. package/dist/src/models/EmailTemplate.d.ts.map +1 -0
  178. package/dist/src/models/EmailTemplate.js +70 -0
  179. package/dist/src/models/EmailTemplate.js.map +1 -0
  180. package/dist/src/models/EmailVerificationCode.d.ts +60 -0
  181. package/dist/src/models/EmailVerificationCode.d.ts.map +1 -0
  182. package/dist/src/models/EmailVerificationCode.js +307 -0
  183. package/dist/src/models/EmailVerificationCode.js.map +1 -0
  184. package/dist/src/models/Group.d.ts +36 -0
  185. package/dist/src/models/Group.d.ts.map +1 -0
  186. package/dist/src/models/Group.js +231 -0
  187. package/dist/src/models/Group.js.map +1 -0
  188. package/dist/src/models/Image.d.ts +12 -0
  189. package/dist/src/models/Image.d.ts.map +1 -0
  190. package/dist/src/models/Image.js +137 -0
  191. package/dist/src/models/Image.js.map +1 -0
  192. package/dist/src/models/Member.d.ts +66 -0
  193. package/dist/src/models/Member.d.ts.map +1 -0
  194. package/dist/src/models/Member.js +309 -0
  195. package/dist/src/models/Member.js.map +1 -0
  196. package/dist/src/models/MemberResponsibilityRecord.d.ts +11 -0
  197. package/dist/src/models/MemberResponsibilityRecord.d.ts.map +1 -0
  198. package/dist/src/models/MemberResponsibilityRecord.js +47 -0
  199. package/dist/src/models/MemberResponsibilityRecord.js.map +1 -0
  200. package/dist/src/models/MolliePayment.d.ts +8 -0
  201. package/dist/src/models/MolliePayment.d.ts.map +1 -0
  202. package/dist/src/models/MolliePayment.js +24 -0
  203. package/dist/src/models/MolliePayment.js.map +1 -0
  204. package/dist/src/models/MollieToken.d.ts +45 -0
  205. package/dist/src/models/MollieToken.d.ts.map +1 -0
  206. package/dist/src/models/MollieToken.js +333 -0
  207. package/dist/src/models/MollieToken.js.map +1 -0
  208. package/dist/src/models/OneTimeToken.d.ts +38 -0
  209. package/dist/src/models/OneTimeToken.d.ts.map +1 -0
  210. package/dist/src/models/OneTimeToken.js +126 -0
  211. package/dist/src/models/OneTimeToken.js.map +1 -0
  212. package/dist/src/models/Order.d.ts +99 -0
  213. package/dist/src/models/Order.d.ts.map +1 -0
  214. package/dist/src/models/Order.js +912 -0
  215. package/dist/src/models/Order.js.map +1 -0
  216. package/dist/src/models/Organization.d.ts +119 -0
  217. package/dist/src/models/Organization.d.ts.map +1 -0
  218. package/dist/src/models/Organization.js +900 -0
  219. package/dist/src/models/Organization.js.map +1 -0
  220. package/dist/src/models/OrganizationRegistrationPeriod.d.ts +14 -0
  221. package/dist/src/models/OrganizationRegistrationPeriod.d.ts.map +1 -0
  222. package/dist/src/models/OrganizationRegistrationPeriod.js +62 -0
  223. package/dist/src/models/OrganizationRegistrationPeriod.js.map +1 -0
  224. package/dist/src/models/PasswordToken.d.ts +29 -0
  225. package/dist/src/models/PasswordToken.d.ts.map +1 -0
  226. package/dist/src/models/PasswordToken.js +118 -0
  227. package/dist/src/models/PasswordToken.js.map +1 -0
  228. package/dist/src/models/PayconiqPayment.d.ts +18 -0
  229. package/dist/src/models/PayconiqPayment.d.ts.map +1 -0
  230. package/dist/src/models/PayconiqPayment.js +216 -0
  231. package/dist/src/models/PayconiqPayment.js.map +1 -0
  232. package/dist/src/models/Payment.d.ts +62 -0
  233. package/dist/src/models/Payment.d.ts.map +1 -0
  234. package/dist/src/models/Payment.js +199 -0
  235. package/dist/src/models/Payment.js.map +1 -0
  236. package/dist/src/models/Platform.d.ts +15 -0
  237. package/dist/src/models/Platform.d.ts.map +1 -0
  238. package/dist/src/models/Platform.js +77 -0
  239. package/dist/src/models/Platform.js.map +1 -0
  240. package/dist/src/models/RegisterCode.d.ts +27 -0
  241. package/dist/src/models/RegisterCode.d.ts.map +1 -0
  242. package/dist/src/models/RegisterCode.js +162 -0
  243. package/dist/src/models/RegisterCode.js.map +1 -0
  244. package/dist/src/models/Registration.d.ts +47 -0
  245. package/dist/src/models/Registration.d.ts.map +1 -0
  246. package/dist/src/models/Registration.js +369 -0
  247. package/dist/src/models/Registration.js.map +1 -0
  248. package/dist/src/models/RegistrationPeriod.d.ts +15 -0
  249. package/dist/src/models/RegistrationPeriod.d.ts.map +1 -0
  250. package/dist/src/models/RegistrationPeriod.js +64 -0
  251. package/dist/src/models/RegistrationPeriod.js.map +1 -0
  252. package/dist/src/models/STCredit.d.ts +20 -0
  253. package/dist/src/models/STCredit.d.ts.map +1 -0
  254. package/dist/src/models/STCredit.js +129 -0
  255. package/dist/src/models/STCredit.js.map +1 -0
  256. package/dist/src/models/STInvoice.d.ts +51 -0
  257. package/dist/src/models/STInvoice.d.ts.map +1 -0
  258. package/dist/src/models/STInvoice.js +453 -0
  259. package/dist/src/models/STInvoice.js.map +1 -0
  260. package/dist/src/models/STPackage.d.ts +36 -0
  261. package/dist/src/models/STPackage.d.ts.map +1 -0
  262. package/dist/src/models/STPackage.js +300 -0
  263. package/dist/src/models/STPackage.js.map +1 -0
  264. package/dist/src/models/STPendingInvoice.d.ts +45 -0
  265. package/dist/src/models/STPendingInvoice.d.ts.map +1 -0
  266. package/dist/src/models/STPendingInvoice.js +284 -0
  267. package/dist/src/models/STPendingInvoice.js.map +1 -0
  268. package/dist/src/models/StripeAccount.d.ts +17 -0
  269. package/dist/src/models/StripeAccount.d.ts.map +1 -0
  270. package/dist/src/models/StripeAccount.js +81 -0
  271. package/dist/src/models/StripeAccount.js.map +1 -0
  272. package/dist/src/models/StripeCheckoutSession.d.ts +9 -0
  273. package/dist/src/models/StripeCheckoutSession.d.ts.map +1 -0
  274. package/dist/src/models/StripeCheckoutSession.js +31 -0
  275. package/dist/src/models/StripeCheckoutSession.js.map +1 -0
  276. package/dist/src/models/StripePaymentIntent.d.ts +9 -0
  277. package/dist/src/models/StripePaymentIntent.d.ts.map +1 -0
  278. package/dist/src/models/StripePaymentIntent.js +31 -0
  279. package/dist/src/models/StripePaymentIntent.js.map +1 -0
  280. package/dist/src/models/Ticket.d.ts +61 -0
  281. package/dist/src/models/Ticket.d.ts.map +1 -0
  282. package/dist/src/models/Ticket.js +143 -0
  283. package/dist/src/models/Ticket.js.map +1 -0
  284. package/dist/src/models/Token.d.ts +49 -0
  285. package/dist/src/models/Token.d.ts.map +1 -0
  286. package/dist/src/models/Token.js +218 -0
  287. package/dist/src/models/Token.js.map +1 -0
  288. package/dist/src/models/Token.test.d.ts +2 -0
  289. package/dist/src/models/Token.test.d.ts.map +1 -0
  290. package/dist/src/models/Token.test.js +60 -0
  291. package/dist/src/models/Token.test.js.map +1 -0
  292. package/dist/src/models/UsedRegisterCode.d.ts +22 -0
  293. package/dist/src/models/UsedRegisterCode.d.ts.map +1 -0
  294. package/dist/src/models/UsedRegisterCode.js +158 -0
  295. package/dist/src/models/UsedRegisterCode.js.map +1 -0
  296. package/dist/src/models/User.d.ts +55 -0
  297. package/dist/src/models/User.d.ts.map +1 -0
  298. package/dist/src/models/User.js +314 -0
  299. package/dist/src/models/User.js.map +1 -0
  300. package/dist/src/models/UserPermissions.d.ts +15 -0
  301. package/dist/src/models/UserPermissions.d.ts.map +1 -0
  302. package/dist/src/models/UserPermissions.js +57 -0
  303. package/dist/src/models/UserPermissions.js.map +1 -0
  304. package/dist/src/models/Webshop.d.ts +44 -0
  305. package/dist/src/models/Webshop.d.ts.map +1 -0
  306. package/dist/src/models/Webshop.js +184 -0
  307. package/dist/src/models/Webshop.js.map +1 -0
  308. package/dist/src/models/WebshopDiscountCode.d.ts +18 -0
  309. package/dist/src/models/WebshopDiscountCode.d.ts.map +1 -0
  310. package/dist/src/models/WebshopDiscountCode.js +88 -0
  311. package/dist/src/models/WebshopDiscountCode.js.map +1 -0
  312. package/dist/src/models/addresses/City.d.ts +14 -0
  313. package/dist/src/models/addresses/City.d.ts.map +1 -0
  314. package/dist/src/models/addresses/City.js +37 -0
  315. package/dist/src/models/addresses/City.js.map +1 -0
  316. package/dist/src/models/addresses/PostalCode.d.ts +20 -0
  317. package/dist/src/models/addresses/PostalCode.d.ts.map +1 -0
  318. package/dist/src/models/addresses/PostalCode.js +138 -0
  319. package/dist/src/models/addresses/PostalCode.js.map +1 -0
  320. package/dist/src/models/addresses/PostalCode.test.d.ts +2 -0
  321. package/dist/src/models/addresses/PostalCode.test.d.ts.map +1 -0
  322. package/dist/src/models/addresses/PostalCode.test.js +98 -0
  323. package/dist/src/models/addresses/PostalCode.test.js.map +1 -0
  324. package/dist/src/models/addresses/Province.d.ts +9 -0
  325. package/dist/src/models/addresses/Province.d.ts.map +1 -0
  326. package/dist/src/models/addresses/Province.js +24 -0
  327. package/dist/src/models/addresses/Province.js.map +1 -0
  328. package/dist/src/models/addresses/Street.d.ts +10 -0
  329. package/dist/src/models/addresses/Street.d.ts.map +1 -0
  330. package/dist/src/models/addresses/Street.js +26 -0
  331. package/dist/src/models/addresses/Street.js.map +1 -0
  332. package/dist/src/models/index.d.ts +37 -0
  333. package/dist/src/models/index.d.ts.map +1 -0
  334. package/dist/src/models/index.js +53 -0
  335. package/dist/src/models/index.js.map +1 -0
  336. package/dist/src/structures/OrganizationServerMetaData.d.ts +43 -0
  337. package/dist/src/structures/OrganizationServerMetaData.d.ts.map +1 -0
  338. package/dist/src/structures/OrganizationServerMetaData.js +128 -0
  339. package/dist/src/structures/OrganizationServerMetaData.js.map +1 -0
  340. package/dist/tests/jest.global.setup.d.ts +3 -0
  341. package/dist/tests/jest.global.setup.d.ts.map +1 -0
  342. package/dist/tests/jest.global.setup.js +20 -0
  343. package/dist/tests/jest.global.setup.js.map +1 -0
  344. package/dist/tests/jest.setup.d.ts +2 -0
  345. package/dist/tests/jest.setup.d.ts.map +1 -0
  346. package/dist/tests/jest.setup.js +15 -0
  347. package/dist/tests/jest.setup.js.map +1 -0
  348. package/package.json +30 -0
  349. package/src/assets/Metropolis-Black.woff2 +0 -0
  350. package/src/assets/Metropolis-BlackItalic.woff2 +0 -0
  351. package/src/assets/Metropolis-Bold.woff2 +0 -0
  352. package/src/assets/Metropolis-BoldItalic.woff2 +0 -0
  353. package/src/assets/Metropolis-ExtraBold.woff2 +0 -0
  354. package/src/assets/Metropolis-ExtraBoldItalic.woff2 +0 -0
  355. package/src/assets/Metropolis-ExtraLight.woff2 +0 -0
  356. package/src/assets/Metropolis-ExtraLightItalic.woff2 +0 -0
  357. package/src/assets/Metropolis-Light.woff2 +0 -0
  358. package/src/assets/Metropolis-LightItalic.woff2 +0 -0
  359. package/src/assets/Metropolis-Medium.woff2 +0 -0
  360. package/src/assets/Metropolis-MediumItalic.woff2 +0 -0
  361. package/src/assets/Metropolis-Regular.woff2 +0 -0
  362. package/src/assets/Metropolis-RegularItalic.woff2 +0 -0
  363. package/src/assets/Metropolis-SemiBold.woff2 +0 -0
  364. package/src/assets/Metropolis-SemiBoldItalic.woff2 +0 -0
  365. package/src/assets/Metropolis-Thin.woff2 +0 -0
  366. package/src/assets/Metropolis-ThinItalic.woff2 +0 -0
  367. package/src/assets/logo.png +0 -0
  368. package/src/factories/AddressFactory.ts +42 -0
  369. package/src/factories/EmergencyContactFactory.ts +43 -0
  370. package/src/factories/GroupFactory.ts +66 -0
  371. package/src/factories/MemberFactory.ts +122 -0
  372. package/src/factories/OrganizationFactory.ts +45 -0
  373. package/src/factories/ParentFactory.ts +49 -0
  374. package/src/factories/RecordFactory.ts +12 -0
  375. package/src/factories/RegisterCodeFactory.ts +25 -0
  376. package/src/factories/RegistrationFactory.ts +32 -0
  377. package/src/factories/UserFactory.ts +66 -0
  378. package/src/factories/WebshopFactory.ts +43 -0
  379. package/src/helpers/DNSValidator.ts +153 -0
  380. package/src/helpers/EmailBuilder.ts +127 -0
  381. package/src/helpers/GroupBuilder.ts +438 -0
  382. package/src/helpers/Handlebars.ts +203 -0
  383. package/src/helpers/InvoiceBuilder.test.ts +57 -0
  384. package/src/helpers/InvoiceBuilder.ts +501 -0
  385. package/src/helpers/RateLimiter.ts +75 -0
  386. package/src/helpers/WebshopCounter.test.ts +16 -0
  387. package/src/helpers/WebshopCounter.ts +36 -0
  388. package/src/index.ts +21 -0
  389. package/src/migrations/1593773929-create-initial-tables.sql +634 -0
  390. package/src/migrations/1605261999-gemeenten-tmp.sql +2820 -0
  391. package/src/migrations/1605262045-import-postcodes.ts +132 -0
  392. package/src/migrations/1605262046-import-postcodes-nl.ts +97 -0
  393. package/src/migrations/1605279038-drop-gemeenten-tmp.sql +1 -0
  394. package/src/migrations/1648392491-default-templates.sql +9 -0
  395. package/src/migrations/1651245707-default-templates-reminders.sql +6 -0
  396. package/src/migrations/1708607340-tickets-deleted-at.sql +1 -0
  397. package/src/migrations/1710459176-register-code-invoices.sql +3 -0
  398. package/src/migrations/1712158247-discount-codes.sql +17 -0
  399. package/src/migrations/1713178665-drop-invites.sql +1 -0
  400. package/src/migrations/1713178666-drop-keychain.sql +1 -0
  401. package/src/migrations/1713178667-drop-challenges.sql +1 -0
  402. package/src/migrations/1713178668-drop-user-keys.sql +7 -0
  403. package/src/migrations/1713178669-drop-organization-key.sql +2 -0
  404. package/src/migrations/1714985451-user-nullable-organization-id.sql +2 -0
  405. package/src/migrations/1714985452-email-verification-code-nullable-organization-id.sql +2 -0
  406. package/src/migrations/1714985453-user-organization-permissions.sql +2 -0
  407. package/src/migrations/1714985454-user-organization-permissions.sql +2 -0
  408. package/src/migrations/1715079362-platform.sql +6 -0
  409. package/src/migrations/1715181649-registrations-organization-id.sql +2 -0
  410. package/src/migrations/1715181650-registrations-organization-id-fill.sql +1 -0
  411. package/src/migrations/1715181651-registrations-organization-id-drop-null.sql +2 -0
  412. package/src/migrations/1716117067-members-nullable-organization-id.sql +2 -0
  413. package/src/migrations/1719567581-registration-periods.sql +13 -0
  414. package/src/migrations/1719567582-organization-registration-periods.sql +13 -0
  415. package/src/migrations/1719567881-organization-periodId.sql +2 -0
  416. package/src/migrations/1719567882-groups-periodId.sql +2 -0
  417. package/src/migrations/1719567883-platform-periodId.sql +2 -0
  418. package/src/migrations/1719568079-default-period.sql +2 -0
  419. package/src/migrations/1719568080-set-default-period-platform.sql +1 -0
  420. package/src/migrations/1719568081-set-default-period-organizations.sql +1 -0
  421. package/src/migrations/1719568082-set-default-period-groups.sql +1 -0
  422. package/src/migrations/1719580828-registrations-periodId.sql +2 -0
  423. package/src/migrations/1719580829-set-default-period-registrations.sql +1 -0
  424. package/src/migrations/data/postcodes/nl/Drenthe +291 -0
  425. package/src/migrations/data/postcodes/nl/Flevoland +107 -0
  426. package/src/migrations/data/postcodes/nl/Friesland +518 -0
  427. package/src/migrations/data/postcodes/nl/Gelderland +601 -0
  428. package/src/migrations/data/postcodes/nl/Groningen +279 -0
  429. package/src/migrations/data/postcodes/nl/Limburg +324 -0
  430. package/src/migrations/data/postcodes/nl/Noord-Brabant +620 -0
  431. package/src/migrations/data/postcodes/nl/Noord-Holland +566 -0
  432. package/src/migrations/data/postcodes/nl/Overrijsel +344 -0
  433. package/src/migrations/data/postcodes/nl/Utrecht +278 -0
  434. package/src/migrations/data/postcodes/nl/Zeeland +179 -0
  435. package/src/migrations/data/postcodes/nl/Zuid-Holland +662 -0
  436. package/src/models/BalanceItem.ts +392 -0
  437. package/src/models/BalanceItemPayment.ts +106 -0
  438. package/src/models/BuckarooPayment.ts +19 -0
  439. package/src/models/Document.ts +203 -0
  440. package/src/models/DocumentTemplate.ts +583 -0
  441. package/src/models/EmailTemplate.ts +64 -0
  442. package/src/models/EmailVerificationCode.ts +352 -0
  443. package/src/models/Group.ts +293 -0
  444. package/src/models/Image.ts +147 -0
  445. package/src/models/Member.ts +386 -0
  446. package/src/models/MemberResponsibilityRecord.ts +39 -0
  447. package/src/models/MolliePayment.ts +19 -0
  448. package/src/models/MollieToken.ts +369 -0
  449. package/src/models/OneTimeToken.ts +131 -0
  450. package/src/models/Order.ts +1030 -0
  451. package/src/models/Organization.ts +1085 -0
  452. package/src/models/OrganizationRegistrationPeriod.ts +54 -0
  453. package/src/models/PasswordToken.ts +139 -0
  454. package/src/models/PayconiqPayment.ts +241 -0
  455. package/src/models/Payment.ts +216 -0
  456. package/src/models/Platform.ts +76 -0
  457. package/src/models/RegisterCode.ts +164 -0
  458. package/src/models/Registration.ts +405 -0
  459. package/src/models/RegistrationPeriod.ts +55 -0
  460. package/src/models/STCredit.ts +134 -0
  461. package/src/models/STInvoice.ts +507 -0
  462. package/src/models/STPackage.ts +324 -0
  463. package/src/models/STPendingInvoice.ts +308 -0
  464. package/src/models/StripeAccount.ts +71 -0
  465. package/src/models/StripeCheckoutSession.ts +22 -0
  466. package/src/models/StripePaymentIntent.ts +22 -0
  467. package/src/models/Ticket.ts +145 -0
  468. package/src/models/Token.test.ts +69 -0
  469. package/src/models/Token.ts +269 -0
  470. package/src/models/UsedRegisterCode.ts +166 -0
  471. package/src/models/User.ts +445 -0
  472. package/src/models/UserPermissions.ts +54 -0
  473. package/src/models/Webshop.ts +206 -0
  474. package/src/models/WebshopDiscountCode.ts +81 -0
  475. package/src/models/addresses/City.ts +31 -0
  476. package/src/models/addresses/PostalCode.test.ts +117 -0
  477. package/src/models/addresses/PostalCode.ts +164 -0
  478. package/src/models/addresses/Province.ts +20 -0
  479. package/src/models/addresses/Street.ts +25 -0
  480. package/src/models/index.ts +49 -0
  481. package/src/structures/OrganizationServerMetaData.ts +117 -0
@@ -0,0 +1,1085 @@
1
+ import { column, Database, Model } from "@simonbackx/simple-database";
2
+ import { DecodedRequest } from '@simonbackx/simple-endpoints';
3
+ import { SimpleError } from '@simonbackx/simple-errors';
4
+ import { I18n } from "@stamhoofd/backend-i18n";
5
+ import { Email, EmailInterfaceRecipient } from "@stamhoofd/email";
6
+ import { OrganizationRegistrationPeriod as OrganizationRegistrationPeriodStruct, Address, Country, DNSRecordStatus, EmailTemplateType, Organization as OrganizationStruct, OrganizationEmail, OrganizationMetaData, OrganizationPrivateMetaData, OrganizationRecordsConfiguration, PaymentMethod, PaymentProvider, PrivatePaymentConfiguration, Recipient, Replacement, STPackageType, TransferSettings } from "@stamhoofd/structures";
7
+ import { Formatter } from "@stamhoofd/utility";
8
+ import { AWSError } from 'aws-sdk';
9
+ import SES from 'aws-sdk/clients/sesv2';
10
+ import { PromiseResult } from 'aws-sdk/lib/request';
11
+ import { v4 as uuidv4 } from "uuid";
12
+
13
+ import { validateDNSRecords } from "../helpers/DNSValidator";
14
+ import { getEmailBuilder } from "../helpers/EmailBuilder";
15
+ import { OrganizationServerMetaData } from '../structures/OrganizationServerMetaData';
16
+ import { EmailTemplate, Group, OrganizationRegistrationPeriod, RegistrationPeriod, StripeAccount } from "./";
17
+
18
+ export class Organization extends Model {
19
+ static table = "organizations";
20
+
21
+ @column({
22
+ primary: true, type: "string", beforeSave(value) {
23
+ return value ?? uuidv4();
24
+ }
25
+ })
26
+ id!: string;
27
+
28
+ @column({ type: "string" })
29
+ name: string;
30
+
31
+ /// URL to a website page or a Facebook page (including http)
32
+ @column({ type: "string", nullable: true })
33
+ website: string | null = null;
34
+
35
+ /// A custom domain name that is used to host the register application (should be unique)
36
+ // E.g. inschrijven.scoutswetteren.be
37
+ @column({ type: "string", nullable: true })
38
+ registerDomain: string | null = null;
39
+
40
+ // Unique representation of this organization from a string, that is used to provide the default domains
41
+ // in uri.stamhoofd.be
42
+ @column({ type: "string" })
43
+ uri: string;
44
+
45
+ @column({ type: "string" })
46
+ periodId: string;
47
+
48
+ /**
49
+ * Public meta data
50
+ */
51
+ @column({ type: "json", decoder: OrganizationMetaData })
52
+ meta: OrganizationMetaData;
53
+
54
+ /**
55
+ * Data only accessible by the owners / users with special permissions
56
+ */
57
+ @column({ type: "json", decoder: OrganizationPrivateMetaData })
58
+ privateMeta: OrganizationPrivateMetaData = OrganizationPrivateMetaData.create({})
59
+
60
+ /**
61
+ * Data only accessible by the server
62
+ */
63
+ @column({ type: "json", decoder: OrganizationServerMetaData })
64
+ serverMeta: OrganizationServerMetaData = OrganizationServerMetaData.create({})
65
+
66
+ @column({ type: "json", decoder: Address })
67
+ address: Address;
68
+
69
+ @column({
70
+ type: "string", beforeSave: function (this: Organization) {
71
+ return this.name+"\n"+this.address.toString()
72
+ }
73
+ })
74
+ searchIndex: string
75
+
76
+ @column({
77
+ type: "datetime", beforeSave(old?: any) {
78
+ if (old !== undefined) {
79
+ return old;
80
+ }
81
+ const date = new Date()
82
+ date.setMilliseconds(0)
83
+ return date
84
+ }
85
+ })
86
+ createdAt: Date
87
+
88
+ @column({
89
+ type: "datetime", beforeSave() {
90
+ const date = new Date()
91
+ date.setMilliseconds(0)
92
+ return date
93
+ },
94
+ skipUpdate: true
95
+ })
96
+ updatedAt: Date
97
+
98
+ /**
99
+ * Return default locale confiruation
100
+ */
101
+ get i18n() {
102
+ return new I18n("nl", this.address.country)
103
+ }
104
+
105
+ /**
106
+ * Makes sure empty name is replaced with organization name
107
+ */
108
+ get mappedTransferSettings(): TransferSettings {
109
+ return this.meta.transferSettings.fillMissing(TransferSettings.create({creditor: this.name}));
110
+ }
111
+
112
+
113
+ // Methods
114
+ static async getByURI(uri: string): Promise<Organization | undefined> {
115
+ const [rows] = await Database.select(
116
+ `SELECT ${this.getDefaultSelect()} FROM ${this.table} WHERE \`uri\` = ? LIMIT 1`,
117
+ [uri]
118
+ );
119
+
120
+ if (rows.length == 0) {
121
+ return undefined;
122
+ }
123
+
124
+ // Read member + address from first row
125
+ return this.fromRow(rows[0][this.table]);
126
+ }
127
+
128
+ // Methods
129
+ static async getByEmail(email: string): Promise<Organization | undefined> {
130
+ if (["hallo@stamhoofd.be", "hallo@stamhoofd.nl"].includes(email)) {
131
+ return
132
+ }
133
+ if (email.startsWith('noreply-')) {
134
+ // Trim
135
+ email = email.substring("noreply-".length)
136
+ }
137
+
138
+ if (email.endsWith("@stamhoofd.email")) {
139
+ const uri = email.substring(0, email.length - "@stamhoofd.email".length)
140
+ return await Organization.getByURI(uri)
141
+ }
142
+
143
+ if (email.endsWith("@stamhoofd.be")) {
144
+ const uri = email.substring(0, email.length - "@stamhoofd.be".length)
145
+ return await Organization.getByURI(uri)
146
+ }
147
+
148
+ if (email.endsWith("@stamhoofd.nl")) {
149
+ const uri = email.substring(0, email.length - "@stamhoofd.nl".length)
150
+ return await Organization.getByURI(uri)
151
+ }
152
+
153
+ const at = email.indexOf("@");
154
+ const domain = email.substring(at+1)
155
+
156
+ const [rows] = await Database.select(
157
+ `SELECT ${this.getDefaultSelect()} FROM ${this.table} WHERE privateMeta->"$.value.mailDomain" = ? LIMIT 1`,
158
+ [domain]
159
+ );
160
+
161
+ if (rows.length == 0) {
162
+ return undefined;
163
+ }
164
+
165
+ // Read member + address from first row
166
+ return this.fromRow(rows[0][this.table]);
167
+ }
168
+
169
+
170
+
171
+ // Methods
172
+ static async getByRegisterDomain(host: string): Promise<Organization | undefined> {
173
+ const [rows] = await Database.select(
174
+ `SELECT ${this.getDefaultSelect()} FROM ${this.table} WHERE \`registerDomain\` = ? LIMIT 1`,
175
+ [host]
176
+ );
177
+
178
+ if (rows.length == 0) {
179
+ return undefined;
180
+ }
181
+
182
+ // Read member + address from first row
183
+ return this.fromRow(rows[0][this.table]);
184
+ }
185
+
186
+ /**
187
+ * Get an Organization by looking at the host of a request
188
+ * Format is 2331c59a-0cbe-4279-871c-ea9d0474cd54.api.stamhoofd.app
189
+ * + switch country if needed
190
+ */
191
+ static async getFromRequest(request: DecodedRequest<any, any, any>): Promise<Organization> {
192
+ const organization = await Organization.fromApiHost(request.host);
193
+
194
+ const i18n = I18n.fromRequest(request)
195
+ i18n.switchToLocale({ country: organization.address.country })
196
+
197
+ return organization
198
+ }
199
+
200
+ /**
201
+ * Get an Organization by looking at the host of a request
202
+ * Format is 2331c59a-0cbe-4279-871c-ea9d0474cd54.api.stamhoofd.app
203
+ */
204
+ static async fromApiHost(host: string): Promise<Organization> {
205
+ const splitted = host.split('.')
206
+ if (splitted.length < 2) {
207
+ throw new SimpleError({
208
+ code: "invalid_host",
209
+ message: "Please specify the organization in the hostname",
210
+ });
211
+ }
212
+ const id = splitted[0]
213
+ const organization = await this.getByID(id);
214
+ if (!organization) {
215
+ throw new SimpleError({
216
+ code: "invalid_organization",
217
+ message: "No organization known for host " + host,
218
+ });
219
+ }
220
+ return organization;
221
+ }
222
+
223
+ /**
224
+ * Potentially includes a path
225
+ */
226
+ getHost(i18n?: I18n): string {
227
+ if (this.registerDomain) {
228
+ let d = this.registerDomain;
229
+
230
+ if (i18n && i18n.language != this.i18n.language) {
231
+ d += "/"+i18n.language
232
+ }
233
+
234
+ return d;
235
+ }
236
+ return this.getDefaultHost(i18n)
237
+ }
238
+
239
+ getDefaultHost(i18n?: I18n): string {
240
+ if (!STAMHOOFD.domains.registration) {
241
+ return STAMHOOFD.domains.dashboard + '/' + (i18n?.locale ?? this.i18n.locale) + '/leden/' + this.uri;
242
+ }
243
+ let defaultDomain = STAMHOOFD.domains.registration[this.address.country] ?? STAMHOOFD.domains.registration[""];
244
+
245
+ if (i18n && i18n.language != this.i18n.language) {
246
+ defaultDomain += "/"+i18n.language
247
+ }
248
+
249
+ return this.uri + "." + defaultDomain;
250
+ }
251
+
252
+ get marketingDomain(): string {
253
+ return STAMHOOFD.domains.marketing[this.address.country] ?? STAMHOOFD.domains.marketing[""];
254
+ }
255
+
256
+ getApiHost(): string {
257
+ const defaultDomain = STAMHOOFD.domains.api;
258
+ if (!defaultDomain) {
259
+ throw new Error("Missing hostname in environment")
260
+ }
261
+ return this.id+"." + defaultDomain;
262
+ }
263
+
264
+ async getStructure({emptyGroups} = {emptyGroups: false}): Promise<OrganizationStruct> {
265
+ const oPeriods = await OrganizationRegistrationPeriod.where({ periodId: this.periodId }, {limit: 1})
266
+ const oPeriod = oPeriods[0];
267
+ const period = await RegistrationPeriod.getByID(this.periodId)
268
+ const groups = emptyGroups ? [] : (await (await import("./Group")).Group.getAll(this.id, this.periodId))
269
+
270
+ const struct = OrganizationStruct.create({
271
+ id: this.id,
272
+ name: this.name,
273
+ meta: this.meta,
274
+ address: this.address,
275
+ registerDomain: this.registerDomain,
276
+ uri: this.uri,
277
+ website: this.website,
278
+ groups: groups.map(g => g.getStructure()),
279
+ createdAt: this.createdAt,
280
+ period: OrganizationRegistrationPeriodStruct.create({
281
+ ...oPeriod,
282
+ period: period!.getStructure()
283
+ })
284
+ })
285
+
286
+ if (this.meta.modules.disableActivities) {
287
+ // Only show groups that are in a given category
288
+ struct.groups = struct.categoryTree.categories[0]?.groups ?? []
289
+ }
290
+
291
+ if (emptyGroups) {
292
+ // Reduce data
293
+ struct.meta = struct.meta.clone()
294
+ struct.meta.categories = []
295
+ struct.meta.recordsConfiguration = OrganizationRecordsConfiguration.create({})
296
+
297
+ }
298
+
299
+ return struct
300
+ }
301
+
302
+ async cleanCategories(groups: {id: string}[]) {
303
+ const reachable = new Map<string, boolean>()
304
+ const queue = [this.meta.rootCategoryId]
305
+ reachable.set(this.meta.rootCategoryId, true)
306
+ let shouldSave = false;
307
+
308
+ const usedGroupIds = new Set<string>()
309
+
310
+ while (queue.length > 0) {
311
+ const id = queue.shift()
312
+ if (!id) {
313
+ break
314
+ }
315
+
316
+ const category = this.meta.categories.find(c => c.id === id)
317
+ if (!category) {
318
+ continue
319
+ }
320
+
321
+ for (const i of category.categoryIds) {
322
+ if (!reachable.get(i)) {
323
+ reachable.set(i, true)
324
+ queue.push(i)
325
+ }
326
+ }
327
+
328
+ // Remove groupIds that no longer exist or are in a different category already
329
+ let filtered = category.groupIds.filter(id => !!groups.find(g => g.id === id) && !usedGroupIds.has(id))
330
+
331
+ // Remove duplicate groups
332
+ filtered = Formatter.uniqueArray(filtered)
333
+
334
+ if (filtered.length !== category.groupIds.length) {
335
+ shouldSave = true;
336
+ console.log("Deleted "+ (category.groupIds.length - filtered.length) +" group ids from category " + category.id + ", in organization "+this.id)
337
+ category.groupIds = filtered
338
+ }
339
+
340
+ for (const groupId of category.groupIds) {
341
+ usedGroupIds.add(groupId)
342
+ }
343
+ }
344
+
345
+ const reachableCategoryIds = [...reachable.keys()]
346
+
347
+ // Delete all categories that are not reachable anymore
348
+ const beforeCount = this.meta.categories.length;
349
+ this.meta.categories = this.meta.categories.filter(c => reachableCategoryIds.includes(c.id))
350
+
351
+ if (this.meta.categories.length !== beforeCount) {
352
+ console.log("Deleted "+ (beforeCount - this.meta.categories.length) +" categories from organization "+this.id)
353
+ await this.save()
354
+ } else {
355
+ if (shouldSave) {
356
+ await this.save()
357
+ }
358
+ }
359
+ }
360
+
361
+ async updateDNSRecords() {
362
+ const organization = this;
363
+
364
+ // Check initial status
365
+ let isValidRecords = true
366
+ for (const record of organization.privateMeta.dnsRecords) {
367
+ if (record.status != DNSRecordStatus.Valid) {
368
+ isValidRecords = false
369
+ }
370
+ }
371
+
372
+ const { allValid } = await validateDNSRecords(organization.privateMeta.dnsRecords)
373
+
374
+ if (organization.registerDomain ?? organization.privateMeta.pendingRegisterDomain) {
375
+ const registerDomainRecord = (organization.privateMeta.pendingRegisterDomain ?? organization.registerDomain)+"."
376
+ const records = organization.privateMeta.dnsRecords.filter(r => r.name === registerDomainRecord)
377
+ const areRegisterDomainRecordsValid = records.length === 0 || records.every(r => r.status === DNSRecordStatus.Valid)
378
+
379
+ if (areRegisterDomainRecordsValid) {
380
+ // We can setup the register domain if needed
381
+ if (organization.privateMeta.pendingRegisterDomain !== null) {
382
+ organization.registerDomain = organization.privateMeta.pendingRegisterDomain
383
+ organization.privateMeta.pendingRegisterDomain = null;
384
+
385
+ console.log("Did set register domain for "+this.id+" to "+organization.registerDomain)
386
+ }
387
+ } else {
388
+ // Clear register domain
389
+ if (organization.registerDomain) {
390
+ // We need to clear it, to prevent sending e-mails with invalid links
391
+ organization.privateMeta.pendingRegisterDomain = organization.privateMeta.pendingRegisterDomain ?? organization.registerDomain
392
+ organization.registerDomain = null
393
+
394
+ console.log("Cleared register domain for "+this.id+" because of invalid non txt records")
395
+ }
396
+ }
397
+ }
398
+
399
+ if (allValid) {
400
+ if (organization.privateMeta.pendingMailDomain !== null) {
401
+ organization.privateMeta.mailDomain = organization.privateMeta.pendingMailDomain
402
+ organization.privateMeta.pendingMailDomain = null;
403
+ }
404
+
405
+ const wasUnstable = organization.serverMeta.isDNSUnstable
406
+ organization.serverMeta.markDNSValid()
407
+
408
+ const didSendDomainSetupMail = organization.serverMeta.didSendDomainSetupMail
409
+ const didSendWarning = organization.serverMeta.DNSRecordWarningCount > 0
410
+ organization.serverMeta.DNSRecordWarningCount = 0
411
+
412
+ const wasActive = this.privateMeta.mailDomainActive
413
+ await this.updateAWSMailIdenitity()
414
+
415
+ // yay! Do not Save until after doing AWS changes
416
+ await organization.save()
417
+
418
+ if (wasUnstable && !organization.serverMeta.isDNSUnstable) {
419
+ console.warn('DNS settings became stable for ' + this.name + ' '+this.id)
420
+
421
+ await this.sendEmailTemplate({
422
+ type: EmailTemplateType.OrganizationStableDNS,
423
+ bcc: true
424
+ })
425
+
426
+ } else if (!wasActive && this.privateMeta.mailDomainActive && (!didSendDomainSetupMail || didSendWarning) && !organization.serverMeta.isDNSUnstable) {
427
+ organization.serverMeta.didSendDomainSetupMail = true
428
+ await organization.save()
429
+
430
+ if (!didSendDomainSetupMail) {
431
+ await this.sendEmailTemplate({
432
+ type: EmailTemplateType.OrganizationDNSSetupComplete
433
+ })
434
+ } else {
435
+ await this.sendEmailTemplate({
436
+ type: EmailTemplateType.OrganizationValidDNS
437
+ })
438
+ }
439
+ }
440
+ } else {
441
+ // DNS settings gone broken
442
+ if (organization.privateMeta.mailDomain) {
443
+ organization.privateMeta.pendingMailDomain = organization.privateMeta.pendingMailDomain ?? organization.privateMeta.mailDomain
444
+ organization.privateMeta.mailDomain = null
445
+ }
446
+
447
+ const wasDNSUnstable = organization.serverMeta.isDNSUnstable
448
+
449
+ organization.serverMeta.markDNSFailure()
450
+
451
+ // disable AWS emails
452
+ this.privateMeta.mailDomainActive = false
453
+
454
+ // save
455
+ await organization.save()
456
+
457
+ if (!wasDNSUnstable && organization.serverMeta.isDNSUnstable) {
458
+ // DNS became instable
459
+ console.warn('DNS settings became instable for ' + this.name + ' '+this.id)
460
+
461
+ await this.sendEmailTemplate({
462
+ type: EmailTemplateType.OrganizationUnstableDNS,
463
+ bcc: true
464
+ })
465
+ } else if (!organization.serverMeta.isDNSUnstable && organization.serverMeta.didSendDomainSetupMail && organization.serverMeta.DNSRecordWarningCount == 0) {
466
+ organization.serverMeta.DNSRecordWarningCount += 1
467
+ await organization.save()
468
+
469
+ await this.sendEmailTemplate({
470
+ type: EmailTemplateType.OrganizationInvalidDNS
471
+ })
472
+ }
473
+ }
474
+ }
475
+
476
+ async sendEmailTemplate(data: {
477
+ type: EmailTemplateType,
478
+ personal?: boolean,
479
+ replyTo?: string,
480
+ bcc?: boolean
481
+ }) {
482
+ // First fetch template
483
+ const templates = (await EmailTemplate.where({ type: data.type, organizationId: null }))
484
+
485
+ if (templates.length == 0) {
486
+ console.error("Could not find email template for type "+data.type)
487
+ return
488
+ }
489
+
490
+ const template = templates[0]
491
+
492
+ const recipients = await this.getAdminRecipients();
493
+
494
+ const defaultI18n = new I18n("nl", Country.Belgium)
495
+ const i18n = this.i18n;
496
+
497
+ const replacementStrings = [
498
+ {
499
+ from: defaultI18n.$t("shared.domains.marketing"),
500
+ to: i18n.$t("shared.domains.marketing")
501
+ },
502
+ {
503
+ from: defaultI18n.$t("shared.emails.general"),
504
+ to: i18n.$t("shared.emails.general")
505
+ },
506
+ {
507
+ from: defaultI18n.$t("shared.domains.email"),
508
+ to: i18n.$t("shared.domains.email")
509
+ }
510
+ ];
511
+
512
+ let html = template.html;
513
+
514
+ for (const s of replacementStrings) {
515
+ html = html.replaceAll(s.from, s.to)
516
+ }
517
+
518
+ // Create e-mail builder
519
+ const builder = await getEmailBuilder(this, {
520
+ recipients,
521
+ subject: template.subject,
522
+ html,
523
+ from: data.personal ? Email.getPersonalEmailFor(this.i18n) : Email.getInternalEmailFor(this.i18n),
524
+ singleBcc: data.bcc ? 'simon@stamhoofd.be' : undefined,
525
+ replyTo: data.replyTo,
526
+ type: 'transactional',
527
+ defaultReplacements: [
528
+ Replacement.create({
529
+ token: 'mailDomain',
530
+ value: this.privateMeta.mailDomain ?? this.privateMeta.pendingMailDomain ?? ''
531
+ })
532
+ ],
533
+ unsubscribeType: 'marketing',
534
+ fromStamhoofd: true
535
+ })
536
+
537
+ Email.schedule(builder)
538
+ }
539
+
540
+ async deleteAWSMailIdenitity(mailDomain: string) {
541
+
542
+ // Protect specific domain names
543
+ if (["stamhoofd.be", "stamhoofd.nl", "stamhoofd.shop", "stamhoofd.app", "stamhoofd.email"].includes(mailDomain)) {
544
+ return
545
+ }
546
+
547
+ if (STAMHOOFD.environment != "production") {
548
+ // Temporary ignore this
549
+ return;
550
+ }
551
+
552
+ const sesv2 = new SES();
553
+
554
+ // Check if mail identitiy already exists..
555
+ let exists = false
556
+ let existing: PromiseResult<SES.GetEmailIdentityResponse, AWSError> | undefined = undefined
557
+ try {
558
+ existing = await sesv2.getEmailIdentity({
559
+ EmailIdentity: mailDomain
560
+ }).promise()
561
+ exists = true
562
+
563
+ // Check if DKIM keys are the same
564
+ if (existing.VerifiedForSendingStatus === true) {
565
+ console.log("Cant delete AWS mail idenitiy @"+this.id+" for "+mailDomain+": already validated and might be in use by other organizations")
566
+ return
567
+ }
568
+
569
+ console.log("Deleting AWS mail idenitiy @"+this.id+" for "+mailDomain)
570
+
571
+ await sesv2.deleteEmailIdentity({
572
+ EmailIdentity: mailDomain
573
+ }).promise()
574
+ console.log("Deleted AWS mail idenitiy @"+this.id+" for "+this.privateMeta.mailDomain)
575
+
576
+ } catch (e) {
577
+ console.error("Could not delete AWS email identitiy @"+this.id+" for "+this.privateMeta.mailDomain)
578
+ console.error(e)
579
+ }
580
+ }
581
+
582
+ /**
583
+ * Create or update the AWS mail idenitiy and also update the active state of the mailDomain
584
+ */
585
+ async updateAWSMailIdenitity() {
586
+ if (this.privateMeta.mailDomain === null) {
587
+ return;
588
+ }
589
+
590
+ // Protect specific domain names
591
+ if (["stamhoofd.be", "stamhoofd.nl", "stamhoofd.shop", "stamhoofd.app", "stamhoofd.email"].includes(this.privateMeta.mailDomain)) {
592
+ console.error("Tried to validate AWS mail identity with protected domains @"+this.id)
593
+ this.privateMeta.mailDomainActive = false;
594
+ return
595
+ }
596
+
597
+ if (STAMHOOFD.environment != "production") {
598
+ // Temporary ignore this
599
+ this.privateMeta.mailDomainActive = true;
600
+ return;
601
+ }
602
+
603
+ const sesv2 = new SES();
604
+
605
+ // Check if mail identitiy already exists..
606
+ let exists = false
607
+ let existing: PromiseResult<SES.GetEmailIdentityResponse, AWSError> | undefined = undefined
608
+ try {
609
+ existing = await sesv2.getEmailIdentity({
610
+ EmailIdentity: this.privateMeta.mailDomain
611
+ }).promise()
612
+ exists = true
613
+
614
+ console.log("AWS mail idenitiy exists already: just checking the verification status in AWS @"+this.id)
615
+
616
+ if (existing.ConfigurationSetName !== "stamhoofd-domains") {
617
+ // Not allowed to use this identity
618
+ this.privateMeta.mailDomainActive = false;
619
+ console.error("Organization is not allowed to use email identity "+this.privateMeta.mailDomain+" @"+this.id+", got "+existing.ConfigurationSetName)
620
+ return;
621
+ }
622
+
623
+ this.privateMeta.mailDomainActive = existing.VerifiedForSendingStatus ?? false
624
+
625
+ if (existing.VerifiedForSendingStatus !== true) {
626
+ console.error("Not validated @"+this.id)
627
+ }
628
+
629
+ if (existing.VerifiedForSendingStatus !== true && existing.DkimAttributes?.Status === "FAILED") {
630
+ console.error("AWS failed to verify DKIM records. Triggering a forced recheck @"+this.id)
631
+ await sesv2.deleteEmailIdentity({
632
+ EmailIdentity: this.privateMeta.mailDomain
633
+ }).promise()
634
+
635
+ // Recreate it immediately
636
+ exists = false
637
+ }
638
+ } catch (e) {
639
+ console.error(e)
640
+ }
641
+
642
+ if (!exists) {
643
+ console.log("Creating email identity in AWS SES...")
644
+
645
+ const result = await sesv2.createEmailIdentity({
646
+ EmailIdentity: this.privateMeta.mailDomain,
647
+ ConfigurationSetName: "stamhoofd-domains",
648
+ DkimSigningAttributes: {
649
+ DomainSigningPrivateKey: this.serverMeta.privateDKIMKey!,
650
+ DomainSigningSelector: "stamhoofd"
651
+ },
652
+ Tags: [
653
+ {
654
+ "Key": "OrganizationId",
655
+ "Value": this.id
656
+ },
657
+ {
658
+ "Key": "Environment",
659
+ "Value": STAMHOOFD.environment ?? "Unknown"
660
+ }
661
+ ]
662
+
663
+ }).promise()
664
+ this.privateMeta.mailDomainActive = result.VerifiedForSendingStatus ?? false
665
+
666
+ // Disable email forwarding of bounces and complaints
667
+ // We handle this now with the configuration set
668
+ await sesv2.putEmailIdentityFeedbackAttributes({
669
+ EmailIdentity: this.privateMeta.mailDomain,
670
+ EmailForwardingEnabled: false
671
+ }).promise()
672
+ }
673
+
674
+ if (this.privateMeta.mailFromDomain && (!exists || (existing && (!existing.MailFromAttributes || existing.MailFromAttributes.MailFromDomain !== this.privateMeta.mailFromDomain)))) {
675
+ // Also set a from domain, to fix SPF
676
+ console.log("Setting mail from domain: "+this.privateMeta.mailFromDomain+" for "+this.id)
677
+ const params = {
678
+ EmailIdentity: this.privateMeta.mailDomain,
679
+ BehaviorOnMxFailure: "USE_DEFAULT_VALUE",
680
+ MailFromDomain: this.privateMeta.mailFromDomain,
681
+ };
682
+ await sesv2.putEmailIdentityMailFromAttributes(params).promise();
683
+ }
684
+ }
685
+
686
+ async checkDrips() {
687
+ const days7 = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000)
688
+
689
+ // Welcome drip
690
+ // Created maximum 7 days ago
691
+ if (this.createdAt > days7 && !this.serverMeta.hasEmail(EmailTemplateType.OrganizationDripWelcome)) {
692
+ await this.sendEmailTemplate({
693
+ type: EmailTemplateType.OrganizationDripWelcome,
694
+ personal: true
695
+ })
696
+
697
+ this.serverMeta.addEmail(EmailTemplateType.OrganizationDripWelcome);
698
+ await this.save();
699
+
700
+ return; // Never send more than 1 drip email on the same day
701
+ }
702
+
703
+ // Webshop trial checkin
704
+ if (!this.serverMeta.hasEmail(EmailTemplateType.OrganizationDripWebshopTrialCheckin)) {
705
+ if (this.meta.packages.isWebshopsTrial) {
706
+ const activeTime = this.meta.packages.getActiveTime(STPackageType.TrialWebshops)
707
+ if (activeTime !== null && activeTime > 4 * 24 * 60 * 60 * 1000) {
708
+ // 7 days checkin
709
+ await this.sendEmailTemplate({
710
+ type: EmailTemplateType.OrganizationDripWebshopTrialCheckin,
711
+ personal: true
712
+ })
713
+
714
+ this.serverMeta.addEmail(EmailTemplateType.OrganizationDripWebshopTrialCheckin);
715
+ this.serverMeta.addEmail(EmailTemplateType.OrganizationDripMembersTrialCheckin); // also mark members checkin
716
+ await this.save();
717
+
718
+ return; // Never send more than 1 drip email on the same day
719
+ }
720
+ }
721
+ }
722
+
723
+ // Members trial checkin
724
+ if (!this.serverMeta.hasEmail(EmailTemplateType.OrganizationDripMembersTrialCheckin)) {
725
+ if (this.meta.packages.isMembersTrial) {
726
+ const activeTime = this.meta.packages.getActiveTime(STPackageType.TrialMembers)
727
+ if (activeTime !== null && activeTime > 4 * 24 * 60 * 60 * 1000) {
728
+ // 7 days checkin
729
+ await this.sendEmailTemplate({
730
+ type: EmailTemplateType.OrganizationDripMembersTrialCheckin,
731
+ personal: true
732
+ })
733
+
734
+ this.serverMeta.addEmail(EmailTemplateType.OrganizationDripMembersTrialCheckin);
735
+ this.serverMeta.addEmail(EmailTemplateType.OrganizationDripWebshopTrialCheckin); // Also mark webshop trial checkin
736
+ await this.save();
737
+
738
+ return; // Never send more than 1 drip email on the same day
739
+ }
740
+ }
741
+ }
742
+
743
+ // Webshop trial expired after 1 week
744
+ if (!this.serverMeta.hasEmail(EmailTemplateType.OrganizationDripWebshopTrialExpired)) {
745
+ if (!this.meta.packages.useWebshops) {
746
+ const deactivatedTime = this.meta.packages.getDeactivatedTime(STPackageType.TrialWebshops)
747
+ if (deactivatedTime !== null && deactivatedTime < 14 * 24 * 60 * 60 * 1000 && deactivatedTime > 7 * 24 * 60 * 60 * 1000) {
748
+ await this.sendEmailTemplate({
749
+ type: EmailTemplateType.OrganizationDripWebshopTrialExpired,
750
+ personal: true
751
+ })
752
+
753
+ this.serverMeta.addEmail(EmailTemplateType.OrganizationDripWebshopTrialExpired);
754
+ this.serverMeta.addEmail(EmailTemplateType.OrganizationDripMembersTrialExpired); // also mark members
755
+ await this.save();
756
+
757
+ return; // Never send more than 1 drip email on the same day
758
+ }
759
+ }
760
+ }
761
+
762
+ if (!this.serverMeta.hasEmail(EmailTemplateType.OrganizationDripMembersTrialExpired)) {
763
+ if (!this.meta.packages.useMembers) {
764
+ const deactivatedTime = this.meta.packages.getDeactivatedTime(STPackageType.TrialMembers)
765
+ if (deactivatedTime !== null && deactivatedTime < 14 * 24 * 60 * 60 * 1000 && deactivatedTime > 7 * 24 * 60 * 60 * 1000) {
766
+ await this.sendEmailTemplate({
767
+ type: EmailTemplateType.OrganizationDripMembersTrialExpired,
768
+ personal: true
769
+ })
770
+
771
+ this.serverMeta.addEmail(EmailTemplateType.OrganizationDripMembersTrialExpired);
772
+ this.serverMeta.addEmail(EmailTemplateType.OrganizationDripWebshopTrialExpired); // also mark webshops
773
+ await this.save();
774
+
775
+ return; // Never send more than 1 drip email on the same day
776
+ }
777
+ }
778
+ }
779
+
780
+ // trial expired reminder (after 10 months)
781
+ if (!this.serverMeta.hasEmail(EmailTemplateType.OrganizationDripTrialExpiredReminder)) {
782
+ if (!this.meta.packages.isPaid && !this.meta.packages.wasPaid) {
783
+ const deactivatedTime1 = this.meta.packages.getDeactivatedTime(STPackageType.TrialWebshops)
784
+ const deactivatedTime2 = this.meta.packages.getDeactivatedTime(STPackageType.TrialMembers)
785
+
786
+ const deactivatedTime = deactivatedTime1 && deactivatedTime2 ? Math.max(deactivatedTime1, deactivatedTime2) : (deactivatedTime1 ? deactivatedTime1 : deactivatedTime2)
787
+
788
+ if (deactivatedTime !== null && deactivatedTime > 10 * 30 * 24 * 60 * 60 * 1000 && deactivatedTime < 13 * 31 * 24 * 60 * 60 * 1000) {
789
+ await this.sendEmailTemplate({
790
+ type: EmailTemplateType.OrganizationDripTrialExpiredReminder,
791
+ personal: true,
792
+ bcc: true
793
+ })
794
+
795
+ this.serverMeta.addEmail(EmailTemplateType.OrganizationDripTrialExpiredReminder);
796
+ await this.save();
797
+
798
+ return; // Never send more than 1 drip email on the same day
799
+ }
800
+ }
801
+ }
802
+
803
+ if (!this.serverMeta.hasEmail(EmailTemplateType.OrganizationDripWebshopNotRenewed)) {
804
+ if (!this.meta.packages.useWebshops) {
805
+ const deactivatedTime = this.meta.packages.getDeactivatedTime(STPackageType.Webshops)
806
+
807
+ if (deactivatedTime !== null && deactivatedTime > 30 * 24 * 60 * 60 * 1000 && deactivatedTime < 30*3 * 24 * 60 * 60 * 1000) {
808
+ await this.sendEmailTemplate({
809
+ type: EmailTemplateType.OrganizationDripWebshopNotRenewed,
810
+ personal: true,
811
+ bcc: true
812
+ })
813
+
814
+ this.serverMeta.addEmail(EmailTemplateType.OrganizationDripWebshopNotRenewed);
815
+ await this.save();
816
+
817
+ return; // Never send more than 1 drip email on the same day
818
+ }
819
+ }
820
+ }
821
+
822
+ if (!this.serverMeta.hasEmail(EmailTemplateType.OrganizationDripMembersNotRenewed)) {
823
+ if (!this.meta.packages.useMembers) {
824
+ const deactivatedTime = this.meta.packages.getDeactivatedTime(STPackageType.Members)
825
+
826
+ if (deactivatedTime !== null && deactivatedTime > 30 * 24 * 60 * 60 * 1000 && deactivatedTime < 30*3 * 24 * 60 * 60 * 1000) {
827
+ await this.sendEmailTemplate({
828
+ type: EmailTemplateType.OrganizationDripMembersNotRenewed,
829
+ personal: true,
830
+ bcc: true
831
+ })
832
+
833
+ this.serverMeta.addEmail(EmailTemplateType.OrganizationDripMembersNotRenewed);
834
+ await this.save();
835
+
836
+ return; // Never send more than 1 drip email on the same day
837
+ }
838
+ }
839
+ }
840
+ }
841
+
842
+ /**
843
+ * E-mail address when we receive replies for organization@stamhoofd.email.
844
+ * Note that this sould be private because it can contain personal e-mail addresses if the organization is not configured correctly
845
+ */
846
+ async getReplyEmails(): Promise<EmailInterfaceRecipient[]> {
847
+ const sender: OrganizationEmail | undefined = this.privateMeta.emails.find(e => e.default) ?? this.privateMeta.emails[0];
848
+
849
+ if (sender) {
850
+ return [
851
+ {
852
+ name: sender.name,
853
+ email: sender.email
854
+ }
855
+ ]
856
+ }
857
+
858
+ return await this.getAdminToEmails()
859
+ }
860
+
861
+ /**
862
+ * These email addresess are private
863
+ */
864
+ async getFullAdmins() {
865
+ // Circular reference fix
866
+ const User = (await import('./User')).User;
867
+ const admins = await User.getAdmins([this.id], {verified: true})
868
+
869
+ // Only full access
870
+ return admins.filter(a => a.permissions && a.permissions.forOrganization(this)?.hasFullAccess())
871
+ }
872
+
873
+ /**
874
+ * These email addresess are private
875
+ */
876
+ async getAdminToEmails(): Promise<EmailInterfaceRecipient[]> {
877
+ const filtered = await this.getFullAdmins()
878
+
879
+ if (STAMHOOFD.environment === "production") {
880
+ if (filtered.length > 1) {
881
+ // remove stamhoofd email addresses
882
+ const f = filtered.flatMap(f => f.getEmailTo() ).filter(e => !e.email.endsWith("@stamhoofd.be") && !e.email.endsWith("@stamhoofd.nl"))
883
+ if (f.length > 0) {
884
+ return f
885
+ }
886
+ }
887
+ }
888
+
889
+ return filtered.flatMap(f => f.getEmailTo() )
890
+ }
891
+
892
+ /**
893
+ * These email addresess are private
894
+ */
895
+ async getAdminRecipients(): Promise<Recipient[]> {
896
+ let filtered = await this.getFullAdmins()
897
+
898
+ if (STAMHOOFD.environment === "production") {
899
+ if (filtered.length > 1) {
900
+ // remove stamhoofd email addresses
901
+ filtered = filtered.filter(e => !e.email.endsWith("@stamhoofd.be") && !e.email.endsWith("@stamhoofd.nl"))
902
+ }
903
+ }
904
+
905
+ return filtered.flatMap(f => {
906
+ return Recipient.create({
907
+ firstName: f.firstName,
908
+ lastName: f.lastName,
909
+ email: f.email,
910
+ replacements: [
911
+ Replacement.create({
912
+ token: "firstName",
913
+ value: f.firstName ?? ""
914
+ }),
915
+ Replacement.create({
916
+ token: "lastName",
917
+ value: f.lastName ?? ""
918
+ }),
919
+ Replacement.create({
920
+ token: "email",
921
+ value: f.email
922
+ }),
923
+ Replacement.create({
924
+ token: "organizationName",
925
+ value: this.name
926
+ })
927
+ ]
928
+ })
929
+ } )
930
+ }
931
+
932
+ /**
933
+ * These email addresess are private
934
+ */
935
+ async getInvoicingToEmails() {
936
+ // Circular reference fix
937
+ const User = (await import('./User')).User;
938
+ const admins = await User.where({ organizationId: this.id, permissions: { sign: "!=", value: null }})
939
+ const filtered = admins.filter(a => a.organizationPermissions && (a.organizationPermissions.hasFullAccess(this.privateMeta.roles) || a.organizationPermissions.hasFinanceAccess(this.privateMeta.roles)))
940
+
941
+ if (filtered.length > 0) {
942
+ return filtered.map(f => f.getEmailTo() ).join(", ")
943
+ }
944
+
945
+ return undefined
946
+ }
947
+
948
+ /**
949
+ * Return default e-mail address for important e-mails that should have the highest deliverability
950
+ */
951
+ getStrongEmail(i18n: I18n, withName = true) {
952
+ if (!withName) {
953
+ return ('noreply-' + this.uri+"@"+i18n.$t("shared.domains.email"));
954
+ }
955
+ return '"'+this.name.replaceAll("\"", "\\\"")+'" <'+ ('noreply-' + this.uri+"@"+i18n.$t("shared.domains.email")) +'>'
956
+ }
957
+
958
+ getEmail(id: string | null, strongDefault = false): { from: string; replyTo: string | undefined } {
959
+ if (id === null) {
960
+ return this.getDefaultEmail(strongDefault)
961
+ }
962
+
963
+ // Send confirmation e-mail
964
+ let from = strongDefault ? this.getStrongEmail(this.i18n, false) : this.uri+"@stamhoofd.email";
965
+ const sender: OrganizationEmail | undefined = this.privateMeta.emails.find(e => e.id === id)
966
+ let replyTo: string | undefined = undefined
967
+
968
+ if (sender) {
969
+ replyTo = sender.email
970
+
971
+ // Can we send from this e-mail or reply-to?
972
+ if (replyTo && this.privateMeta.mailDomain && this.privateMeta.mailDomainActive && sender.email.endsWith("@"+this.privateMeta.mailDomain)) {
973
+ from = sender.email
974
+ replyTo = undefined
975
+ }
976
+
977
+ // Include name in form field
978
+ if (sender.name) {
979
+ from = '"'+sender.name.replaceAll("\"", "\\\"")+"\" <"+from+">"
980
+ } else {
981
+ from = '"'+this.name.replaceAll("\"", "\\\"")+"\" <"+from+">"
982
+ }
983
+
984
+ if (replyTo) {
985
+ if (sender.name) {
986
+ replyTo = '"'+sender.name.replaceAll("\"", "\\\"")+"\" <"+replyTo+">"
987
+ } else {
988
+ replyTo = '"'+this.name.replaceAll("\"", "\\\"")+"\" <"+replyTo+">"
989
+ }
990
+ }
991
+ return { from, replyTo }
992
+ }
993
+ return this.getDefaultEmail(strongDefault)
994
+ }
995
+
996
+ getGroupEmail(group: Group) {
997
+ return this.getEmail(group.privateSettings.defaultEmailId)
998
+ }
999
+
1000
+ getDefaultEmail(strongDefault = false): { from: string; replyTo: string | undefined } {
1001
+ // Send confirmation e-mail
1002
+ let from = strongDefault ? this.getStrongEmail(this.i18n, false) : this.uri+"@stamhoofd.email";
1003
+ const sender: OrganizationEmail | undefined = this.privateMeta.emails.find(e => e.default) ?? this.privateMeta.emails[0];
1004
+ let replyTo: string | undefined = undefined
1005
+
1006
+ if (sender) {
1007
+ replyTo = sender.email
1008
+
1009
+ // Can we send from this e-mail or reply-to?
1010
+ if (replyTo && this.privateMeta.mailDomain && this.privateMeta.mailDomainActive && sender.email.endsWith("@"+this.privateMeta.mailDomain)) {
1011
+ from = sender.email
1012
+ replyTo = undefined
1013
+ }
1014
+
1015
+ // Include name in form field
1016
+ if (sender.name) {
1017
+ from = '"'+sender.name.replaceAll("\"", "\\\"")+"\" <"+from+">"
1018
+ } else {
1019
+ from = '"'+this.name.replaceAll("\"", "\\\"")+"\" <"+from+">"
1020
+ }
1021
+
1022
+ if (replyTo) {
1023
+ if (sender.name) {
1024
+ replyTo = '"'+sender.name.replaceAll("\"", "\\\"")+"\" <"+replyTo+">"
1025
+ } else {
1026
+ replyTo = '"'+this.name.replaceAll("\"", "\\\"")+"\" <"+replyTo+">"
1027
+ }
1028
+ }
1029
+ } else {
1030
+ from = '"'+this.name.replaceAll("\"", "\\\"")+"\" <"+from+">"
1031
+ }
1032
+
1033
+ return {
1034
+ from, replyTo
1035
+ }
1036
+ }
1037
+
1038
+ async getPaymentProviderFor(method: PaymentMethod, config: PrivatePaymentConfiguration): Promise<{
1039
+ provider: PaymentProvider | null,
1040
+ stripeAccount: StripeAccount | null
1041
+ }> {
1042
+ let stripeAccount = (config.stripeAccountId ? (await StripeAccount.getByID(config.stripeAccountId)) : null) ?? null
1043
+ if (stripeAccount && stripeAccount.organizationId !== this.id) {
1044
+ console.warn('Stripe account '+stripeAccount.id+' is not linked to organization '+this.id);
1045
+ stripeAccount = null
1046
+ }
1047
+ const provider = this.privateMeta.getPaymentProviderFor(method, stripeAccount?.meta)
1048
+ if (provider === null && ![PaymentMethod.Unknown, PaymentMethod.Transfer, PaymentMethod.PointOfSale].includes(method)) {
1049
+ if (!stripeAccount && config.stripeAccountId) {
1050
+ console.warn('Missing stripe account id ' + config.stripeAccountId);
1051
+ }
1052
+ throw new SimpleError({
1053
+ code: 'payment_provider_not_configured',
1054
+ message: 'Payment provider not configured for '+method,
1055
+ human: 'Deze betaalmethode werd helaas niet volledig geconfigureerd. Probeer later even opnieuw, neem contact met ons op of kies een andere betaalmethode.'
1056
+ })
1057
+ }
1058
+ return {
1059
+ provider,
1060
+ stripeAccount
1061
+ }
1062
+ }
1063
+
1064
+ async getConnectedPaymentProviders(): Promise<PaymentProvider[]> {
1065
+ const allPaymentMethods = Object.values(PaymentMethod)
1066
+ const providers: PaymentProvider[] = []
1067
+
1068
+ let stripeAccounts: (StripeAccount|null)[] = await StripeAccount.where({ organizationId: this.id, status: 'active' })
1069
+
1070
+ if (stripeAccounts.length === 0) {
1071
+ stripeAccounts = [null]
1072
+ }
1073
+
1074
+ for (const account of stripeAccounts) {
1075
+ for (const method of allPaymentMethods) {
1076
+ const provider = this.privateMeta.getPaymentProviderFor(method, account?.meta)
1077
+ if (provider && !providers.includes(provider)) {
1078
+ providers.push(provider)
1079
+ }
1080
+ }
1081
+ }
1082
+
1083
+ return providers
1084
+ }
1085
+ }