@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.
- package/dist/src/assets/Metropolis-Black.woff2 +0 -0
- package/dist/src/assets/Metropolis-BlackItalic.woff2 +0 -0
- package/dist/src/assets/Metropolis-Bold.woff2 +0 -0
- package/dist/src/assets/Metropolis-BoldItalic.woff2 +0 -0
- package/dist/src/assets/Metropolis-ExtraBold.woff2 +0 -0
- package/dist/src/assets/Metropolis-ExtraBoldItalic.woff2 +0 -0
- package/dist/src/assets/Metropolis-ExtraLight.woff2 +0 -0
- package/dist/src/assets/Metropolis-ExtraLightItalic.woff2 +0 -0
- package/dist/src/assets/Metropolis-Light.woff2 +0 -0
- package/dist/src/assets/Metropolis-LightItalic.woff2 +0 -0
- package/dist/src/assets/Metropolis-Medium.woff2 +0 -0
- package/dist/src/assets/Metropolis-MediumItalic.woff2 +0 -0
- package/dist/src/assets/Metropolis-Regular.woff2 +0 -0
- package/dist/src/assets/Metropolis-RegularItalic.woff2 +0 -0
- package/dist/src/assets/Metropolis-SemiBold.woff2 +0 -0
- package/dist/src/assets/Metropolis-SemiBoldItalic.woff2 +0 -0
- package/dist/src/assets/Metropolis-Thin.woff2 +0 -0
- package/dist/src/assets/Metropolis-ThinItalic.woff2 +0 -0
- package/dist/src/assets/assets/Metropolis-Black.woff2 +0 -0
- package/dist/src/assets/assets/Metropolis-BlackItalic.woff2 +0 -0
- package/dist/src/assets/assets/Metropolis-Bold.woff2 +0 -0
- package/dist/src/assets/assets/Metropolis-BoldItalic.woff2 +0 -0
- package/dist/src/assets/assets/Metropolis-ExtraBold.woff2 +0 -0
- package/dist/src/assets/assets/Metropolis-ExtraBoldItalic.woff2 +0 -0
- package/dist/src/assets/assets/Metropolis-ExtraLight.woff2 +0 -0
- package/dist/src/assets/assets/Metropolis-ExtraLightItalic.woff2 +0 -0
- package/dist/src/assets/assets/Metropolis-Light.woff2 +0 -0
- package/dist/src/assets/assets/Metropolis-LightItalic.woff2 +0 -0
- package/dist/src/assets/assets/Metropolis-Medium.woff2 +0 -0
- package/dist/src/assets/assets/Metropolis-MediumItalic.woff2 +0 -0
- package/dist/src/assets/assets/Metropolis-Regular.woff2 +0 -0
- package/dist/src/assets/assets/Metropolis-RegularItalic.woff2 +0 -0
- package/dist/src/assets/assets/Metropolis-SemiBold.woff2 +0 -0
- package/dist/src/assets/assets/Metropolis-SemiBoldItalic.woff2 +0 -0
- package/dist/src/assets/assets/Metropolis-Thin.woff2 +0 -0
- package/dist/src/assets/assets/Metropolis-ThinItalic.woff2 +0 -0
- package/dist/src/assets/assets/logo.png +0 -0
- package/dist/src/assets/logo.png +0 -0
- package/dist/src/factories/AddressFactory.d.ts +10 -0
- package/dist/src/factories/AddressFactory.d.ts.map +1 -0
- package/dist/src/factories/AddressFactory.js +42 -0
- package/dist/src/factories/AddressFactory.js.map +1 -0
- package/dist/src/factories/EmergencyContactFactory.d.ts +9 -0
- package/dist/src/factories/EmergencyContactFactory.d.ts.map +1 -0
- package/dist/src/factories/EmergencyContactFactory.js +42 -0
- package/dist/src/factories/EmergencyContactFactory.js.map +1 -0
- package/dist/src/factories/GroupFactory.d.ts +19 -0
- package/dist/src/factories/GroupFactory.d.ts.map +1 -0
- package/dist/src/factories/GroupFactory.js +52 -0
- package/dist/src/factories/GroupFactory.js.map +1 -0
- package/dist/src/factories/MemberFactory.d.ts +16 -0
- package/dist/src/factories/MemberFactory.d.ts.map +1 -0
- package/dist/src/factories/MemberFactory.js +98 -0
- package/dist/src/factories/MemberFactory.js.map +1 -0
- package/dist/src/factories/OrganizationFactory.d.ts +16 -0
- package/dist/src/factories/OrganizationFactory.d.ts.map +1 -0
- package/dist/src/factories/OrganizationFactory.js +40 -0
- package/dist/src/factories/OrganizationFactory.js.map +1 -0
- package/dist/src/factories/ParentFactory.d.ts +10 -0
- package/dist/src/factories/ParentFactory.d.ts.map +1 -0
- package/dist/src/factories/ParentFactory.js +44 -0
- package/dist/src/factories/ParentFactory.js.map +1 -0
- package/dist/src/factories/RecordFactory.d.ts +10 -0
- package/dist/src/factories/RecordFactory.d.ts.map +1 -0
- package/dist/src/factories/RecordFactory.js +14 -0
- package/dist/src/factories/RecordFactory.js.map +1 -0
- package/dist/src/factories/RegisterCodeFactory.d.ts +18 -0
- package/dist/src/factories/RegisterCodeFactory.d.ts.map +1 -0
- package/dist/src/factories/RegisterCodeFactory.js +19 -0
- package/dist/src/factories/RegisterCodeFactory.js.map +1 -0
- package/dist/src/factories/RegistrationFactory.d.ts +14 -0
- package/dist/src/factories/RegistrationFactory.d.ts.map +1 -0
- package/dist/src/factories/RegistrationFactory.js +26 -0
- package/dist/src/factories/RegistrationFactory.js.map +1 -0
- package/dist/src/factories/UserFactory.d.ts +21 -0
- package/dist/src/factories/UserFactory.d.ts.map +1 -0
- package/dist/src/factories/UserFactory.js +41 -0
- package/dist/src/factories/UserFactory.js.map +1 -0
- package/dist/src/factories/WebshopFactory.d.ts +16 -0
- package/dist/src/factories/WebshopFactory.d.ts.map +1 -0
- package/dist/src/factories/WebshopFactory.js +35 -0
- package/dist/src/factories/WebshopFactory.js.map +1 -0
- package/dist/src/helpers/DNSValidator.d.ts +6 -0
- package/dist/src/helpers/DNSValidator.d.ts.map +1 -0
- package/dist/src/helpers/DNSValidator.js +144 -0
- package/dist/src/helpers/DNSValidator.js.map +1 -0
- package/dist/src/helpers/EmailBuilder.d.ts +22 -0
- package/dist/src/helpers/EmailBuilder.d.ts.map +1 -0
- package/dist/src/helpers/EmailBuilder.js +100 -0
- package/dist/src/helpers/EmailBuilder.js.map +1 -0
- package/dist/src/helpers/GroupBuilder.d.ts +9 -0
- package/dist/src/helpers/GroupBuilder.d.ts.map +1 -0
- package/dist/src/helpers/GroupBuilder.js +382 -0
- package/dist/src/helpers/GroupBuilder.js.map +1 -0
- package/dist/src/helpers/Handlebars.d.ts +2 -0
- package/dist/src/helpers/Handlebars.d.ts.map +1 -0
- package/dist/src/helpers/Handlebars.js +192 -0
- package/dist/src/helpers/Handlebars.js.map +1 -0
- package/dist/src/helpers/InvoiceBuilder.d.ts +29 -0
- package/dist/src/helpers/InvoiceBuilder.d.ts.map +1 -0
- package/dist/src/helpers/InvoiceBuilder.js +406 -0
- package/dist/src/helpers/InvoiceBuilder.js.map +1 -0
- package/dist/src/helpers/InvoiceBuilder.test.d.ts +2 -0
- package/dist/src/helpers/InvoiceBuilder.test.d.ts.map +1 -0
- package/dist/src/helpers/InvoiceBuilder.test.js +52 -0
- package/dist/src/helpers/InvoiceBuilder.test.js.map +1 -0
- package/dist/src/helpers/RateLimiter.d.ts +27 -0
- package/dist/src/helpers/RateLimiter.d.ts.map +1 -0
- package/dist/src/helpers/RateLimiter.js +57 -0
- package/dist/src/helpers/RateLimiter.js.map +1 -0
- package/dist/src/helpers/WebshopCounter.d.ts +6 -0
- package/dist/src/helpers/WebshopCounter.d.ts.map +1 -0
- package/dist/src/helpers/WebshopCounter.js +36 -0
- package/dist/src/helpers/WebshopCounter.js.map +1 -0
- package/dist/src/helpers/WebshopCounter.test.d.ts +2 -0
- package/dist/src/helpers/WebshopCounter.test.d.ts.map +1 -0
- package/dist/src/helpers/WebshopCounter.test.js +17 -0
- package/dist/src/helpers/WebshopCounter.test.js.map +1 -0
- package/dist/src/index.d.ts +18 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +23 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/migrations/1593773929-create-initial-tables.sql +634 -0
- package/dist/src/migrations/1605261999-gemeenten-tmp.sql +2820 -0
- package/dist/src/migrations/1605262045-import-postcodes.d.ts +16 -0
- package/dist/src/migrations/1605262045-import-postcodes.d.ts.map +1 -0
- package/dist/src/migrations/1605262045-import-postcodes.js +116 -0
- package/dist/src/migrations/1605262045-import-postcodes.js.map +1 -0
- package/dist/src/migrations/1605262046-import-postcodes-nl.d.ts +4 -0
- package/dist/src/migrations/1605262046-import-postcodes-nl.d.ts.map +1 -0
- package/dist/src/migrations/1605262046-import-postcodes-nl.js +83 -0
- package/dist/src/migrations/1605262046-import-postcodes-nl.js.map +1 -0
- package/dist/src/migrations/1605279038-drop-gemeenten-tmp.sql +1 -0
- package/dist/src/migrations/1648392491-default-templates.sql +9 -0
- package/dist/src/migrations/1651245707-default-templates-reminders.sql +6 -0
- package/dist/src/migrations/1708607340-tickets-deleted-at.sql +1 -0
- package/dist/src/migrations/1710459176-register-code-invoices.sql +3 -0
- package/dist/src/migrations/1712158247-discount-codes.sql +17 -0
- package/dist/src/migrations/1713178665-drop-invites.sql +1 -0
- package/dist/src/migrations/1713178666-drop-keychain.sql +1 -0
- package/dist/src/migrations/1713178667-drop-challenges.sql +1 -0
- package/dist/src/migrations/1713178668-drop-user-keys.sql +7 -0
- package/dist/src/migrations/1713178669-drop-organization-key.sql +2 -0
- package/dist/src/migrations/data/postcodes/nl/Drenthe +291 -0
- package/dist/src/migrations/data/postcodes/nl/Flevoland +107 -0
- package/dist/src/migrations/data/postcodes/nl/Friesland +518 -0
- package/dist/src/migrations/data/postcodes/nl/Gelderland +601 -0
- package/dist/src/migrations/data/postcodes/nl/Groningen +279 -0
- package/dist/src/migrations/data/postcodes/nl/Limburg +324 -0
- package/dist/src/migrations/data/postcodes/nl/Noord-Brabant +620 -0
- package/dist/src/migrations/data/postcodes/nl/Noord-Holland +566 -0
- package/dist/src/migrations/data/postcodes/nl/Overrijsel +344 -0
- package/dist/src/migrations/data/postcodes/nl/Utrecht +278 -0
- package/dist/src/migrations/data/postcodes/nl/Zeeland +179 -0
- package/dist/src/migrations/data/postcodes/nl/Zuid-Holland +662 -0
- package/dist/src/models/BalanceItem.d.ts +57 -0
- package/dist/src/models/BalanceItem.d.ts.map +1 -0
- package/dist/src/models/BalanceItem.js +346 -0
- package/dist/src/models/BalanceItem.js.map +1 -0
- package/dist/src/models/BalanceItemPayment.d.ts +31 -0
- package/dist/src/models/BalanceItemPayment.d.ts.map +1 -0
- package/dist/src/models/BalanceItemPayment.js +101 -0
- package/dist/src/models/BalanceItemPayment.js.map +1 -0
- package/dist/src/models/BuckarooPayment.d.ts +8 -0
- package/dist/src/models/BuckarooPayment.d.ts.map +1 -0
- package/dist/src/models/BuckarooPayment.js +24 -0
- package/dist/src/models/BuckarooPayment.js.map +1 -0
- package/dist/src/models/Document.d.ts +44 -0
- package/dist/src/models/Document.d.ts.map +1 -0
- package/dist/src/models/Document.js +194 -0
- package/dist/src/models/Document.js.map +1 -0
- package/dist/src/models/DocumentTemplate.d.ts +45 -0
- package/dist/src/models/DocumentTemplate.d.ts.map +1 -0
- package/dist/src/models/DocumentTemplate.js +533 -0
- package/dist/src/models/DocumentTemplate.js.map +1 -0
- package/dist/src/models/EmailTemplate.d.ts +22 -0
- package/dist/src/models/EmailTemplate.d.ts.map +1 -0
- package/dist/src/models/EmailTemplate.js +70 -0
- package/dist/src/models/EmailTemplate.js.map +1 -0
- package/dist/src/models/EmailVerificationCode.d.ts +60 -0
- package/dist/src/models/EmailVerificationCode.d.ts.map +1 -0
- package/dist/src/models/EmailVerificationCode.js +307 -0
- package/dist/src/models/EmailVerificationCode.js.map +1 -0
- package/dist/src/models/Group.d.ts +36 -0
- package/dist/src/models/Group.d.ts.map +1 -0
- package/dist/src/models/Group.js +231 -0
- package/dist/src/models/Group.js.map +1 -0
- package/dist/src/models/Image.d.ts +12 -0
- package/dist/src/models/Image.d.ts.map +1 -0
- package/dist/src/models/Image.js +137 -0
- package/dist/src/models/Image.js.map +1 -0
- package/dist/src/models/Member.d.ts +66 -0
- package/dist/src/models/Member.d.ts.map +1 -0
- package/dist/src/models/Member.js +309 -0
- package/dist/src/models/Member.js.map +1 -0
- package/dist/src/models/MemberResponsibilityRecord.d.ts +11 -0
- package/dist/src/models/MemberResponsibilityRecord.d.ts.map +1 -0
- package/dist/src/models/MemberResponsibilityRecord.js +47 -0
- package/dist/src/models/MemberResponsibilityRecord.js.map +1 -0
- package/dist/src/models/MolliePayment.d.ts +8 -0
- package/dist/src/models/MolliePayment.d.ts.map +1 -0
- package/dist/src/models/MolliePayment.js +24 -0
- package/dist/src/models/MolliePayment.js.map +1 -0
- package/dist/src/models/MollieToken.d.ts +45 -0
- package/dist/src/models/MollieToken.d.ts.map +1 -0
- package/dist/src/models/MollieToken.js +333 -0
- package/dist/src/models/MollieToken.js.map +1 -0
- package/dist/src/models/OneTimeToken.d.ts +38 -0
- package/dist/src/models/OneTimeToken.d.ts.map +1 -0
- package/dist/src/models/OneTimeToken.js +126 -0
- package/dist/src/models/OneTimeToken.js.map +1 -0
- package/dist/src/models/Order.d.ts +99 -0
- package/dist/src/models/Order.d.ts.map +1 -0
- package/dist/src/models/Order.js +912 -0
- package/dist/src/models/Order.js.map +1 -0
- package/dist/src/models/Organization.d.ts +119 -0
- package/dist/src/models/Organization.d.ts.map +1 -0
- package/dist/src/models/Organization.js +900 -0
- package/dist/src/models/Organization.js.map +1 -0
- package/dist/src/models/OrganizationRegistrationPeriod.d.ts +14 -0
- package/dist/src/models/OrganizationRegistrationPeriod.d.ts.map +1 -0
- package/dist/src/models/OrganizationRegistrationPeriod.js +62 -0
- package/dist/src/models/OrganizationRegistrationPeriod.js.map +1 -0
- package/dist/src/models/PasswordToken.d.ts +29 -0
- package/dist/src/models/PasswordToken.d.ts.map +1 -0
- package/dist/src/models/PasswordToken.js +118 -0
- package/dist/src/models/PasswordToken.js.map +1 -0
- package/dist/src/models/PayconiqPayment.d.ts +18 -0
- package/dist/src/models/PayconiqPayment.d.ts.map +1 -0
- package/dist/src/models/PayconiqPayment.js +216 -0
- package/dist/src/models/PayconiqPayment.js.map +1 -0
- package/dist/src/models/Payment.d.ts +62 -0
- package/dist/src/models/Payment.d.ts.map +1 -0
- package/dist/src/models/Payment.js +199 -0
- package/dist/src/models/Payment.js.map +1 -0
- package/dist/src/models/Platform.d.ts +15 -0
- package/dist/src/models/Platform.d.ts.map +1 -0
- package/dist/src/models/Platform.js +77 -0
- package/dist/src/models/Platform.js.map +1 -0
- package/dist/src/models/RegisterCode.d.ts +27 -0
- package/dist/src/models/RegisterCode.d.ts.map +1 -0
- package/dist/src/models/RegisterCode.js +162 -0
- package/dist/src/models/RegisterCode.js.map +1 -0
- package/dist/src/models/Registration.d.ts +47 -0
- package/dist/src/models/Registration.d.ts.map +1 -0
- package/dist/src/models/Registration.js +369 -0
- package/dist/src/models/Registration.js.map +1 -0
- package/dist/src/models/RegistrationPeriod.d.ts +15 -0
- package/dist/src/models/RegistrationPeriod.d.ts.map +1 -0
- package/dist/src/models/RegistrationPeriod.js +64 -0
- package/dist/src/models/RegistrationPeriod.js.map +1 -0
- package/dist/src/models/STCredit.d.ts +20 -0
- package/dist/src/models/STCredit.d.ts.map +1 -0
- package/dist/src/models/STCredit.js +129 -0
- package/dist/src/models/STCredit.js.map +1 -0
- package/dist/src/models/STInvoice.d.ts +51 -0
- package/dist/src/models/STInvoice.d.ts.map +1 -0
- package/dist/src/models/STInvoice.js +453 -0
- package/dist/src/models/STInvoice.js.map +1 -0
- package/dist/src/models/STPackage.d.ts +36 -0
- package/dist/src/models/STPackage.d.ts.map +1 -0
- package/dist/src/models/STPackage.js +300 -0
- package/dist/src/models/STPackage.js.map +1 -0
- package/dist/src/models/STPendingInvoice.d.ts +45 -0
- package/dist/src/models/STPendingInvoice.d.ts.map +1 -0
- package/dist/src/models/STPendingInvoice.js +284 -0
- package/dist/src/models/STPendingInvoice.js.map +1 -0
- package/dist/src/models/StripeAccount.d.ts +17 -0
- package/dist/src/models/StripeAccount.d.ts.map +1 -0
- package/dist/src/models/StripeAccount.js +81 -0
- package/dist/src/models/StripeAccount.js.map +1 -0
- package/dist/src/models/StripeCheckoutSession.d.ts +9 -0
- package/dist/src/models/StripeCheckoutSession.d.ts.map +1 -0
- package/dist/src/models/StripeCheckoutSession.js +31 -0
- package/dist/src/models/StripeCheckoutSession.js.map +1 -0
- package/dist/src/models/StripePaymentIntent.d.ts +9 -0
- package/dist/src/models/StripePaymentIntent.d.ts.map +1 -0
- package/dist/src/models/StripePaymentIntent.js +31 -0
- package/dist/src/models/StripePaymentIntent.js.map +1 -0
- package/dist/src/models/Ticket.d.ts +61 -0
- package/dist/src/models/Ticket.d.ts.map +1 -0
- package/dist/src/models/Ticket.js +143 -0
- package/dist/src/models/Ticket.js.map +1 -0
- package/dist/src/models/Token.d.ts +49 -0
- package/dist/src/models/Token.d.ts.map +1 -0
- package/dist/src/models/Token.js +218 -0
- package/dist/src/models/Token.js.map +1 -0
- package/dist/src/models/Token.test.d.ts +2 -0
- package/dist/src/models/Token.test.d.ts.map +1 -0
- package/dist/src/models/Token.test.js +60 -0
- package/dist/src/models/Token.test.js.map +1 -0
- package/dist/src/models/UsedRegisterCode.d.ts +22 -0
- package/dist/src/models/UsedRegisterCode.d.ts.map +1 -0
- package/dist/src/models/UsedRegisterCode.js +158 -0
- package/dist/src/models/UsedRegisterCode.js.map +1 -0
- package/dist/src/models/User.d.ts +55 -0
- package/dist/src/models/User.d.ts.map +1 -0
- package/dist/src/models/User.js +314 -0
- package/dist/src/models/User.js.map +1 -0
- package/dist/src/models/UserPermissions.d.ts +15 -0
- package/dist/src/models/UserPermissions.d.ts.map +1 -0
- package/dist/src/models/UserPermissions.js +57 -0
- package/dist/src/models/UserPermissions.js.map +1 -0
- package/dist/src/models/Webshop.d.ts +44 -0
- package/dist/src/models/Webshop.d.ts.map +1 -0
- package/dist/src/models/Webshop.js +184 -0
- package/dist/src/models/Webshop.js.map +1 -0
- package/dist/src/models/WebshopDiscountCode.d.ts +18 -0
- package/dist/src/models/WebshopDiscountCode.d.ts.map +1 -0
- package/dist/src/models/WebshopDiscountCode.js +88 -0
- package/dist/src/models/WebshopDiscountCode.js.map +1 -0
- package/dist/src/models/addresses/City.d.ts +14 -0
- package/dist/src/models/addresses/City.d.ts.map +1 -0
- package/dist/src/models/addresses/City.js +37 -0
- package/dist/src/models/addresses/City.js.map +1 -0
- package/dist/src/models/addresses/PostalCode.d.ts +20 -0
- package/dist/src/models/addresses/PostalCode.d.ts.map +1 -0
- package/dist/src/models/addresses/PostalCode.js +138 -0
- package/dist/src/models/addresses/PostalCode.js.map +1 -0
- package/dist/src/models/addresses/PostalCode.test.d.ts +2 -0
- package/dist/src/models/addresses/PostalCode.test.d.ts.map +1 -0
- package/dist/src/models/addresses/PostalCode.test.js +98 -0
- package/dist/src/models/addresses/PostalCode.test.js.map +1 -0
- package/dist/src/models/addresses/Province.d.ts +9 -0
- package/dist/src/models/addresses/Province.d.ts.map +1 -0
- package/dist/src/models/addresses/Province.js +24 -0
- package/dist/src/models/addresses/Province.js.map +1 -0
- package/dist/src/models/addresses/Street.d.ts +10 -0
- package/dist/src/models/addresses/Street.d.ts.map +1 -0
- package/dist/src/models/addresses/Street.js +26 -0
- package/dist/src/models/addresses/Street.js.map +1 -0
- package/dist/src/models/index.d.ts +37 -0
- package/dist/src/models/index.d.ts.map +1 -0
- package/dist/src/models/index.js +53 -0
- package/dist/src/models/index.js.map +1 -0
- package/dist/src/structures/OrganizationServerMetaData.d.ts +43 -0
- package/dist/src/structures/OrganizationServerMetaData.d.ts.map +1 -0
- package/dist/src/structures/OrganizationServerMetaData.js +128 -0
- package/dist/src/structures/OrganizationServerMetaData.js.map +1 -0
- package/dist/tests/jest.global.setup.d.ts +3 -0
- package/dist/tests/jest.global.setup.d.ts.map +1 -0
- package/dist/tests/jest.global.setup.js +20 -0
- package/dist/tests/jest.global.setup.js.map +1 -0
- package/dist/tests/jest.setup.d.ts +2 -0
- package/dist/tests/jest.setup.d.ts.map +1 -0
- package/dist/tests/jest.setup.js +15 -0
- package/dist/tests/jest.setup.js.map +1 -0
- package/package.json +30 -0
- package/src/assets/Metropolis-Black.woff2 +0 -0
- package/src/assets/Metropolis-BlackItalic.woff2 +0 -0
- package/src/assets/Metropolis-Bold.woff2 +0 -0
- package/src/assets/Metropolis-BoldItalic.woff2 +0 -0
- package/src/assets/Metropolis-ExtraBold.woff2 +0 -0
- package/src/assets/Metropolis-ExtraBoldItalic.woff2 +0 -0
- package/src/assets/Metropolis-ExtraLight.woff2 +0 -0
- package/src/assets/Metropolis-ExtraLightItalic.woff2 +0 -0
- package/src/assets/Metropolis-Light.woff2 +0 -0
- package/src/assets/Metropolis-LightItalic.woff2 +0 -0
- package/src/assets/Metropolis-Medium.woff2 +0 -0
- package/src/assets/Metropolis-MediumItalic.woff2 +0 -0
- package/src/assets/Metropolis-Regular.woff2 +0 -0
- package/src/assets/Metropolis-RegularItalic.woff2 +0 -0
- package/src/assets/Metropolis-SemiBold.woff2 +0 -0
- package/src/assets/Metropolis-SemiBoldItalic.woff2 +0 -0
- package/src/assets/Metropolis-Thin.woff2 +0 -0
- package/src/assets/Metropolis-ThinItalic.woff2 +0 -0
- package/src/assets/logo.png +0 -0
- package/src/factories/AddressFactory.ts +42 -0
- package/src/factories/EmergencyContactFactory.ts +43 -0
- package/src/factories/GroupFactory.ts +66 -0
- package/src/factories/MemberFactory.ts +122 -0
- package/src/factories/OrganizationFactory.ts +45 -0
- package/src/factories/ParentFactory.ts +49 -0
- package/src/factories/RecordFactory.ts +12 -0
- package/src/factories/RegisterCodeFactory.ts +25 -0
- package/src/factories/RegistrationFactory.ts +32 -0
- package/src/factories/UserFactory.ts +66 -0
- package/src/factories/WebshopFactory.ts +43 -0
- package/src/helpers/DNSValidator.ts +153 -0
- package/src/helpers/EmailBuilder.ts +127 -0
- package/src/helpers/GroupBuilder.ts +438 -0
- package/src/helpers/Handlebars.ts +203 -0
- package/src/helpers/InvoiceBuilder.test.ts +57 -0
- package/src/helpers/InvoiceBuilder.ts +501 -0
- package/src/helpers/RateLimiter.ts +75 -0
- package/src/helpers/WebshopCounter.test.ts +16 -0
- package/src/helpers/WebshopCounter.ts +36 -0
- package/src/index.ts +21 -0
- package/src/migrations/1593773929-create-initial-tables.sql +634 -0
- package/src/migrations/1605261999-gemeenten-tmp.sql +2820 -0
- package/src/migrations/1605262045-import-postcodes.ts +132 -0
- package/src/migrations/1605262046-import-postcodes-nl.ts +97 -0
- package/src/migrations/1605279038-drop-gemeenten-tmp.sql +1 -0
- package/src/migrations/1648392491-default-templates.sql +9 -0
- package/src/migrations/1651245707-default-templates-reminders.sql +6 -0
- package/src/migrations/1708607340-tickets-deleted-at.sql +1 -0
- package/src/migrations/1710459176-register-code-invoices.sql +3 -0
- package/src/migrations/1712158247-discount-codes.sql +17 -0
- package/src/migrations/1713178665-drop-invites.sql +1 -0
- package/src/migrations/1713178666-drop-keychain.sql +1 -0
- package/src/migrations/1713178667-drop-challenges.sql +1 -0
- package/src/migrations/1713178668-drop-user-keys.sql +7 -0
- package/src/migrations/1713178669-drop-organization-key.sql +2 -0
- package/src/migrations/1714985451-user-nullable-organization-id.sql +2 -0
- package/src/migrations/1714985452-email-verification-code-nullable-organization-id.sql +2 -0
- package/src/migrations/1714985453-user-organization-permissions.sql +2 -0
- package/src/migrations/1714985454-user-organization-permissions.sql +2 -0
- package/src/migrations/1715079362-platform.sql +6 -0
- package/src/migrations/1715181649-registrations-organization-id.sql +2 -0
- package/src/migrations/1715181650-registrations-organization-id-fill.sql +1 -0
- package/src/migrations/1715181651-registrations-organization-id-drop-null.sql +2 -0
- package/src/migrations/1716117067-members-nullable-organization-id.sql +2 -0
- package/src/migrations/1719567581-registration-periods.sql +13 -0
- package/src/migrations/1719567582-organization-registration-periods.sql +13 -0
- package/src/migrations/1719567881-organization-periodId.sql +2 -0
- package/src/migrations/1719567882-groups-periodId.sql +2 -0
- package/src/migrations/1719567883-platform-periodId.sql +2 -0
- package/src/migrations/1719568079-default-period.sql +2 -0
- package/src/migrations/1719568080-set-default-period-platform.sql +1 -0
- package/src/migrations/1719568081-set-default-period-organizations.sql +1 -0
- package/src/migrations/1719568082-set-default-period-groups.sql +1 -0
- package/src/migrations/1719580828-registrations-periodId.sql +2 -0
- package/src/migrations/1719580829-set-default-period-registrations.sql +1 -0
- package/src/migrations/data/postcodes/nl/Drenthe +291 -0
- package/src/migrations/data/postcodes/nl/Flevoland +107 -0
- package/src/migrations/data/postcodes/nl/Friesland +518 -0
- package/src/migrations/data/postcodes/nl/Gelderland +601 -0
- package/src/migrations/data/postcodes/nl/Groningen +279 -0
- package/src/migrations/data/postcodes/nl/Limburg +324 -0
- package/src/migrations/data/postcodes/nl/Noord-Brabant +620 -0
- package/src/migrations/data/postcodes/nl/Noord-Holland +566 -0
- package/src/migrations/data/postcodes/nl/Overrijsel +344 -0
- package/src/migrations/data/postcodes/nl/Utrecht +278 -0
- package/src/migrations/data/postcodes/nl/Zeeland +179 -0
- package/src/migrations/data/postcodes/nl/Zuid-Holland +662 -0
- package/src/models/BalanceItem.ts +392 -0
- package/src/models/BalanceItemPayment.ts +106 -0
- package/src/models/BuckarooPayment.ts +19 -0
- package/src/models/Document.ts +203 -0
- package/src/models/DocumentTemplate.ts +583 -0
- package/src/models/EmailTemplate.ts +64 -0
- package/src/models/EmailVerificationCode.ts +352 -0
- package/src/models/Group.ts +293 -0
- package/src/models/Image.ts +147 -0
- package/src/models/Member.ts +386 -0
- package/src/models/MemberResponsibilityRecord.ts +39 -0
- package/src/models/MolliePayment.ts +19 -0
- package/src/models/MollieToken.ts +369 -0
- package/src/models/OneTimeToken.ts +131 -0
- package/src/models/Order.ts +1030 -0
- package/src/models/Organization.ts +1085 -0
- package/src/models/OrganizationRegistrationPeriod.ts +54 -0
- package/src/models/PasswordToken.ts +139 -0
- package/src/models/PayconiqPayment.ts +241 -0
- package/src/models/Payment.ts +216 -0
- package/src/models/Platform.ts +76 -0
- package/src/models/RegisterCode.ts +164 -0
- package/src/models/Registration.ts +405 -0
- package/src/models/RegistrationPeriod.ts +55 -0
- package/src/models/STCredit.ts +134 -0
- package/src/models/STInvoice.ts +507 -0
- package/src/models/STPackage.ts +324 -0
- package/src/models/STPendingInvoice.ts +308 -0
- package/src/models/StripeAccount.ts +71 -0
- package/src/models/StripeCheckoutSession.ts +22 -0
- package/src/models/StripePaymentIntent.ts +22 -0
- package/src/models/Ticket.ts +145 -0
- package/src/models/Token.test.ts +69 -0
- package/src/models/Token.ts +269 -0
- package/src/models/UsedRegisterCode.ts +166 -0
- package/src/models/User.ts +445 -0
- package/src/models/UserPermissions.ts +54 -0
- package/src/models/Webshop.ts +206 -0
- package/src/models/WebshopDiscountCode.ts +81 -0
- package/src/models/addresses/City.ts +31 -0
- package/src/models/addresses/PostalCode.test.ts +117 -0
- package/src/models/addresses/PostalCode.ts +164 -0
- package/src/models/addresses/Province.ts +20 -0
- package/src/models/addresses/Street.ts +25 -0
- package/src/models/index.ts +49 -0
- 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
|
+
}
|