@stamhoofd/models 2.120.6 → 2.122.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/factories/GroupFactory.d.ts.map +1 -1
- package/dist/factories/GroupFactory.js +1 -1
- package/dist/factories/GroupFactory.js.map +1 -1
- package/dist/factories/OrganizationFactory.d.ts +2 -1
- package/dist/factories/OrganizationFactory.d.ts.map +1 -1
- package/dist/factories/OrganizationFactory.js +9 -1
- package/dist/factories/OrganizationFactory.js.map +1 -1
- package/dist/factories/RegistrationInvitationFactory.d.ts +15 -0
- package/dist/factories/RegistrationInvitationFactory.d.ts.map +1 -0
- package/dist/factories/RegistrationInvitationFactory.js +18 -0
- package/dist/factories/RegistrationInvitationFactory.js.map +1 -0
- package/dist/factories/STPackageFactory.js.map +1 -1
- package/dist/factories/UserFactory.d.ts.map +1 -1
- package/dist/factories/UserFactory.js +2 -2
- package/dist/factories/UserFactory.js.map +1 -1
- package/dist/factories/index.d.ts +1 -0
- package/dist/factories/index.d.ts.map +1 -1
- package/dist/factories/index.js +1 -0
- package/dist/factories/index.js.map +1 -1
- package/dist/helpers/EmailBuilder.d.ts.map +1 -1
- package/dist/helpers/EmailBuilder.js +8 -8
- package/dist/helpers/EmailBuilder.js.map +1 -1
- package/dist/helpers/Handlebars.d.ts.map +1 -1
- package/dist/helpers/Handlebars.js +10 -1
- package/dist/helpers/Handlebars.js.map +1 -1
- package/dist/helpers/InvoiceCounter.d.ts +24 -0
- package/dist/helpers/InvoiceCounter.d.ts.map +1 -0
- package/dist/helpers/InvoiceCounter.js +133 -0
- package/dist/helpers/InvoiceCounter.js.map +1 -0
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -1
- package/dist/index.js.map +1 -1
- package/dist/migrations/1605262045-import-postcodes.d.ts.map +1 -1
- package/dist/migrations/1605262045-import-postcodes.js +58 -24
- package/dist/migrations/1605262045-import-postcodes.js.map +1 -1
- package/dist/migrations/1605262046-import-postcodes-nl.d.ts.map +1 -1
- package/dist/migrations/1605262046-import-postcodes-nl.js +54 -17
- package/dist/migrations/1605262046-import-postcodes-nl.js.map +1 -1
- package/dist/migrations/1719567881-organization-periodId.sql +2 -0
- package/dist/migrations/1719567882-groups-periodId.sql +2 -0
- package/dist/migrations/1720080975-convert-charset.d.ts +4 -0
- package/dist/migrations/1720080975-convert-charset.d.ts.map +1 -0
- package/dist/migrations/1720080975-convert-charset.js +26 -0
- package/dist/migrations/1720080975-convert-charset.js.map +1 -0
- package/dist/migrations/1720080976-convert-charset-leads.d.ts.map +1 -1
- package/dist/migrations/1720080976-convert-charset-leads.js +11 -10
- package/dist/migrations/1720080976-convert-charset-leads.js.map +1 -1
- package/dist/migrations/1721400546-users-memberId.sql +2 -0
- package/dist/migrations/1722269236-group-waitinglist-id.sql +2 -1
- package/dist/migrations/1722525785-balance-item-paying-organization-id.sql +2 -0
- package/dist/migrations/1722525787-depending-balance-item.sql +2 -0
- package/dist/migrations/1722963554-registration-group-price-and-options.sql +1 -1
- package/dist/migrations/1723652797-payments-paying-organization-id-fk.sql +2 -0
- package/dist/migrations/1733317908-added-missing-organization-fk-on-registrations.sql +2 -0
- package/dist/migrations/1733317910-paying-organization-id-fk.sql +2 -0
- package/dist/migrations/1733504881-negative-invoice-id.sql +6 -0
- package/dist/migrations/1733994455-balance-item-status-open.d.ts +4 -0
- package/dist/migrations/1733994455-balance-item-status-open.d.ts.map +1 -0
- package/dist/migrations/1733994455-balance-item-status-open.js +28 -0
- package/dist/migrations/1733994455-balance-item-status-open.js.map +1 -0
- package/dist/migrations/1763216320-bigint-balance-item-payments.sql +2 -0
- package/dist/migrations/1763216320-bigint-balance-items.sql +5 -0
- package/dist/migrations/1763216320-bigint-orders.sql +2 -0
- package/dist/migrations/1763216320-bigint-payments.sql +2 -0
- package/dist/migrations/1763216332-bigint-balance-item-price-total.sql +2 -0
- package/dist/migrations/1769087808-corrected-invoice-user-agent.sql +2 -0
- package/dist/migrations/1769087809-payments-invoice-id.sql +2 -0
- package/dist/migrations/1772033555-balance-item-package-id.sql +2 -0
- package/dist/migrations/1776873089-create-registration-invitations-table.sql +13 -0
- package/dist/migrations/1778657958-payments-create-mandate.sql +2 -0
- package/dist/migrations/1778657959-payments-mandate-id.sql +2 -0
- package/dist/migrations/1778796615-payments-reversing-payment-id.sql +5 -0
- package/dist/migrations/1778950642-price-invoiced.sql +2 -0
- package/dist/migrations/1779443446-transfer-fees.sql +3 -0
- package/dist/migrations/1779709174-used-register-code-balance-item-id.sql +5 -0
- package/dist/migrations/1779968328-payments-admin-user-id.sql +5 -0
- package/dist/migrations/1779970611-payments-refunded-amount.sql +2 -0
- package/dist/migrations/1779972640-balance-items-failed-at.sql +2 -0
- package/dist/migrations/1780328285-document-template-locked.sql +2 -0
- package/dist/migrations/1780328286-document-locked.sql +2 -0
- package/dist/migrations/1780412083-documents-set-locked.d.ts +4 -0
- package/dist/migrations/1780412083-documents-set-locked.d.ts.map +1 -0
- package/dist/migrations/1780412083-documents-set-locked.js +14 -0
- package/dist/migrations/1780412083-documents-set-locked.js.map +1 -0
- package/dist/migrations/1780928401-v1-groups-migration-data.d.ts +4 -0
- package/dist/migrations/1780928401-v1-groups-migration-data.d.ts.map +1 -0
- package/dist/migrations/1780928401-v1-groups-migration-data.js +44 -0
- package/dist/migrations/1780928401-v1-groups-migration-data.js.map +1 -0
- package/dist/models/BalanceItem.d.ts +14 -1
- package/dist/models/BalanceItem.d.ts.map +1 -1
- package/dist/models/BalanceItem.js +91 -41
- package/dist/models/BalanceItem.js.map +1 -1
- package/dist/models/CachedBalance.d.ts +6 -1
- package/dist/models/CachedBalance.d.ts.map +1 -1
- package/dist/models/CachedBalance.js +3 -2
- package/dist/models/CachedBalance.js.map +1 -1
- package/dist/models/Document.d.ts +4 -0
- package/dist/models/Document.d.ts.map +1 -1
- package/dist/models/Document.js +26 -3
- package/dist/models/Document.js.map +1 -1
- package/dist/models/DocumentTemplate.d.ts +4 -0
- package/dist/models/DocumentTemplate.d.ts.map +1 -1
- package/dist/models/DocumentTemplate.js +37 -1
- package/dist/models/DocumentTemplate.js.map +1 -1
- package/dist/models/Email.d.ts.map +1 -1
- package/dist/models/Email.js +1 -1
- package/dist/models/Email.js.map +1 -1
- package/dist/models/EmailVerificationCode.d.ts.map +1 -1
- package/dist/models/EmailVerificationCode.js +3 -13
- package/dist/models/EmailVerificationCode.js.map +1 -1
- package/dist/models/Event.d.ts +2 -1
- package/dist/models/Event.d.ts.map +1 -1
- package/dist/models/Event.js +3 -0
- package/dist/models/Event.js.map +1 -1
- package/dist/models/EventNotification.d.ts.map +1 -1
- package/dist/models/EventNotification.js +5 -5
- package/dist/models/EventNotification.js.map +1 -1
- package/dist/models/Group.d.ts +4 -0
- package/dist/models/Group.d.ts.map +1 -1
- package/dist/models/Group.js +17 -0
- package/dist/models/Group.js.map +1 -1
- package/dist/models/Invoice.d.ts +1 -0
- package/dist/models/Invoice.d.ts.map +1 -1
- package/dist/models/Invoice.js +8 -8
- package/dist/models/Invoice.js.map +1 -1
- package/dist/models/MemberPlatformMembership.d.ts.map +1 -1
- package/dist/models/MemberPlatformMembership.js +9 -0
- package/dist/models/MemberPlatformMembership.js.map +1 -1
- package/dist/models/MollieToken.d.ts +4 -8
- package/dist/models/MollieToken.d.ts.map +1 -1
- package/dist/models/MollieToken.js +37 -90
- package/dist/models/MollieToken.js.map +1 -1
- package/dist/models/Order.d.ts.map +1 -1
- package/dist/models/Order.js +1 -0
- package/dist/models/Order.js.map +1 -1
- package/dist/models/Organization.d.ts +30 -23
- package/dist/models/Organization.d.ts.map +1 -1
- package/dist/models/Organization.js +113 -61
- package/dist/models/Organization.js.map +1 -1
- package/dist/models/PasswordToken.d.ts +5 -1
- package/dist/models/PasswordToken.d.ts.map +1 -1
- package/dist/models/PasswordToken.js +18 -17
- package/dist/models/PasswordToken.js.map +1 -1
- package/dist/models/Payment.d.ts +35 -3
- package/dist/models/Payment.d.ts.map +1 -1
- package/dist/models/Payment.js +66 -3
- package/dist/models/Payment.js.map +1 -1
- package/dist/models/Registration.d.ts +1 -0
- package/dist/models/Registration.d.ts.map +1 -1
- package/dist/models/Registration.js +4 -3
- package/dist/models/Registration.js.map +1 -1
- package/dist/models/RegistrationInvitation.d.ts +14 -0
- package/dist/models/RegistrationInvitation.d.ts.map +1 -0
- package/dist/models/RegistrationInvitation.js +45 -0
- package/dist/models/RegistrationInvitation.js.map +1 -0
- package/dist/models/STCredit.d.ts +4 -0
- package/dist/models/STCredit.d.ts.map +1 -1
- package/dist/models/STCredit.js +28 -0
- package/dist/models/STCredit.js.map +1 -1
- package/dist/models/STInvoice.d.ts +7 -1
- package/dist/models/STInvoice.d.ts.map +1 -1
- package/dist/models/STInvoice.js +9 -0
- package/dist/models/STInvoice.js.map +1 -1
- package/dist/models/STPackage.d.ts +4 -0
- package/dist/models/STPackage.d.ts.map +1 -1
- package/dist/models/STPackage.js +12 -1
- package/dist/models/STPackage.js.map +1 -1
- package/dist/models/UsedRegisterCode.d.ts +9 -0
- package/dist/models/UsedRegisterCode.d.ts.map +1 -1
- package/dist/models/UsedRegisterCode.js +31 -0
- package/dist/models/UsedRegisterCode.js.map +1 -1
- package/dist/models/User.d.ts +1 -1
- package/dist/models/User.d.ts.map +1 -1
- package/dist/models/User.js +1 -1
- package/dist/models/User.js.map +1 -1
- package/dist/models/_relations.js +25 -0
- package/dist/models/_relations.js.map +1 -1
- package/dist/models/addresses/City.d.ts +4 -4
- package/dist/models/addresses/City.d.ts.map +1 -1
- package/dist/models/addresses/City.js +6 -6
- package/dist/models/addresses/City.js.map +1 -1
- package/dist/models/addresses/PostalCode.d.ts +2 -2
- package/dist/models/addresses/PostalCode.d.ts.map +1 -1
- package/dist/models/addresses/PostalCode.js +4 -3
- package/dist/models/addresses/PostalCode.js.map +1 -1
- package/dist/models/addresses/Street.d.ts +3 -3
- package/dist/models/addresses/Street.d.ts.map +1 -1
- package/dist/models/addresses/Street.js +4 -4
- package/dist/models/addresses/Street.js.map +1 -1
- package/dist/models/index.d.ts +2 -0
- package/dist/models/index.d.ts.map +1 -1
- package/dist/models/index.js +2 -0
- package/dist/models/index.js.map +1 -1
- package/dist/models/v1GroupMigrationData.d.ts +22 -0
- package/dist/models/v1GroupMigrationData.d.ts.map +1 -0
- package/dist/models/v1GroupMigrationData.js +48 -0
- package/dist/models/v1GroupMigrationData.js.map +1 -0
- package/package.json +41 -13
- package/src/factories/GroupFactory.ts +4 -6
- package/src/factories/OrganizationFactory.ts +12 -4
- package/src/factories/RegistrationInvitationFactory.ts +24 -0
- package/src/factories/STPackageFactory.ts +2 -2
- package/src/factories/UserFactory.ts +4 -5
- package/src/factories/index.ts +1 -0
- package/src/helpers/EmailBuilder.ts +19 -28
- package/src/helpers/Handlebars.ts +10 -1
- package/src/helpers/InvoiceCounter.test.ts +220 -0
- package/src/helpers/InvoiceCounter.ts +162 -0
- package/src/index.ts +0 -1
- package/src/migrations/1605262045-import-postcodes.ts +62 -25
- package/src/migrations/1605262046-import-postcodes-nl.ts +58 -17
- package/src/migrations/1719567881-organization-periodId.sql +2 -0
- package/src/migrations/1719567882-groups-periodId.sql +2 -0
- package/src/migrations/1720080975-convert-charset.ts +34 -0
- package/src/migrations/1720080976-convert-charset-leads.ts +16 -13
- package/src/migrations/1721400546-users-memberId.sql +2 -0
- package/src/migrations/1722269236-group-waitinglist-id.sql +2 -1
- package/src/migrations/1722525785-balance-item-paying-organization-id.sql +2 -0
- package/src/migrations/1722525787-depending-balance-item.sql +2 -0
- package/src/migrations/1722963554-registration-group-price-and-options.sql +1 -1
- package/src/migrations/1723652797-payments-paying-organization-id-fk.sql +2 -0
- package/src/migrations/1733317908-added-missing-organization-fk-on-registrations.sql +2 -0
- package/src/migrations/1733317910-paying-organization-id-fk.sql +2 -0
- package/src/migrations/1733504881-negative-invoice-id.sql +6 -0
- package/src/migrations/1733994455-balance-item-status-open.ts +30 -0
- package/src/migrations/1763216320-bigint-balance-item-payments.sql +2 -0
- package/src/migrations/1763216320-bigint-balance-items.sql +5 -0
- package/src/migrations/1763216320-bigint-orders.sql +2 -0
- package/src/migrations/1763216320-bigint-payments.sql +2 -0
- package/src/migrations/1763216332-bigint-balance-item-price-total.sql +2 -0
- package/src/migrations/1769087808-corrected-invoice-user-agent.sql +2 -0
- package/src/migrations/1769087809-payments-invoice-id.sql +2 -0
- package/src/migrations/1772033555-balance-item-package-id.sql +2 -0
- package/src/migrations/1776873089-create-registration-invitations-table.sql +13 -0
- package/src/migrations/1778657958-payments-create-mandate.sql +2 -0
- package/src/migrations/1778657959-payments-mandate-id.sql +2 -0
- package/src/migrations/1778796615-payments-reversing-payment-id.sql +5 -0
- package/src/migrations/1778950642-price-invoiced.sql +2 -0
- package/src/migrations/1779443446-transfer-fees.sql +3 -0
- package/src/migrations/1779709174-used-register-code-balance-item-id.sql +5 -0
- package/src/migrations/1779968328-payments-admin-user-id.sql +5 -0
- package/src/migrations/1779970611-payments-refunded-amount.sql +2 -0
- package/src/migrations/1779972640-balance-items-failed-at.sql +2 -0
- package/src/migrations/1780328285-document-template-locked.sql +2 -0
- package/src/migrations/1780328286-document-locked.sql +2 -0
- package/src/migrations/1780412083-documents-set-locked.ts +18 -0
- package/src/migrations/1780928401-v1-groups-migration-data.ts +50 -0
- package/src/models/BalanceItem.ts +98 -43
- package/src/models/CachedBalance.test.ts +46 -46
- package/src/models/CachedBalance.ts +7 -7
- package/src/models/Document.ts +34 -13
- package/src/models/DocumentTemplate.ts +56 -17
- package/src/models/Email.test.ts +3 -3
- package/src/models/Email.ts +28 -49
- package/src/models/EmailVerificationCode.ts +8 -22
- package/src/models/Event.ts +6 -4
- package/src/models/EventNotification.ts +6 -6
- package/src/models/Group.ts +24 -3
- package/src/models/Invoice.ts +10 -9
- package/src/models/MemberPlatformMembership.test.ts +70 -0
- package/src/models/MemberPlatformMembership.ts +16 -12
- package/src/models/MollieToken.ts +42 -102
- package/src/models/Order.ts +14 -26
- package/src/models/Organization.ts +143 -86
- package/src/models/PasswordToken.ts +21 -21
- package/src/models/Payment.ts +61 -4
- package/src/models/Registration.ts +6 -5
- package/src/models/RegistrationInvitation.ts +40 -0
- package/src/models/STCredit.ts +32 -0
- package/src/models/STInvoice.ts +11 -5
- package/src/models/STPackage.ts +19 -14
- package/src/models/UsedRegisterCode.ts +34 -0
- package/src/models/User.ts +6 -7
- package/src/models/_relations.ts +29 -0
- package/src/models/addresses/City.ts +8 -6
- package/src/models/addresses/PostalCode.test.ts +1 -0
- package/src/models/addresses/PostalCode.ts +5 -3
- package/src/models/addresses/Street.ts +6 -4
- package/src/models/index.ts +3 -0
- package/src/models/v1GroupMigrationData.ts +43 -0
- package/dist/helpers/MemberMerger.d.ts +0 -14
- package/dist/helpers/MemberMerger.d.ts.map +0 -1
- package/dist/helpers/MemberMerger.js +0 -364
- package/dist/helpers/MemberMerger.js.map +0 -1
- package/dist/migrations/1720080975-convert-charset.sql +0 -85
- package/dist/migrations/1723202126-member-number-index.sql +0 -2
- package/dist/models/OneTimeToken.d.ts +0 -38
- package/dist/models/OneTimeToken.d.ts.map +0 -1
- package/dist/models/OneTimeToken.js +0 -125
- package/dist/models/OneTimeToken.js.map +0 -1
- package/src/helpers/MemberMerger.test.ts +0 -782
- package/src/helpers/MemberMerger.ts +0 -577
- package/src/migrations/1720080975-convert-charset.sql +0 -85
- package/src/migrations/1723202126-member-number-index.sql +0 -2
- package/src/models/OneTimeToken.ts +0 -133
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { BalanceItemStatus } from '
|
|
2
|
-
import { ReceivableBalanceType } from '
|
|
1
|
+
import { BalanceItemStatus } from '@stamhoofd/structures/BalanceItem.js';
|
|
2
|
+
import { ReceivableBalanceType } from '@stamhoofd/structures/ReceivableBalance.js';
|
|
3
3
|
import { MemberFactory } from '../factories/MemberFactory.js';
|
|
4
4
|
import { OrganizationFactory } from '../factories/OrganizationFactory.js';
|
|
5
5
|
import { UserFactory } from '../factories/UserFactory.js';
|
|
@@ -21,19 +21,19 @@ describe('CachedBalance', () => {
|
|
|
21
21
|
|
|
22
22
|
test('Balances for members are summed', async () => {
|
|
23
23
|
const organization = await new OrganizationFactory({}).create();
|
|
24
|
-
const member = await new MemberFactory({organization}).create();
|
|
24
|
+
const member = await new MemberFactory({ organization }).create();
|
|
25
25
|
|
|
26
26
|
const balanceA = new BalanceItem();
|
|
27
|
-
balanceA.dueAt = null
|
|
27
|
+
balanceA.dueAt = null;
|
|
28
28
|
balanceA.quantity = 2;
|
|
29
29
|
balanceA.unitPrice = 1_00;
|
|
30
30
|
balanceA.memberId = member.id;
|
|
31
31
|
balanceA.organizationId = organization.id;
|
|
32
|
-
balanceA.status = BalanceItemStatus.Due
|
|
32
|
+
balanceA.status = BalanceItemStatus.Due;
|
|
33
33
|
await balanceA.save();
|
|
34
34
|
|
|
35
35
|
// Update cached balance for user.
|
|
36
|
-
await CachedBalance.updateForMembers(organization.id, [member.id])
|
|
36
|
+
await CachedBalance.updateForMembers(organization.id, [member.id]);
|
|
37
37
|
const cached = await CachedBalance.getForObjects([member.id], organization.id, ReceivableBalanceType.member);
|
|
38
38
|
expect(cached).toHaveLength(1);
|
|
39
39
|
expect(cached[0].amountOpen).toBe(2_00);
|
|
@@ -44,7 +44,7 @@ describe('CachedBalance', () => {
|
|
|
44
44
|
|
|
45
45
|
test('Balances less than 7 days in the future are summed', async () => {
|
|
46
46
|
const organization = await new OrganizationFactory({}).create();
|
|
47
|
-
const member = await new MemberFactory({organization}).create();
|
|
47
|
+
const member = await new MemberFactory({ organization }).create();
|
|
48
48
|
|
|
49
49
|
const balanceA = new BalanceItem();
|
|
50
50
|
balanceA.dueAt = new Date(now.getTime() + 1000 * 60 * 60 * 24 * 6); // 6 days later
|
|
@@ -52,11 +52,11 @@ describe('CachedBalance', () => {
|
|
|
52
52
|
balanceA.unitPrice = 1_00;
|
|
53
53
|
balanceA.memberId = member.id;
|
|
54
54
|
balanceA.organizationId = organization.id;
|
|
55
|
-
balanceA.status = BalanceItemStatus.Due
|
|
55
|
+
balanceA.status = BalanceItemStatus.Due;
|
|
56
56
|
await balanceA.save();
|
|
57
57
|
|
|
58
58
|
// Update cached balance for user.
|
|
59
|
-
await CachedBalance.updateForMembers(organization.id, [member.id])
|
|
59
|
+
await CachedBalance.updateForMembers(organization.id, [member.id]);
|
|
60
60
|
const cached = await CachedBalance.getForObjects([member.id], organization.id, ReceivableBalanceType.member);
|
|
61
61
|
expect(cached).toHaveLength(1);
|
|
62
62
|
expect(cached[0].amountOpen).toBe(1_00);
|
|
@@ -67,7 +67,7 @@ describe('CachedBalance', () => {
|
|
|
67
67
|
|
|
68
68
|
test('Balances more than 7 days in the future are not summed', async () => {
|
|
69
69
|
const organization = await new OrganizationFactory({}).create();
|
|
70
|
-
const member = await new MemberFactory({organization}).create();
|
|
70
|
+
const member = await new MemberFactory({ organization }).create();
|
|
71
71
|
|
|
72
72
|
const balanceA = new BalanceItem();
|
|
73
73
|
balanceA.dueAt = new Date(now.getTime() + 1000 * 60 * 60 * 24 * 8); // 8 days later
|
|
@@ -75,11 +75,11 @@ describe('CachedBalance', () => {
|
|
|
75
75
|
balanceA.unitPrice = 1_00;
|
|
76
76
|
balanceA.memberId = member.id;
|
|
77
77
|
balanceA.organizationId = organization.id;
|
|
78
|
-
balanceA.status = BalanceItemStatus.Due
|
|
78
|
+
balanceA.status = BalanceItemStatus.Due;
|
|
79
79
|
await balanceA.save();
|
|
80
80
|
|
|
81
81
|
// Update cached balance for user.
|
|
82
|
-
await CachedBalance.updateForMembers(organization.id, [member.id])
|
|
82
|
+
await CachedBalance.updateForMembers(organization.id, [member.id]);
|
|
83
83
|
const cached = await CachedBalance.getForObjects([member.id], organization.id, ReceivableBalanceType.member);
|
|
84
84
|
expect(cached).toHaveLength(1);
|
|
85
85
|
expect(cached[0].amountOpen).toBe(0);
|
|
@@ -90,7 +90,7 @@ describe('CachedBalance', () => {
|
|
|
90
90
|
|
|
91
91
|
test('Paid balances more than 7 days in the future are summed', async () => {
|
|
92
92
|
const organization = await new OrganizationFactory({}).create();
|
|
93
|
-
const member = await new MemberFactory({organization}).create();
|
|
93
|
+
const member = await new MemberFactory({ organization }).create();
|
|
94
94
|
|
|
95
95
|
const balanceA = new BalanceItem();
|
|
96
96
|
balanceA.dueAt = new Date(now.getTime() + 1000 * 60 * 60 * 24 * 8); // 8 days later
|
|
@@ -98,12 +98,12 @@ describe('CachedBalance', () => {
|
|
|
98
98
|
balanceA.unitPrice = 1_00;
|
|
99
99
|
balanceA.memberId = member.id;
|
|
100
100
|
balanceA.organizationId = organization.id;
|
|
101
|
-
balanceA.status = BalanceItemStatus.Due
|
|
101
|
+
balanceA.status = BalanceItemStatus.Due;
|
|
102
102
|
balanceA.pricePaid = 2_00;
|
|
103
103
|
await balanceA.save();
|
|
104
104
|
|
|
105
105
|
// Update cached balance for user.
|
|
106
|
-
await CachedBalance.updateForMembers(organization.id, [member.id])
|
|
106
|
+
await CachedBalance.updateForMembers(organization.id, [member.id]);
|
|
107
107
|
const cached = await CachedBalance.getForObjects([member.id], organization.id, ReceivableBalanceType.member);
|
|
108
108
|
expect(cached).toHaveLength(1);
|
|
109
109
|
expect(cached[0].amountOpen).toBe(0);
|
|
@@ -112,9 +112,9 @@ describe('CachedBalance', () => {
|
|
|
112
112
|
expect(cached[0].nextDueAt).toEqual(null);
|
|
113
113
|
});
|
|
114
114
|
|
|
115
|
-
|
|
115
|
+
test('Paid balances more than 7 days in the future are summed and due at is still set if only partially paid', async () => {
|
|
116
116
|
const organization = await new OrganizationFactory({}).create();
|
|
117
|
-
const member = await new MemberFactory({organization}).create();
|
|
117
|
+
const member = await new MemberFactory({ organization }).create();
|
|
118
118
|
|
|
119
119
|
const balanceA = new BalanceItem();
|
|
120
120
|
balanceA.dueAt = new Date(now.getTime() + 1000 * 60 * 60 * 24 * 8); // 8 days later
|
|
@@ -122,12 +122,12 @@ describe('CachedBalance', () => {
|
|
|
122
122
|
balanceA.unitPrice = 1_00;
|
|
123
123
|
balanceA.memberId = member.id;
|
|
124
124
|
balanceA.organizationId = organization.id;
|
|
125
|
-
balanceA.status = BalanceItemStatus.Due
|
|
125
|
+
balanceA.status = BalanceItemStatus.Due;
|
|
126
126
|
balanceA.pricePaid = 1_00;
|
|
127
127
|
await balanceA.save();
|
|
128
128
|
|
|
129
129
|
// Update cached balance for user.
|
|
130
|
-
await CachedBalance.updateForMembers(organization.id, [member.id])
|
|
130
|
+
await CachedBalance.updateForMembers(organization.id, [member.id]);
|
|
131
131
|
const cached = await CachedBalance.getForObjects([member.id], organization.id, ReceivableBalanceType.member);
|
|
132
132
|
expect(cached).toHaveLength(1);
|
|
133
133
|
expect(cached[0].amountOpen).toBe(0);
|
|
@@ -138,7 +138,7 @@ describe('CachedBalance', () => {
|
|
|
138
138
|
|
|
139
139
|
test('Canceled items are not summed', async () => {
|
|
140
140
|
const organization = await new OrganizationFactory({}).create();
|
|
141
|
-
const member = await new MemberFactory({organization}).create();
|
|
141
|
+
const member = await new MemberFactory({ organization }).create();
|
|
142
142
|
|
|
143
143
|
const balanceA = new BalanceItem();
|
|
144
144
|
balanceA.dueAt = null;
|
|
@@ -146,11 +146,11 @@ describe('CachedBalance', () => {
|
|
|
146
146
|
balanceA.unitPrice = 1_00;
|
|
147
147
|
balanceA.memberId = member.id;
|
|
148
148
|
balanceA.organizationId = organization.id;
|
|
149
|
-
balanceA.status = BalanceItemStatus.Canceled
|
|
149
|
+
balanceA.status = BalanceItemStatus.Canceled;
|
|
150
150
|
await balanceA.save();
|
|
151
151
|
|
|
152
152
|
// Update cached balance for user.
|
|
153
|
-
await CachedBalance.updateForMembers(organization.id, [member.id])
|
|
153
|
+
await CachedBalance.updateForMembers(organization.id, [member.id]);
|
|
154
154
|
const cached = await CachedBalance.getForObjects([member.id], organization.id, ReceivableBalanceType.member);
|
|
155
155
|
expect(cached).toHaveLength(1);
|
|
156
156
|
expect(cached[0].amountOpen).toBe(0);
|
|
@@ -160,7 +160,7 @@ describe('CachedBalance', () => {
|
|
|
160
160
|
|
|
161
161
|
test('Hidden items are not summed', async () => {
|
|
162
162
|
const organization = await new OrganizationFactory({}).create();
|
|
163
|
-
const member = await new MemberFactory({organization}).create();
|
|
163
|
+
const member = await new MemberFactory({ organization }).create();
|
|
164
164
|
|
|
165
165
|
const balanceA = new BalanceItem();
|
|
166
166
|
balanceA.dueAt = null;
|
|
@@ -168,11 +168,11 @@ describe('CachedBalance', () => {
|
|
|
168
168
|
balanceA.unitPrice = 1_00;
|
|
169
169
|
balanceA.memberId = member.id;
|
|
170
170
|
balanceA.organizationId = organization.id;
|
|
171
|
-
balanceA.status = BalanceItemStatus.Hidden
|
|
171
|
+
balanceA.status = BalanceItemStatus.Hidden;
|
|
172
172
|
await balanceA.save();
|
|
173
173
|
|
|
174
174
|
// Update cached balance for user.
|
|
175
|
-
await CachedBalance.updateForMembers(organization.id, [member.id])
|
|
175
|
+
await CachedBalance.updateForMembers(organization.id, [member.id]);
|
|
176
176
|
const cached = await CachedBalance.getForObjects([member.id], organization.id, ReceivableBalanceType.member);
|
|
177
177
|
expect(cached).toHaveLength(1);
|
|
178
178
|
expect(cached[0].amountOpen).toBe(0);
|
|
@@ -183,8 +183,8 @@ describe('CachedBalance', () => {
|
|
|
183
183
|
describe('nextDueAt for users with members', () => {
|
|
184
184
|
test('Two balance items in the future are merged if less than 7 days in the future', async () => {
|
|
185
185
|
const organization = await new OrganizationFactory({}).create();
|
|
186
|
-
const member = await new MemberFactory({organization}).create();
|
|
187
|
-
const user = await new UserFactory({organization}).create();
|
|
186
|
+
const member = await new MemberFactory({ organization }).create();
|
|
187
|
+
const user = await new UserFactory({ organization }).create();
|
|
188
188
|
|
|
189
189
|
// Link member with user
|
|
190
190
|
await Member.users.reverse('members').link(user, [member]);
|
|
@@ -195,7 +195,7 @@ describe('CachedBalance', () => {
|
|
|
195
195
|
balanceA.unitPrice = 1_00;
|
|
196
196
|
balanceA.memberId = member.id;
|
|
197
197
|
balanceA.organizationId = organization.id;
|
|
198
|
-
balanceA.status = BalanceItemStatus.Due
|
|
198
|
+
balanceA.status = BalanceItemStatus.Due;
|
|
199
199
|
await balanceA.save();
|
|
200
200
|
|
|
201
201
|
const balanceB = new BalanceItem();
|
|
@@ -204,12 +204,12 @@ describe('CachedBalance', () => {
|
|
|
204
204
|
balanceB.unitPrice = 1_00;
|
|
205
205
|
balanceB.userId = user.id;
|
|
206
206
|
balanceB.organizationId = organization.id;
|
|
207
|
-
balanceB.status = BalanceItemStatus.Due
|
|
207
|
+
balanceB.status = BalanceItemStatus.Due;
|
|
208
208
|
await balanceB.save();
|
|
209
209
|
|
|
210
210
|
// Update cached balance for user.
|
|
211
|
-
await CachedBalance.updateForMembers(organization.id, [member.id])
|
|
212
|
-
await CachedBalance.updateForUsers(organization.id, [user.id])
|
|
211
|
+
await CachedBalance.updateForMembers(organization.id, [member.id]);
|
|
212
|
+
await CachedBalance.updateForUsers(organization.id, [user.id]);
|
|
213
213
|
{
|
|
214
214
|
const cached = await CachedBalance.getForObjects([user.id], organization.id, ReceivableBalanceType.user);
|
|
215
215
|
expect(cached).toHaveLength(1);
|
|
@@ -231,8 +231,8 @@ describe('CachedBalance', () => {
|
|
|
231
231
|
|
|
232
232
|
test('[Regression] Two balance items more than 7 days in the future set correct nextDueAt', async () => {
|
|
233
233
|
const organization = await new OrganizationFactory({}).create();
|
|
234
|
-
const member = await new MemberFactory({organization}).create();
|
|
235
|
-
const user = await new UserFactory({organization}).create();
|
|
234
|
+
const member = await new MemberFactory({ organization }).create();
|
|
235
|
+
const user = await new UserFactory({ organization }).create();
|
|
236
236
|
|
|
237
237
|
// Link member with user
|
|
238
238
|
await Member.users.reverse('members').link(user, [member]);
|
|
@@ -243,7 +243,7 @@ describe('CachedBalance', () => {
|
|
|
243
243
|
balanceA.unitPrice = 1_00;
|
|
244
244
|
balanceA.memberId = member.id;
|
|
245
245
|
balanceA.organizationId = organization.id;
|
|
246
|
-
balanceA.status = BalanceItemStatus.Due
|
|
246
|
+
balanceA.status = BalanceItemStatus.Due;
|
|
247
247
|
await balanceA.save();
|
|
248
248
|
|
|
249
249
|
const balanceB = new BalanceItem();
|
|
@@ -252,12 +252,12 @@ describe('CachedBalance', () => {
|
|
|
252
252
|
balanceB.unitPrice = 1_00;
|
|
253
253
|
balanceB.userId = user.id;
|
|
254
254
|
balanceB.organizationId = organization.id;
|
|
255
|
-
balanceB.status = BalanceItemStatus.Due
|
|
255
|
+
balanceB.status = BalanceItemStatus.Due;
|
|
256
256
|
await balanceB.save();
|
|
257
257
|
|
|
258
258
|
// Update cached balance for user.
|
|
259
|
-
await CachedBalance.updateForMembers(organization.id, [member.id])
|
|
260
|
-
await CachedBalance.updateForUsers(organization.id, [user.id])
|
|
259
|
+
await CachedBalance.updateForMembers(organization.id, [member.id]);
|
|
260
|
+
await CachedBalance.updateForUsers(organization.id, [user.id]);
|
|
261
261
|
{
|
|
262
262
|
const cached = await CachedBalance.getForObjects([user.id], organization.id, ReceivableBalanceType.user);
|
|
263
263
|
expect(cached).toHaveLength(1);
|
|
@@ -278,9 +278,9 @@ describe('CachedBalance', () => {
|
|
|
278
278
|
|
|
279
279
|
// Advance time with one day, balanceA is now less than 7 days in the future and should be included in the cached balance.
|
|
280
280
|
// nextDueAt should be different and set to balanceB.dueAt
|
|
281
|
-
vitest.setSystemTime(new Date(now.getTime() + 1000 * 60 * 60 * 24 * 1))
|
|
282
|
-
await CachedBalance.updateForMembers(organization.id, [member.id])
|
|
283
|
-
await CachedBalance.updateForUsers(organization.id, [user.id])
|
|
281
|
+
vitest.setSystemTime(new Date(now.getTime() + 1000 * 60 * 60 * 24 * 1));
|
|
282
|
+
await CachedBalance.updateForMembers(organization.id, [member.id]);
|
|
283
|
+
await CachedBalance.updateForUsers(organization.id, [user.id]);
|
|
284
284
|
const cachedAfter = await CachedBalance.getForObjects([user.id], organization.id, ReceivableBalanceType.user);
|
|
285
285
|
expect(cachedAfter).toHaveLength(1);
|
|
286
286
|
expect(cachedAfter[0].amountOpen).toBe(1_00);
|
|
@@ -291,8 +291,8 @@ describe('CachedBalance', () => {
|
|
|
291
291
|
|
|
292
292
|
test('Two balance items more than 7 days in the future that are partially paid are summed correctly', async () => {
|
|
293
293
|
const organization = await new OrganizationFactory({}).create();
|
|
294
|
-
const member = await new MemberFactory({organization}).create();
|
|
295
|
-
const user = await new UserFactory({organization}).create();
|
|
294
|
+
const member = await new MemberFactory({ organization }).create();
|
|
295
|
+
const user = await new UserFactory({ organization }).create();
|
|
296
296
|
|
|
297
297
|
// Link member with user
|
|
298
298
|
await Member.users.reverse('members').link(user, [member]);
|
|
@@ -304,7 +304,7 @@ describe('CachedBalance', () => {
|
|
|
304
304
|
balanceA.memberId = member.id;
|
|
305
305
|
balanceA.organizationId = organization.id;
|
|
306
306
|
balanceA.pricePaid = 50;
|
|
307
|
-
balanceA.status = BalanceItemStatus.Due
|
|
307
|
+
balanceA.status = BalanceItemStatus.Due;
|
|
308
308
|
await balanceA.save();
|
|
309
309
|
|
|
310
310
|
const balanceB = new BalanceItem();
|
|
@@ -314,12 +314,12 @@ describe('CachedBalance', () => {
|
|
|
314
314
|
balanceB.userId = user.id;
|
|
315
315
|
balanceB.organizationId = organization.id;
|
|
316
316
|
balanceB.pricePaid = 50;
|
|
317
|
-
balanceB.status = BalanceItemStatus.Due
|
|
317
|
+
balanceB.status = BalanceItemStatus.Due;
|
|
318
318
|
await balanceB.save();
|
|
319
319
|
|
|
320
320
|
// Update cached balance for user.
|
|
321
|
-
await CachedBalance.updateForMembers(organization.id, [member.id])
|
|
322
|
-
await CachedBalance.updateForUsers(organization.id, [user.id])
|
|
321
|
+
await CachedBalance.updateForMembers(organization.id, [member.id]);
|
|
322
|
+
await CachedBalance.updateForUsers(organization.id, [user.id]);
|
|
323
323
|
const cached = await CachedBalance.getForObjects([user.id], organization.id, ReceivableBalanceType.user);
|
|
324
324
|
expect(cached).toHaveLength(1);
|
|
325
325
|
expect(cached[0].amountOpen).toBe(0);
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { column } from '@simonbackx/simple-database';
|
|
2
|
-
import type { SQLWhere} from '@stamhoofd/sql';
|
|
2
|
+
import type { SQLWhere } from '@stamhoofd/sql';
|
|
3
3
|
import { QueryableModel, SQL, SQLAlias, SQLMin, SQLSelectAs, SQLSum, SQLWhereSign } from '@stamhoofd/sql';
|
|
4
4
|
import { BalanceItemStatus, BalanceItem as BalanceItemStruct, ReceivableBalanceType } from '@stamhoofd/structures';
|
|
5
|
+
import { Formatter } from '@stamhoofd/utility';
|
|
5
6
|
import { v4 as uuidv4 } from 'uuid';
|
|
6
7
|
import { BalanceItem } from './BalanceItem.js';
|
|
7
8
|
import { MemberUser } from './MemberUser.js';
|
|
8
|
-
import { Formatter } from '@stamhoofd/utility';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
* Keeps track of how much a member/user owes or needs to be reimbursed.
|
|
@@ -328,8 +328,7 @@ export class CachedBalance extends QueryableModel {
|
|
|
328
328
|
|
|
329
329
|
result[1].amountPending += amountPending;
|
|
330
330
|
result[1].amountPaid += amountPaid;
|
|
331
|
-
}
|
|
332
|
-
else {
|
|
331
|
+
} else {
|
|
333
332
|
results.push([objectId, { amountPaid, amountOpen: 0, amountPending, nextDueAt: amountOpen !== 0 ? dueAt : null }]);
|
|
334
333
|
}
|
|
335
334
|
}
|
|
@@ -407,10 +406,12 @@ export class CachedBalance extends QueryableModel {
|
|
|
407
406
|
|
|
408
407
|
static async updateForOrganizations(organizationId: string, organizationIds: string[]) {
|
|
409
408
|
if (organizationIds.length === 0) {
|
|
410
|
-
return;
|
|
409
|
+
return [];
|
|
411
410
|
}
|
|
412
411
|
const results = await this.fetchForObjects(organizationId, organizationIds, 'payingOrganizationId');
|
|
413
412
|
await this.setForResults(organizationId, results, ReceivableBalanceType.organization);
|
|
413
|
+
|
|
414
|
+
return results;
|
|
414
415
|
}
|
|
415
416
|
|
|
416
417
|
static async updateForMembers(organizationId: string, memberIds: string[]) {
|
|
@@ -462,8 +463,7 @@ export class CachedBalance extends QueryableModel {
|
|
|
462
463
|
if (memberCachedBalance.nextDueAt && (!result[1].nextDueAt || memberCachedBalance.nextDueAt < result[1].nextDueAt)) {
|
|
463
464
|
result[1].nextDueAt = memberCachedBalance.nextDueAt;
|
|
464
465
|
}
|
|
465
|
-
}
|
|
466
|
-
else {
|
|
466
|
+
} else {
|
|
467
467
|
// Not possible
|
|
468
468
|
throw new Error('User not found in results');
|
|
469
469
|
}
|
package/src/models/Document.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { DocumentData, DocumentStatus, Document as DocumentStruct, Platform, Ver
|
|
|
3
3
|
import { Formatter } from '@stamhoofd/utility';
|
|
4
4
|
import { v4 as uuidv4 } from 'uuid';
|
|
5
5
|
|
|
6
|
+
import { SimpleError } from '@simonbackx/simple-errors';
|
|
6
7
|
import { QueryableModel } from '@stamhoofd/sql';
|
|
7
8
|
import { render } from '../helpers/Handlebars.js';
|
|
8
9
|
import type { Member, MemberWithRegistrations, RegistrationWithMember } from './Member.js';
|
|
@@ -38,6 +39,9 @@ export class Document extends QueryableModel {
|
|
|
38
39
|
@column({ type: 'string' })
|
|
39
40
|
status = DocumentStatus.Draft;
|
|
40
41
|
|
|
42
|
+
@column({ type: 'boolean' })
|
|
43
|
+
isLocked = false;
|
|
44
|
+
|
|
41
45
|
/**
|
|
42
46
|
* Assigned when exporting the document
|
|
43
47
|
*/
|
|
@@ -63,6 +67,18 @@ export class Document extends QueryableModel {
|
|
|
63
67
|
})
|
|
64
68
|
updatedAt: Date;
|
|
65
69
|
|
|
70
|
+
override save(options?: Parameters<QueryableModel['save']>[0] & { forceSave?: boolean }): Promise<boolean> {
|
|
71
|
+
if (!options?.forceSave && this.isLocked) {
|
|
72
|
+
throw new SimpleError({
|
|
73
|
+
code: 'locked',
|
|
74
|
+
message: 'Document is locked',
|
|
75
|
+
human: $t(`%1Uc`),
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return super.save(options);
|
|
80
|
+
}
|
|
81
|
+
|
|
66
82
|
getStructure() {
|
|
67
83
|
return DocumentStruct.create(this);
|
|
68
84
|
}
|
|
@@ -84,6 +100,7 @@ export class Document extends QueryableModel {
|
|
|
84
100
|
};
|
|
85
101
|
const platformLogo = Platform.shared.config.logoDocuments ?? Platform.shared.config.horizontalLogo ?? Platform.shared.config.squareLogo;
|
|
86
102
|
const organizationLogo = organization.meta.horizontalLogo ?? organization.meta.squareLogo;
|
|
103
|
+
const logo = organizationLogo || platformLogo;
|
|
87
104
|
|
|
88
105
|
if (organizationLogo) {
|
|
89
106
|
data['organization'] = {
|
|
@@ -98,6 +115,10 @@ export class Document extends QueryableModel {
|
|
|
98
115
|
};
|
|
99
116
|
}
|
|
100
117
|
|
|
118
|
+
if (logo) {
|
|
119
|
+
data['logo'] = logo.encode({ version: Version }) ?? null;
|
|
120
|
+
}
|
|
121
|
+
|
|
101
122
|
for (const field of this.data.fieldAnswers.values()) {
|
|
102
123
|
const keys = field.settings.id.split('.');
|
|
103
124
|
let current = data;
|
|
@@ -121,6 +142,11 @@ export class Document extends QueryableModel {
|
|
|
121
142
|
}
|
|
122
143
|
|
|
123
144
|
async updateData(): Promise<void> {
|
|
145
|
+
if (this.isLocked) {
|
|
146
|
+
console.log('Document is locked, skipping update');
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
|
|
124
150
|
const DocumentTemplate = (await import('./DocumentTemplate.js')).DocumentTemplate;
|
|
125
151
|
const template = await DocumentTemplate.getByID(this.templateId);
|
|
126
152
|
if (!template) {
|
|
@@ -165,8 +191,7 @@ export class Document extends QueryableModel {
|
|
|
165
191
|
await this.updateForRegistrations(loadedMember.registrations.filter(r => r.registeredAt && r.deactivatedAt === null && r.organizationId === organizationId).map(r => r.id), organizationId);
|
|
166
192
|
}
|
|
167
193
|
}
|
|
168
|
-
}
|
|
169
|
-
catch (e) {
|
|
194
|
+
} catch (e) {
|
|
170
195
|
console.error(e);
|
|
171
196
|
}
|
|
172
197
|
}
|
|
@@ -176,13 +201,12 @@ export class Document extends QueryableModel {
|
|
|
176
201
|
console.log('Updating documents for registration', registration.id);
|
|
177
202
|
|
|
178
203
|
const DocumentTemplate = (await import('./DocumentTemplate.js')).DocumentTemplate;
|
|
179
|
-
const templates = await DocumentTemplate.where({ updatesEnabled: 1, organizationId: registration.organizationId });
|
|
204
|
+
const templates = await DocumentTemplate.where({ updatesEnabled: 1, isLocked: 0, organizationId: registration.organizationId });
|
|
180
205
|
|
|
181
206
|
for (const template of templates) {
|
|
182
207
|
await template.updateForRegistration(registration);
|
|
183
208
|
}
|
|
184
|
-
}
|
|
185
|
-
catch (e) {
|
|
209
|
+
} catch (e) {
|
|
186
210
|
console.error(e);
|
|
187
211
|
}
|
|
188
212
|
}
|
|
@@ -208,7 +232,7 @@ export class Document extends QueryableModel {
|
|
|
208
232
|
console.log('Updating documents for updateForRegistrations', registrationIds, organizationId);
|
|
209
233
|
|
|
210
234
|
const DocumentTemplate = (await import('./DocumentTemplate.js')).DocumentTemplate;
|
|
211
|
-
const templates = await DocumentTemplate.where({ updatesEnabled: 1, organizationId });
|
|
235
|
+
const templates = await DocumentTemplate.where({ updatesEnabled: 1, isLocked: 0, organizationId });
|
|
212
236
|
|
|
213
237
|
if (templates.length) {
|
|
214
238
|
const Member = (await import('./Member.js')).Member;
|
|
@@ -219,8 +243,7 @@ export class Document extends QueryableModel {
|
|
|
219
243
|
await template.updateForRegistrations(loadedRegistrations);
|
|
220
244
|
}
|
|
221
245
|
}
|
|
222
|
-
}
|
|
223
|
-
catch (e) {
|
|
246
|
+
} catch (e) {
|
|
224
247
|
console.error(e);
|
|
225
248
|
}
|
|
226
249
|
}
|
|
@@ -230,7 +253,7 @@ export class Document extends QueryableModel {
|
|
|
230
253
|
console.log('Updating documents for group', groupId);
|
|
231
254
|
|
|
232
255
|
const DocumentTemplate = (await import('./DocumentTemplate.js')).DocumentTemplate;
|
|
233
|
-
const templates = await DocumentTemplate.where({ updatesEnabled: 1, organizationId });
|
|
256
|
+
const templates = await DocumentTemplate.where({ updatesEnabled: 1, isLocked: 0, organizationId });
|
|
234
257
|
|
|
235
258
|
if (templates.length) {
|
|
236
259
|
const Member = (await import('./Member.js')).Member;
|
|
@@ -240,8 +263,7 @@ export class Document extends QueryableModel {
|
|
|
240
263
|
await template.updateForRegistrations(registrations);
|
|
241
264
|
}
|
|
242
265
|
}
|
|
243
|
-
}
|
|
244
|
-
catch (e) {
|
|
266
|
+
} catch (e) {
|
|
245
267
|
console.error(e);
|
|
246
268
|
}
|
|
247
269
|
}
|
|
@@ -263,8 +285,7 @@ export class Document extends QueryableModel {
|
|
|
263
285
|
const context = this.buildContext(organization);
|
|
264
286
|
const renderedHtml = await render(htmlTemplate, context);
|
|
265
287
|
return renderedHtml;
|
|
266
|
-
}
|
|
267
|
-
catch (e) {
|
|
288
|
+
} catch (e) {
|
|
268
289
|
console.error('Failed to render document html', e);
|
|
269
290
|
return null;
|
|
270
291
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { column } from '@simonbackx/simple-database';
|
|
2
2
|
import { isSimpleError, isSimpleErrors, SimpleError } from '@simonbackx/simple-errors';
|
|
3
3
|
import { QueueHandler } from '@stamhoofd/queues';
|
|
4
|
-
import type { Parent, RecordAnswer} from '@stamhoofd/structures';
|
|
4
|
+
import type { Parent, RecordAnswer } from '@stamhoofd/structures';
|
|
5
5
|
import { BalanceItemStatus, DocumentData, DocumentPrivateSettings, DocumentSettings, DocumentStatus, DocumentTemplatePrivate, GroupType, NationalRegisterNumberOptOut, RecordAddressAnswer, RecordAnswerDecoder, RecordDateAnswer, RecordPriceAnswer, RecordSettings, RecordTextAnswer, RecordType } from '@stamhoofd/structures';
|
|
6
6
|
import { Formatter, Sorter } from '@stamhoofd/utility';
|
|
7
7
|
import { v4 as uuidv4 } from 'uuid';
|
|
@@ -37,6 +37,9 @@ export class DocumentTemplate extends QueryableModel {
|
|
|
37
37
|
@column({ type: 'string' })
|
|
38
38
|
status = DocumentStatus.Draft;
|
|
39
39
|
|
|
40
|
+
@column({ type: 'boolean' })
|
|
41
|
+
isLocked = false;
|
|
42
|
+
|
|
40
43
|
@column({ type: 'boolean' })
|
|
41
44
|
updatesEnabled = true;
|
|
42
45
|
|
|
@@ -87,6 +90,18 @@ export class DocumentTemplate extends QueryableModel {
|
|
|
87
90
|
})
|
|
88
91
|
updatedAt: Date;
|
|
89
92
|
|
|
93
|
+
override save(options?: Parameters<QueryableModel['save']>[0] & { forceSave?: boolean }): Promise<boolean> {
|
|
94
|
+
if (!options?.forceSave && this.isLocked) {
|
|
95
|
+
throw new SimpleError({
|
|
96
|
+
code: 'locked',
|
|
97
|
+
message: 'Document template is locked',
|
|
98
|
+
human: $t(`%1Uc`),
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return super.save(options);
|
|
103
|
+
}
|
|
104
|
+
|
|
90
105
|
getPrivateStructure() {
|
|
91
106
|
return DocumentTemplatePrivate.create(this);
|
|
92
107
|
}
|
|
@@ -363,8 +378,7 @@ export class DocumentTemplate extends QueryableModel {
|
|
|
363
378
|
found = true;
|
|
364
379
|
fieldAnswers.set(field.id, clone);
|
|
365
380
|
break;
|
|
366
|
-
}
|
|
367
|
-
else {
|
|
381
|
+
} else {
|
|
368
382
|
console.warn('Found type mismatch for default data: ' + linkedToMemberAnswerSettingsId + ' - ' + field.id);
|
|
369
383
|
}
|
|
370
384
|
}
|
|
@@ -412,8 +426,7 @@ export class DocumentTemplate extends QueryableModel {
|
|
|
412
426
|
for (const answer of fieldAnswers.values()) {
|
|
413
427
|
try {
|
|
414
428
|
answer.validate();
|
|
415
|
-
}
|
|
416
|
-
catch (e) {
|
|
429
|
+
} catch (e) {
|
|
417
430
|
missingData = true;
|
|
418
431
|
|
|
419
432
|
console.log('Missing data because of validation error', e, answer, answer.settings);
|
|
@@ -453,6 +466,14 @@ export class DocumentTemplate extends QueryableModel {
|
|
|
453
466
|
}
|
|
454
467
|
|
|
455
468
|
async updateForRegistration(registration: RegistrationWithMember, existingDocuments?: Document[]): Promise<Document[]> {
|
|
469
|
+
if (this.isLocked) {
|
|
470
|
+
throw new SimpleError({
|
|
471
|
+
code: 'locked',
|
|
472
|
+
message: 'Document template is locked',
|
|
473
|
+
human: $t(`%1Uc`),
|
|
474
|
+
});
|
|
475
|
+
}
|
|
476
|
+
|
|
456
477
|
existingDocuments = existingDocuments !== undefined ? existingDocuments : await Document.where({ templateId: this.id, registrationId: registration.id }, { limit: 5 });
|
|
457
478
|
|
|
458
479
|
if (!this.checkRegistrationIncluded(registration)) {
|
|
@@ -549,8 +570,7 @@ export class DocumentTemplate extends QueryableModel {
|
|
|
549
570
|
if (age > this.settings.maxAge) {
|
|
550
571
|
return false;
|
|
551
572
|
}
|
|
552
|
-
}
|
|
553
|
-
else {
|
|
573
|
+
} else {
|
|
554
574
|
console.warn('Missing registration.startDate in fieldAnswers when checking maxAge');
|
|
555
575
|
}
|
|
556
576
|
}
|
|
@@ -581,11 +601,20 @@ export class DocumentTemplate extends QueryableModel {
|
|
|
581
601
|
async buildAll({ generateNumbers = false } = {}) {
|
|
582
602
|
QueueHandler.abort('documents-build-all/' + this.id);
|
|
583
603
|
return await QueueHandler.schedule('documents-build-all/' + this.id, async ({ abort }) => {
|
|
604
|
+
if (this.isLocked) {
|
|
605
|
+
return await Document.where({ templateId: this.id });
|
|
606
|
+
}
|
|
607
|
+
|
|
584
608
|
if (!this.updatesEnabled) {
|
|
585
609
|
// Check status
|
|
586
610
|
const documents = await Document.where({ templateId: this.id });
|
|
587
611
|
for (const document of documents) {
|
|
588
612
|
abort.throwIfAborted();
|
|
613
|
+
|
|
614
|
+
if (document.isLocked) {
|
|
615
|
+
continue;
|
|
616
|
+
}
|
|
617
|
+
|
|
589
618
|
await this.updateAnswers(document); // Only update global data
|
|
590
619
|
if (document.status === DocumentStatus.Draft || document.status === DocumentStatus.Published) {
|
|
591
620
|
document.status = this.status;
|
|
@@ -597,6 +626,11 @@ export class DocumentTemplate extends QueryableModel {
|
|
|
597
626
|
if (generateNumbers) {
|
|
598
627
|
for (const document of documents) {
|
|
599
628
|
abort.throwIfAborted();
|
|
629
|
+
|
|
630
|
+
if (document.isLocked) {
|
|
631
|
+
continue;
|
|
632
|
+
}
|
|
633
|
+
|
|
600
634
|
if (document.number === null && document.status === DocumentStatus.Published) {
|
|
601
635
|
document.number = this.nextNumberForDocuments(documents);
|
|
602
636
|
await document.save();
|
|
@@ -627,11 +661,15 @@ export class DocumentTemplate extends QueryableModel {
|
|
|
627
661
|
const documents = await Document.where({ templateId: this.id });
|
|
628
662
|
for (const document of documents) {
|
|
629
663
|
abort.throwIfAborted();
|
|
664
|
+
|
|
665
|
+
if (document.isLocked) {
|
|
666
|
+
continue;
|
|
667
|
+
}
|
|
668
|
+
|
|
630
669
|
if (!documentSet.has(document.id)) {
|
|
631
670
|
if (document.number === null) {
|
|
632
671
|
await document.delete();
|
|
633
|
-
}
|
|
634
|
-
else {
|
|
672
|
+
} else {
|
|
635
673
|
document.status = DocumentStatus.Deleted;
|
|
636
674
|
await document.save();
|
|
637
675
|
}
|
|
@@ -644,6 +682,11 @@ export class DocumentTemplate extends QueryableModel {
|
|
|
644
682
|
if (generateNumbers) {
|
|
645
683
|
for (const document of allDocuments) {
|
|
646
684
|
abort.throwIfAborted();
|
|
685
|
+
|
|
686
|
+
if (document.isLocked) {
|
|
687
|
+
continue;
|
|
688
|
+
}
|
|
689
|
+
|
|
647
690
|
if (document.number === null && document.status === DocumentStatus.Published) {
|
|
648
691
|
document.number = this.nextNumberForDocuments(allDocuments);
|
|
649
692
|
await document.save();
|
|
@@ -733,8 +776,7 @@ export class DocumentTemplate extends QueryableModel {
|
|
|
733
776
|
const context = await this.buildContext(organization);
|
|
734
777
|
const renderedHtml = await render(this.privateSettings.templateDefinition.xmlExport, context);
|
|
735
778
|
return renderedHtml;
|
|
736
|
-
}
|
|
737
|
-
catch (e) {
|
|
779
|
+
} catch (e) {
|
|
738
780
|
if (isSimpleError(e) || isSimpleErrors(e)) {
|
|
739
781
|
throw e;
|
|
740
782
|
}
|
|
@@ -753,8 +795,7 @@ export class DocumentTemplate extends QueryableModel {
|
|
|
753
795
|
answer.settings = field;
|
|
754
796
|
try {
|
|
755
797
|
answer.validate();
|
|
756
|
-
}
|
|
757
|
-
catch (e) {
|
|
798
|
+
} catch (e) {
|
|
758
799
|
// Invalid
|
|
759
800
|
return false;
|
|
760
801
|
}
|
|
@@ -774,8 +815,7 @@ export class DocumentTemplate extends QueryableModel {
|
|
|
774
815
|
if (!existing.isReviewedAfter(addAnswer)) {
|
|
775
816
|
newAnswers.set(addAnswer.settings.id, addAnswer);
|
|
776
817
|
}
|
|
777
|
-
}
|
|
778
|
-
else {
|
|
818
|
+
} else {
|
|
779
819
|
newAnswers.set(addAnswer.settings.id, addAnswer);
|
|
780
820
|
}
|
|
781
821
|
}
|
|
@@ -786,8 +826,7 @@ export class DocumentTemplate extends QueryableModel {
|
|
|
786
826
|
if (document.status !== DocumentStatus.Deleted) {
|
|
787
827
|
if (!complete) {
|
|
788
828
|
document.status = DocumentStatus.MissingData;
|
|
789
|
-
}
|
|
790
|
-
else {
|
|
829
|
+
} else {
|
|
791
830
|
if (document.status === DocumentStatus.MissingData) {
|
|
792
831
|
document.status = this.status;
|
|
793
832
|
}
|