@stamhoofd/models 2.121.0 → 2.122.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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/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/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 +7 -1
- package/dist/helpers/Handlebars.js.map +1 -1
- 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/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/1778796615-payments-reversing-payment-id.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 +7 -2
- package/dist/models/BalanceItem.d.ts.map +1 -1
- package/dist/models/BalanceItem.js +41 -38
- 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/Invoice.d.ts +1 -0
- package/dist/models/Invoice.d.ts.map +1 -1
- package/dist/models/Invoice.js +8 -0
- 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/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 +23 -25
- package/dist/models/Organization.d.ts.map +1 -1
- package/dist/models/Organization.js +92 -64
- 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 +21 -2
- package/dist/models/Payment.d.ts.map +1 -1
- package/dist/models/Payment.js +43 -2
- package/dist/models/Payment.js.map +1 -1
- package/dist/models/Registration.d.ts.map +1 -1
- package/dist/models/Registration.js +3 -3
- package/dist/models/Registration.js.map +1 -1
- 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/_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 +1 -0
- package/dist/models/index.d.ts.map +1 -1
- package/dist/models/index.js +1 -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 +32 -13
- package/src/factories/GroupFactory.ts +4 -6
- package/src/factories/OrganizationFactory.ts +12 -4
- package/src/factories/STPackageFactory.ts +2 -2
- package/src/factories/UserFactory.ts +4 -5
- package/src/helpers/EmailBuilder.ts +19 -28
- package/src/helpers/Handlebars.ts +6 -1
- 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/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/1778796615-payments-reversing-payment-id.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 +44 -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/Invoice.ts +9 -0
- package/src/models/MemberPlatformMembership.test.ts +70 -0
- package/src/models/MemberPlatformMembership.ts +16 -12
- package/src/models/Order.ts +14 -26
- package/src/models/Organization.ts +122 -93
- package/src/models/PasswordToken.ts +21 -21
- package/src/models/Payment.ts +42 -4
- package/src/models/Registration.ts +3 -3
- 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/_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 +2 -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
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { Database, Migration } from '@simonbackx/simple-database';
|
|
2
|
+
import { BalanceItemStatus } from '@stamhoofd/structures';
|
|
3
|
+
|
|
4
|
+
export default new Migration(async () => {
|
|
5
|
+
if (STAMHOOFD.environment === 'test') {
|
|
6
|
+
console.log('skipped in tests');
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const query = `
|
|
11
|
+
UPDATE
|
|
12
|
+
balance_items
|
|
13
|
+
SET status = ?
|
|
14
|
+
WHERE status IN (?)`;
|
|
15
|
+
await Database.update(query, [
|
|
16
|
+
BalanceItemStatus.Due,
|
|
17
|
+
['Paid', 'Pending'],
|
|
18
|
+
]);
|
|
19
|
+
|
|
20
|
+
const q2 = `
|
|
21
|
+
UPDATE
|
|
22
|
+
balance_items
|
|
23
|
+
SET status = ?,
|
|
24
|
+
amount = coalesce(nullif(ROUND(coalesce(pricePaid / nullif(unitPrice, 0), 0)), 0), 1)
|
|
25
|
+
WHERE amount = 0 AND status = ?`;
|
|
26
|
+
await Database.update(q2, [
|
|
27
|
+
BalanceItemStatus.Canceled,
|
|
28
|
+
BalanceItemStatus.Due,
|
|
29
|
+
]);
|
|
30
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Database, Migration } from '@simonbackx/simple-database';
|
|
2
|
+
|
|
3
|
+
export default new Migration(async () => {
|
|
4
|
+
process.stdout.write('\n');
|
|
5
|
+
|
|
6
|
+
if (STAMHOOFD.userMode === 'platform') {
|
|
7
|
+
console.log('Skipped set documents locked for userMode platform.');
|
|
8
|
+
return Promise.resolve();
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
console.log('Start locking document templates.');
|
|
12
|
+
await Database.statement(`update document_templates set isLocked = 1 where status = 'Published';`);
|
|
13
|
+
|
|
14
|
+
console.log('Start locking documents.');
|
|
15
|
+
await Database.statement(`update documents set isLocked = 1 where status = 'Published';`);
|
|
16
|
+
|
|
17
|
+
return Promise.resolve();
|
|
18
|
+
});
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { Database, Migration } from '@simonbackx/simple-database';
|
|
2
|
+
export default new Migration(async () => {
|
|
3
|
+
if (STAMHOOFD.environment === 'test') {
|
|
4
|
+
console.log('skipped in tests');
|
|
5
|
+
return;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
if (STAMHOOFD.userMode === 'platform') {
|
|
9
|
+
console.log('skipped for userMode platform');
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
console.log('start create v1_groups_migration_data table');
|
|
14
|
+
|
|
15
|
+
// create table to keep track of which combination of group id and cycle has been migrated to a new group after the migration from Stamhoofd v1 to v2
|
|
16
|
+
const groupsQuery = `CREATE TABLE \`v1_groups_migration_data\` (
|
|
17
|
+
\`newGroupId\` varchar(36) NOT NULL,
|
|
18
|
+
\`oldGroupId\` varchar(36) NOT NULL,
|
|
19
|
+
\`oldCycle\` int NOT NULL DEFAULT '0',
|
|
20
|
+
PRIMARY KEY (\`newGroupId\`),
|
|
21
|
+
UNIQUE KEY \`oldKey\` (\`oldGroupId\`,\`oldCycle\`) USING BTREE,
|
|
22
|
+
CONSTRAINT \`v1_groups_migration_data_ibfk_1\` FOREIGN KEY (\`newGroupId\`) REFERENCES \`groups\` (\`id\`) ON DELETE CASCADE ON UPDATE CASCADE
|
|
23
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;`;
|
|
24
|
+
|
|
25
|
+
await Database.statement(groupsQuery);
|
|
26
|
+
console.log('finished create v1_groups_migration_data table');
|
|
27
|
+
|
|
28
|
+
console.log('start create v1_waiting_list_migration_data table');
|
|
29
|
+
// create table to keep track of which combination of waiting list group id and cycle has been migrated to a new group after the migration from Stamhoofd v1 to v2
|
|
30
|
+
const waitingListsQuery = `CREATE TABLE \`v1_waiting_list_migration_data\` (
|
|
31
|
+
\`newGroupId\` varchar(36) NOT NULL,
|
|
32
|
+
\`oldGroupId\` varchar(36) NOT NULL,
|
|
33
|
+
\`oldCycle\` int NOT NULL DEFAULT '0',
|
|
34
|
+
PRIMARY KEY (\`newGroupId\`),
|
|
35
|
+
UNIQUE KEY \`oldKey\` (\`oldGroupId\`,\`oldCycle\`) USING BTREE,
|
|
36
|
+
CONSTRAINT \`v1_waiting_list_migration_data_ibfk_1\` FOREIGN KEY (\`newGroupId\`) REFERENCES \`groups\` (\`id\`) ON DELETE CASCADE ON UPDATE CASCADE
|
|
37
|
+
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;`;
|
|
38
|
+
await Database.statement(waitingListsQuery);
|
|
39
|
+
|
|
40
|
+
console.log('finished create v1_waiting_list_migration_data table');
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// CREATE TABLE `v1_groups_migration_data` (
|
|
44
|
+
// `newGroupId` varchar(36) NOT NULL,
|
|
45
|
+
// `oldGroupId` varchar(36) NOT NULL,
|
|
46
|
+
// `oldCycle` int NOT NULL DEFAULT '0',
|
|
47
|
+
// PRIMARY KEY (`newGroupId`),
|
|
48
|
+
// UNIQUE KEY `oldKey` (`oldGroupId`,`oldCycle`) USING BTREE,
|
|
49
|
+
// CONSTRAINT `groups_ibfk_1` FOREIGN KEY (`newGroupId`) REFERENCES `groups` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
|
|
50
|
+
// ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
|
|
@@ -5,7 +5,8 @@ import { Formatter, STMath } from '@stamhoofd/utility';
|
|
|
5
5
|
import { v4 as uuidv4 } from 'uuid';
|
|
6
6
|
|
|
7
7
|
import { EnumDecoder, MapDecoder } from '@simonbackx/simple-encoding';
|
|
8
|
-
import {
|
|
8
|
+
import { SimpleError } from '@simonbackx/simple-errors';
|
|
9
|
+
import { QueryableModel, SQL } from '@stamhoofd/sql';
|
|
9
10
|
import { Payment } from './Payment.js';
|
|
10
11
|
|
|
11
12
|
/**
|
|
@@ -212,6 +213,12 @@ export class BalanceItem extends QueryableModel {
|
|
|
212
213
|
@column({ type: 'datetime', nullable: true })
|
|
213
214
|
paidAt: Date | null = null;
|
|
214
215
|
|
|
216
|
+
/**
|
|
217
|
+
* Marking a balance item as 'failed' can have side effects. To prevent executing these side effects multiple times, we store it in here.
|
|
218
|
+
*/
|
|
219
|
+
@column({ type: 'datetime', nullable: true })
|
|
220
|
+
failedAt: Date | null = null;
|
|
221
|
+
|
|
215
222
|
@column({
|
|
216
223
|
type: 'datetime', beforeSave(old?: any) {
|
|
217
224
|
if (old !== undefined) {
|
|
@@ -550,7 +557,7 @@ export class BalanceItem extends QueryableModel {
|
|
|
550
557
|
await Database.update(query, params);
|
|
551
558
|
}
|
|
552
559
|
|
|
553
|
-
|
|
560
|
+
/**
|
|
554
561
|
* Update the outstanding balance of multiple members in one go (or all members)
|
|
555
562
|
*/
|
|
556
563
|
static async updateInvoiced(balanceItemIds: string[] | 'all') {
|
|
@@ -662,55 +669,38 @@ export class BalanceItem extends QueryableModel {
|
|
|
662
669
|
}
|
|
663
670
|
|
|
664
671
|
static async balanceItemsForUsersAndMembers(organizationId: string | null, userIds: string[], memberIds: string[]): Promise<BalanceItem[]> {
|
|
665
|
-
if (memberIds.length
|
|
672
|
+
if (memberIds.length === 0 && userIds.length === 0) {
|
|
666
673
|
return [];
|
|
667
674
|
}
|
|
668
675
|
|
|
669
|
-
const
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
if (memberIds.length) {
|
|
673
|
-
if (memberIds.length == 1) {
|
|
674
|
-
where.push(`memberId = ?`);
|
|
675
|
-
params.push(memberIds[0]);
|
|
676
|
-
}
|
|
677
|
-
else {
|
|
678
|
-
where.push(`memberId IN (?)`);
|
|
679
|
-
params.push(memberIds);
|
|
680
|
-
}
|
|
681
|
-
}
|
|
682
|
-
|
|
683
|
-
// Note here, we don't search for memberId IS NULL restriction in MySQL because it slows down the query too much (500ms)
|
|
684
|
-
// Better if we do it in code here
|
|
685
|
-
if (userIds.length) {
|
|
686
|
-
if (userIds.length == 1) {
|
|
687
|
-
where.push('userId = ?');
|
|
688
|
-
params.push(userIds[0]);
|
|
689
|
-
}
|
|
690
|
-
else {
|
|
691
|
-
where.push('userId IN (?)');
|
|
692
|
-
params.push(userIds);
|
|
693
|
-
}
|
|
694
|
-
}
|
|
695
|
-
|
|
696
|
-
const requiredWhere: string[] = [];
|
|
676
|
+
const base = BalanceItem.select()
|
|
677
|
+
.whereNot('status', BalanceItemStatus.Hidden);
|
|
697
678
|
|
|
698
679
|
if (organizationId) {
|
|
699
|
-
|
|
700
|
-
params.push(organizationId);
|
|
680
|
+
base.andWhere('organizationId', organizationId);
|
|
701
681
|
}
|
|
702
682
|
|
|
703
|
-
|
|
704
|
-
|
|
683
|
+
if (memberIds.length && userIds.length) {
|
|
684
|
+
// Don't include other members than the provided members
|
|
685
|
+
base.andWhere(
|
|
686
|
+
SQL.where('memberId', memberIds)
|
|
687
|
+
// Include null member
|
|
688
|
+
.or(
|
|
689
|
+
// Don't include balances of other members, even when userId matches
|
|
690
|
+
// this allows removing access for a member
|
|
691
|
+
SQL.where('userId', userIds)
|
|
692
|
+
.and('memberId', null),
|
|
693
|
+
),
|
|
694
|
+
);
|
|
695
|
+
} else if (memberIds.length) {
|
|
696
|
+
base.andWhere('memberId', memberIds);
|
|
697
|
+
} else if (userIds.length) {
|
|
698
|
+
base.andWhere('userId', userIds);
|
|
699
|
+
}
|
|
705
700
|
|
|
706
|
-
|
|
707
|
-
const balanceItems = BalanceItem.fromRows(rows, BalanceItem.table);
|
|
701
|
+
base.andWhere('priceOpen', '!=', 0);
|
|
708
702
|
|
|
709
|
-
|
|
710
|
-
if (memberIds.length) {
|
|
711
|
-
return balanceItems.filter(b => !b.memberId || memberIds.includes(b.memberId));
|
|
712
|
-
}
|
|
713
|
-
return balanceItems;
|
|
703
|
+
return await base.fetch();
|
|
714
704
|
}
|
|
715
705
|
|
|
716
706
|
static async balanceItemsForOrganization(payingOrganizationId: string, organizationId?: string): Promise<BalanceItem[]> {
|
|
@@ -719,9 +709,20 @@ export class BalanceItem extends QueryableModel {
|
|
|
719
709
|
.whereNot('status', BalanceItemStatus.Hidden);
|
|
720
710
|
|
|
721
711
|
if (organizationId) {
|
|
722
|
-
base.where('organizationId', organizationId)
|
|
712
|
+
base.where('organizationId', organizationId);
|
|
723
713
|
}
|
|
724
714
|
|
|
725
715
|
return await base.fetch();
|
|
726
716
|
}
|
|
717
|
+
|
|
718
|
+
override save(...args: Parameters<QueryableModel['save']>): Promise<boolean> {
|
|
719
|
+
if (this.unitPrice % 100 !== 0) {
|
|
720
|
+
throw new SimpleError({
|
|
721
|
+
statusCode: 500,
|
|
722
|
+
code: 'unrounded_balance_item',
|
|
723
|
+
message: 'Balance item unitPrices should be rounded up to 1 cent',
|
|
724
|
+
});
|
|
725
|
+
}
|
|
726
|
+
return super.save(...args);
|
|
727
|
+
}
|
|
727
728
|
}
|
|
@@ -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
|
}
|