@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,583 @@
1
+
2
+ import { column, Model } from "@simonbackx/simple-database";
3
+ import { isSimpleError, isSimpleErrors, SimpleError } from "@simonbackx/simple-errors";
4
+ import { QueueHandler } from "@stamhoofd/queues";
5
+ import { DocumentData, DocumentPrivateSettings, DocumentSettings, DocumentStatus, DocumentTemplatePrivate, RecordAddressAnswer, RecordAnswer, RecordAnswerDecoder, RecordDateAnswer, RecordPriceAnswer, RecordSettings, RecordTextAnswer, RecordType } from '@stamhoofd/structures';
6
+ import { Sorter } from "@stamhoofd/utility";
7
+ import { v4 as uuidv4 } from "uuid";
8
+
9
+ import { render } from "../helpers/Handlebars";
10
+ import { BalanceItem } from "./BalanceItem";
11
+ import { Document } from "./Document";
12
+ import { Group } from "./Group";
13
+ import { Member, RegistrationWithMember } from "./Member";
14
+ import { Organization } from "./Organization";
15
+
16
+ export class DocumentTemplate extends Model {
17
+ static table = "document_templates";
18
+
19
+ @column({ primary: true, type: "string", beforeSave(value) {
20
+ return value ?? uuidv4();
21
+ } })
22
+ id!: string;
23
+
24
+ /**
25
+ * The HTML that is used to generate the PDF
26
+ */
27
+ @column({ type: "string" })
28
+ html: string
29
+
30
+ @column({ type: "string"})
31
+ organizationId: string
32
+
33
+ @column({ type: "string" })
34
+ status = DocumentStatus.Draft
35
+
36
+ @column({ type: "boolean" })
37
+ updatesEnabled = true
38
+
39
+ /**
40
+ * Settings of the smart document. This information is public
41
+ */
42
+ @column({ type: "json", decoder: DocumentSettings })
43
+ settings: DocumentSettings
44
+
45
+ /**
46
+ *
47
+ */
48
+ @column({ type: "json", decoder: DocumentPrivateSettings })
49
+ privateSettings: DocumentPrivateSettings
50
+
51
+ @column({ type: "datetime" })
52
+ createdAt: Date = new Date()
53
+
54
+ @column({
55
+ type: "datetime", beforeSave() {
56
+ const date = new Date()
57
+ date.setMilliseconds(0)
58
+ return date
59
+ },
60
+ skipUpdate: true
61
+ })
62
+ updatedAt: Date
63
+
64
+ getPrivateStructure() {
65
+ return DocumentTemplatePrivate.create(this)
66
+ }
67
+
68
+ /**
69
+ * Returns the default answers for a given registration
70
+ */
71
+ async buildAnswers(registration: RegistrationWithMember): Promise<{fieldAnswers: Map<string, RecordAnswer>, missingData: boolean}> {
72
+ const fieldAnswers = new Map<string, RecordAnswer>()
73
+ let missingData = false
74
+
75
+ const group = await Group.getByID(registration.groupId)
76
+ const {payments} = await BalanceItem.getForRegistration(registration.id)
77
+
78
+ const paidAtDates = payments.flatMap(p => p.paidAt ? [p.paidAt?.getTime()] : [])
79
+
80
+ // We take the minimum date here, because there is a highter change of later paymetns to be for other things than the registration itself
81
+ const paidAt = paidAtDates.length ? new Date(Math.min(...paidAtDates)) : null
82
+
83
+ // Some fields are supported by default in linked fields
84
+ const defaultData: Record<string, RecordAnswer> = {
85
+ //"registration.startDate": registration.group.settings.startDate,
86
+ //"registration.endDate": registration.group.settings.endDate,
87
+ "group.name": RecordTextAnswer.create({
88
+ settings: RecordSettings.create({
89
+ id: "group.name",
90
+ type: RecordType.Text,
91
+ }), // settings will be overwritten
92
+ value: group?.settings?.name ?? ""
93
+ }),
94
+ "registration.startDate": RecordDateAnswer.create({
95
+ settings: RecordSettings.create({
96
+ id: "registration.startDate",
97
+ type: RecordType.Date,
98
+ }), // settings will be overwritten
99
+ dateValue: group?.settings?.getStartDate({cycle: registration.cycle === group.cycle ? undefined : registration.cycle}) ?? null
100
+ }),
101
+ "registration.endDate": RecordDateAnswer.create({
102
+ settings: RecordSettings.create({
103
+ id: "registration.endDate",
104
+ type: RecordType.Date,
105
+ }), // settings will be overwritten
106
+ dateValue: group?.settings?.getEndDate({cycle: registration.cycle === group.cycle ? undefined : registration.cycle}) ?? null
107
+ }),
108
+ "registration.price":
109
+ RecordPriceAnswer.create({
110
+ settings: RecordSettings.create({}), // settings will be overwritten
111
+ value: registration.price
112
+ }),
113
+ "registration.pricePaid":
114
+ RecordPriceAnswer.create({
115
+ settings: RecordSettings.create({}), // settings will be overwritten
116
+ value: registration.pricePaid
117
+ }),
118
+ "registration.paidAt":
119
+ RecordDateAnswer.create({
120
+ settings: RecordSettings.create({
121
+ id: "registration.paidAt",
122
+ type: RecordType.Date,
123
+ }), // settings will be overwritten
124
+ dateValue: paidAt
125
+ }),
126
+ "member.firstName": RecordTextAnswer.create({
127
+ settings: RecordSettings.create({}), // settings will be overwritten
128
+ value: registration.member.details.firstName
129
+ }),
130
+ "member.lastName": RecordTextAnswer.create({
131
+ settings: RecordSettings.create({}), // settings will be overwritten
132
+ value: registration.member.details.lastName
133
+ }),
134
+ "member.address": RecordAddressAnswer.create({
135
+ settings: RecordSettings.create({}), // settings will be overwritten
136
+ address: registration.member.details.address ?? null
137
+ }),
138
+ "member.email": RecordTextAnswer.create({
139
+ settings: RecordSettings.create({}), // settings will be overwritten
140
+ value: registration.member.details.email ?? null
141
+ }),
142
+ "member.birthDay": RecordDateAnswer.create({
143
+ settings: RecordSettings.create({}), // settings will be overwritten
144
+ dateValue: registration.member.details.birthDay
145
+ }),
146
+ "parents[0].firstName": RecordTextAnswer.create({
147
+ settings: RecordSettings.create({}), // settings will be overwritten
148
+ value: registration.member.details.parents[0]?.firstName
149
+ }),
150
+ "parents[0].lastName": RecordTextAnswer.create({
151
+ settings: RecordSettings.create({}), // settings will be overwritten
152
+ value: registration.member.details.parents[0]?.lastName
153
+ }),
154
+ "parents[0].address": RecordAddressAnswer.create({
155
+ settings: RecordSettings.create({}), // settings will be overwritten
156
+ address: registration.member.details.parents[0]?.address ?? null
157
+ }),
158
+ "parents[0].email": RecordTextAnswer.create({
159
+ settings: RecordSettings.create({}), // settings will be overwritten
160
+ value: registration.member.details.parents[0]?.email ?? null
161
+ }),
162
+ "parents[1].firstName": RecordTextAnswer.create({
163
+ settings: RecordSettings.create({}), // settings will be overwritten
164
+ value: registration.member.details.parents[1]?.firstName
165
+ }),
166
+ "parents[1].lastName": RecordTextAnswer.create({
167
+ settings: RecordSettings.create({}), // settings will be overwritten
168
+ value: registration.member.details.parents[1]?.lastName
169
+ }),
170
+ "parents[1].address": RecordAddressAnswer.create({
171
+ settings: RecordSettings.create({}), // settings will be overwritten
172
+ address: registration.member.details.parents[1]?.address ?? null
173
+ }),
174
+ "parents[1].email": RecordTextAnswer.create({
175
+ settings: RecordSettings.create({}), // settings will be overwritten
176
+ value: registration.member.details.parents[1]?.email ?? null
177
+ })
178
+ }
179
+
180
+ // Add data that is different for each member
181
+ for (const field of this.privateSettings.templateDefinition.documentFieldCategories.flatMap(c => c.getAllRecords())) {
182
+ // Where do we need to find the answer to this linked field?
183
+ // - Could either return an id of a recordSetting connected to member
184
+ // - or an idea of defaultData that is supported by default
185
+ // The result is always a recordAnswer whose type should match the type of the linkedField
186
+ const linkedToMemberAnswerSettingsIds = this.settings.linkedFields.get(field.id)
187
+
188
+ let found = false;
189
+
190
+ if (linkedToMemberAnswerSettingsIds) {
191
+ for (const linkedToMemberAnswerSettingsId of linkedToMemberAnswerSettingsIds) {
192
+ if (linkedToMemberAnswerSettingsId) {
193
+ const answer = registration.member.details.recordAnswers.get(linkedToMemberAnswerSettingsId);
194
+ if (answer && !answer.isEmpty && answer.settings.type === field.type) {
195
+ // We need to link it with the settings in the template
196
+ const clone = answer.clone()
197
+ clone.settings = field
198
+ clone.reviewedAt = null // All linked fields are not reviewed. Unless they are manually changed by an admin later
199
+
200
+ found = true
201
+ fieldAnswers.set(field.id, clone)
202
+ break;
203
+ }
204
+
205
+ // Check if supported by default
206
+ if (defaultData[linkedToMemberAnswerSettingsId] && !defaultData[linkedToMemberAnswerSettingsId].isEmpty) {
207
+ if (defaultData[linkedToMemberAnswerSettingsId] instanceof RecordAnswerDecoder.getClassForType(field.type)) {
208
+ // We need to clone here, because the same default data can be used in multiple places
209
+ const clone = defaultData[linkedToMemberAnswerSettingsId].clone()
210
+ clone.settings = field
211
+
212
+ found = true
213
+ fieldAnswers.set(field.id, clone)
214
+ break;
215
+ } else {
216
+ console.warn("Found type mismatch for default data: " + linkedToMemberAnswerSettingsId + " - " + field.id)
217
+ }
218
+ }
219
+ }
220
+ }
221
+ }
222
+
223
+ if (!found && field.required) {
224
+ missingData = true;
225
+ }
226
+
227
+ if (!found) {
228
+ // Add placeholder (so we have proper warnings)
229
+ const clone = RecordAnswerDecoder.getClassForType(field.type).create({
230
+ settings: field,
231
+ })
232
+ fieldAnswers.set(field.id, clone)
233
+ }
234
+ }
235
+
236
+ // Add global answers (same for each document)
237
+ for (const answer of this.settings.fieldAnswers.values()) {
238
+ // todo: check duplicate
239
+ answer.reviewedAt = null
240
+ fieldAnswers.set(answer.settings.id, answer)
241
+ }
242
+
243
+ // Add group based answers (same for each group)
244
+ for (const answer of this.privateSettings.groups.find(g => g.groupId === registration.groupId && g.cycle === registration.cycle)?.fieldAnswers?.values() ?? []){
245
+ // todo: check duplicate
246
+ answer.reviewedAt = null
247
+ fieldAnswers.set(answer.settings.id, answer)
248
+ }
249
+
250
+ // Add other default data
251
+ for (const key in defaultData) {
252
+ if (defaultData[key] && defaultData[key].settings.id === key && !fieldAnswers.get(key)) {
253
+ fieldAnswers.set(key, defaultData[key])
254
+ }
255
+ }
256
+
257
+ // Verify answers
258
+ if (!missingData) {
259
+ for (const answer of fieldAnswers.values()) {
260
+ try {
261
+ answer.validate()
262
+ } catch (e) {
263
+ missingData = true
264
+ break;
265
+ }
266
+ }
267
+ }
268
+
269
+ return {
270
+ fieldAnswers,
271
+ missingData
272
+ }
273
+ }
274
+
275
+ async createForRegistrationIfNeeded(registration: RegistrationWithMember) {
276
+ // Check group and cycle
277
+ for (const groupDefinition of this.privateSettings.groups) {
278
+ if (groupDefinition.groupId === registration.groupId && groupDefinition.cycle === registration.cycle) {
279
+ const document = await this.generateForRegistration(registration)
280
+ if (document) {
281
+ await document.save()
282
+ }
283
+ }
284
+ }
285
+ }
286
+
287
+ private async generateForRegistration(registration: RegistrationWithMember) {
288
+ const {fieldAnswers, missingData} = await this.buildAnswers(registration)
289
+ const existingDocuments = await Document.where({ templateId: this.id, registrationId: registration.id }, {limit: 1})
290
+
291
+ if (!this.checkIncluded(registration, fieldAnswers)) {
292
+ if (existingDocuments.length > 0) {
293
+ for (const document of existingDocuments) {
294
+ await document.delete()
295
+ }
296
+ }
297
+ return null
298
+ }
299
+
300
+ const fieldId = 'registration.startDate';
301
+ let startDate: null | Date = null;
302
+
303
+ for (const answer of fieldAnswers) {
304
+ if (answer instanceof RecordDateAnswer) {
305
+ if (answer.settings.id === fieldId && !answer.isEmpty) {
306
+ startDate = answer.dateValue;
307
+ break;
308
+ }
309
+ }
310
+ }
311
+
312
+ const group = await Group.getByID(registration.groupId)
313
+ const description = `${registration.member.details.name}, ${group ? group.settings.name : ''}`;
314
+
315
+ if (existingDocuments.length > 0) {
316
+ for (const document of existingDocuments) {
317
+ await this.updateDocumentFor(document, registration)
318
+ document.data.name = this.settings.name
319
+ document.data.description = description
320
+ if (document.status === DocumentStatus.Draft || document.status === DocumentStatus.Published) {
321
+ document.status = this.status;
322
+ }
323
+ await document.save()
324
+ return document;
325
+ }
326
+ } else {
327
+ const document = new Document()
328
+ document.organizationId = this.organizationId
329
+ document.templateId = this.id
330
+ document.status = missingData ? DocumentStatus.MissingData : this.status;
331
+ document.data = DocumentData.create({
332
+ name: this.settings.name,
333
+ description,
334
+ fieldAnswers
335
+ })
336
+ document.memberId = registration.member.id
337
+ document.registrationId = registration.id
338
+ await document.save()
339
+ return document;
340
+ }
341
+ }
342
+
343
+ checkIncluded(registration: RegistrationWithMember, fieldAnswers: Map<string, RecordAnswer>) {
344
+ if (this.settings.maxAge !== null) {
345
+ const fieldId = 'registration.startDate';
346
+ let startDate: null | Date = null;
347
+
348
+ for (const answer of fieldAnswers.values()) {
349
+ if (answer instanceof RecordDateAnswer) {
350
+ if (answer.settings.id === fieldId && !answer.isEmpty) {
351
+ startDate = answer.dateValue;
352
+ break;
353
+ }
354
+ }
355
+ }
356
+
357
+ if (startDate) {
358
+ const age = registration.member.details.ageOnDate(startDate)
359
+
360
+ if (age === null) {
361
+ console.warn("Missing member age checking maxAge")
362
+ return false;
363
+ }
364
+
365
+ if (age > this.settings.maxAge) {
366
+ return false;
367
+ }
368
+ } else {
369
+ console.warn("Missing registration.startDate in fieldAnswers when checking maxAge")
370
+ }
371
+ }
372
+
373
+ if (this.settings.minPrice !== null) {
374
+ const fieldId = 'registration.price';
375
+ let price: null | number = null;
376
+
377
+ for (const answer of fieldAnswers) {
378
+ if (answer instanceof RecordPriceAnswer) {
379
+ if (answer.settings.id === fieldId && answer.value !== null) {
380
+ price = answer.value;
381
+ break;
382
+ }
383
+ }
384
+ }
385
+
386
+ if (price !== null) {
387
+ if (price < this.settings.minPrice) {
388
+ return false;
389
+ }
390
+ } else {
391
+ console.warn("Missing registration.price in fieldAnswers when checking minPrice")
392
+ }
393
+ }
394
+
395
+ return true;
396
+ }
397
+
398
+ async buildAll({generateNumbers = false} = {}) {
399
+ return await QueueHandler.schedule("documents-build-all/"+this.id, async () => {
400
+ if (!this.updatesEnabled) {
401
+ // Check status
402
+ const documents = await Document.where({ templateId: this.id })
403
+ for (const document of documents) {
404
+ if (document.status === DocumentStatus.Draft || document.status === DocumentStatus.Published) {
405
+ document.status = this.status;
406
+ await document.save();
407
+ }
408
+ }
409
+
410
+ // Generate numbers for all documents
411
+ if (generateNumbers) {
412
+ let nextNumber = Math.max(0, ...documents.map(d => d.number).filter(n => n !== null) as number[]) + 1
413
+ for (const document of documents) {
414
+ if (document.number === null && document.status === DocumentStatus.Published) {
415
+ document.number = nextNumber;
416
+ await document.save();
417
+ nextNumber++;
418
+ }
419
+ }
420
+ }
421
+ return documents
422
+ }
423
+
424
+ console.log('Building all documents for template', this.id)
425
+ const documentSet: Map<string, Document> = new Map()
426
+
427
+ for (const groupDefinition of this.privateSettings.groups) {
428
+ // Get the registrations for this group with this cycle
429
+ const registrations = await Member.getRegistrationWithMembersForGroup(groupDefinition.groupId, groupDefinition.cycle)
430
+
431
+ for (const registration of registrations) {
432
+ const document = await this.generateForRegistration(registration)
433
+ if (document) {
434
+ documentSet.set(document.id, document)
435
+ }
436
+ }
437
+ }
438
+
439
+ // Delete documents that no longer match and don't have a number yet
440
+ const documents = await Document.where({ templateId: this.id })
441
+ for (const document of documents) {
442
+ if (!documentSet.has(document.id)) {
443
+ if (document.number === null) {
444
+ await document.delete()
445
+ } else {
446
+ document.status = DocumentStatus.Deleted;
447
+ await document.save();
448
+ }
449
+ }
450
+ }
451
+
452
+ const allDocuments = [...documentSet.values()]
453
+
454
+ // Generate numbers for all documents
455
+ if (generateNumbers) {
456
+ let nextNumber = Math.max(0, ...allDocuments.map(d => d.number).filter(n => n !== null) as number[]) + 1
457
+ for (const document of allDocuments) {
458
+ if (document.number === null && document.status === DocumentStatus.Published) {
459
+ document.number = nextNumber;
460
+ await document.save();
461
+ nextNumber++;
462
+ }
463
+ }
464
+ }
465
+
466
+ return allDocuments
467
+ });
468
+ }
469
+
470
+ private async buildContext(organization: Organization) {
471
+ // Convert the field answers in a simplified javascript object
472
+ const documents = (await this.buildAll({generateNumbers: true})).filter(d => d.status === DocumentStatus.Published && !!d.number).sort((a, b) => Sorter.byNumberValue(b.number ?? 0, a.number ?? 0))
473
+
474
+ // Check numbers are strictly increasing
475
+ let lastNumber = 0;
476
+ for (const document of documents) {
477
+ if (document.number !== lastNumber + 1) {
478
+ throw new SimpleError({
479
+ code: "invalid_document_number",
480
+ message: 'Expected document number to be ' + (lastNumber + 1) + ' but got ' + document.number,
481
+ human: "Er ging iets mis bij het nummeren van de documenten (ben je zeker dat je geen documenten hebt verwijderd of toegevoegd sinds de vorige export?). Als je de export nog niet hebt gebruikt in Belcotax kan je de nummering resetten en de export opnieuw proberen.",
482
+ })
483
+ }
484
+ lastNumber = document.number;
485
+ }
486
+
487
+ const data = {
488
+ "id": this.id,
489
+ "created_at": this.createdAt,
490
+ "documents": documents.map(d => d.buildContext(organization)),
491
+ };
492
+
493
+ for (const field of this.settings.fieldAnswers.values()) {
494
+ const keys = field.settings.id.split('.')
495
+ let current = data
496
+ const lastKey = keys.pop()!
497
+ if (!lastKey) {
498
+ throw new Error("Invalid field id")
499
+ }
500
+ for (const key of keys) {
501
+ if (!current[key]) {
502
+ current[key] = {}
503
+ }
504
+ current = current[key]
505
+
506
+ if (typeof current !== "object") {
507
+ throw new Error("Invalid field type")
508
+ }
509
+ }
510
+ current[lastKey] = field.objectValue
511
+ }
512
+
513
+ return data;
514
+ }
515
+
516
+ async getRenderedXml(organization: Organization) {
517
+ if (!this.privateSettings.templateDefinition.xmlExport) {
518
+ return null;
519
+ }
520
+
521
+ try {
522
+ const context = await this.buildContext(organization)
523
+ const renderedHtml = render(this.privateSettings.templateDefinition.xmlExport, context);
524
+ return renderedHtml;
525
+ } catch (e) {
526
+ if (isSimpleError(e) || isSimpleErrors(e)) {
527
+ throw e;
528
+ }
529
+ console.error('Failed to render document html', e)
530
+ return null;
531
+ }
532
+ }
533
+
534
+ areAnswersComplete(answers: Map<string, RecordAnswer>) {
535
+ for (const field of this.privateSettings.templateDefinition.documentFieldCategories.flatMap(c => c.getAllRecords())) {
536
+ const answer = answers.get(field.id)
537
+ if (!answer) {
538
+ return false;
539
+ }
540
+ // Update settings
541
+ answer.settings = field
542
+ try {
543
+ answer.validate()
544
+ } catch (e) {
545
+ // Invalid
546
+ return false;
547
+ }
548
+ }
549
+ return true;
550
+ }
551
+
552
+ async updateDocumentFor(document: Document, registration: RegistrationWithMember) {
553
+ const {fieldAnswers} = await this.buildAnswers(registration)
554
+ const existingAnswers = document.data.fieldAnswers
555
+
556
+ const newAnswers = new Map(existingAnswers)
557
+
558
+ for (const addAnswer of fieldAnswers.values()) {
559
+ const existing = newAnswers.get(addAnswer.settings.id) //newAnswers.findIndex(a => a.settings.id === addAnswer.settings.id)
560
+ if (existing) {
561
+ // We already have an answer for this field, we'll only update it if addAnswer is reviewed later
562
+ if (!existing.isReviewedAfter(addAnswer)) {
563
+ newAnswers.set(addAnswer.settings.id, addAnswer)
564
+ }
565
+ } else {
566
+ newAnswers.set(addAnswer.settings.id, addAnswer)
567
+ }
568
+ }
569
+
570
+ document.data.fieldAnswers = newAnswers
571
+ const complete = this.areAnswersComplete(newAnswers)
572
+
573
+ if (document.status !== DocumentStatus.Deleted) {
574
+ if (!complete) {
575
+ document.status = DocumentStatus.MissingData
576
+ } else {
577
+ if (document.status === DocumentStatus.MissingData) {
578
+ document.status = this.status
579
+ }
580
+ }
581
+ }
582
+ }
583
+ }
@@ -0,0 +1,64 @@
1
+ import { column, Model } from "@simonbackx/simple-database";
2
+ import { AnyDecoder } from "@simonbackx/simple-encoding";
3
+ import { EmailTemplateType } from "@stamhoofd/structures";
4
+ import { v4 as uuidv4 } from "uuid";
5
+
6
+
7
+ /**
8
+ * Holds the challenges for a given email. User should not exist, since that would allow user enumeration attacks
9
+ */
10
+ export class EmailTemplate extends Model {
11
+ static table = "email_templates";
12
+
13
+ @column({
14
+ primary: true, type: "string", beforeSave(value) {
15
+ return value ?? uuidv4();
16
+ }
17
+ })
18
+ id!: string;
19
+
20
+ @column({ type: "string"})
21
+ subject: string;
22
+
23
+ @column({ type: "string", nullable: true })
24
+ organizationId: string | null;
25
+
26
+ @column({ type: "string", nullable: true })
27
+ groupId: string | null = null;
28
+
29
+ @column({ type: "string", nullable: true })
30
+ webshopId: string | null = null;
31
+
32
+ @column({ type: "string" })
33
+ type: EmailTemplateType; // should be enumeration
34
+
35
+ /** Raw json structure to edit the template */
36
+ @column({ type: "json", decoder: AnyDecoder })
37
+ json: any;
38
+
39
+ /** Template converted to HTML, with the {{replacements}} already correctly in place */
40
+ @column({ type: "string" })
41
+ html: string;
42
+
43
+ @column({ type: "string" })
44
+ text: string;
45
+
46
+ @column({
47
+ type: "datetime", beforeSave() {
48
+ const date = new Date()
49
+ date.setMilliseconds(0)
50
+ return date
51
+ }
52
+ })
53
+ createdAt: Date
54
+
55
+ @column({
56
+ type: "datetime", beforeSave() {
57
+ const date = new Date()
58
+ date.setMilliseconds(0)
59
+ return date
60
+ },
61
+ skipUpdate: true
62
+ })
63
+ updatedAt: Date
64
+ }