@stamhoofd/models 2.4.0 → 2.6.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/src/migrations/1722269236-group-waitinglist-id.sql +4 -0
- package/dist/src/migrations/1722525785-balance-item-paying-organization-id.sql +2 -0
- package/dist/src/migrations/1722525787-depending-balance-item.sql +2 -0
- package/dist/src/migrations/1722845608-registration-stock-reservations.sql +2 -0
- package/dist/src/migrations/1722845609-group-stock-reservations.sql +2 -0
- package/dist/src/migrations/1722852362-stripe-intents-account-id.sql +2 -0
- package/dist/src/migrations/1722852363-stripe-checkout-sessions-account-id.sql +2 -0
- package/dist/src/models/BalanceItem.d.ts +8 -0
- package/dist/src/models/BalanceItem.d.ts.map +1 -1
- package/dist/src/models/BalanceItem.js +70 -44
- package/dist/src/models/BalanceItem.js.map +1 -1
- package/dist/src/models/DocumentTemplate.js +1 -1
- package/dist/src/models/DocumentTemplate.js.map +1 -1
- package/dist/src/models/Event.d.ts +7 -0
- package/dist/src/models/Event.d.ts.map +1 -1
- package/dist/src/models/Event.js +28 -0
- package/dist/src/models/Event.js.map +1 -1
- package/dist/src/models/Group.d.ts +13 -3
- package/dist/src/models/Group.d.ts.map +1 -1
- package/dist/src/models/Group.js +45 -6
- package/dist/src/models/Group.js.map +1 -1
- package/dist/src/models/Member.d.ts +1 -1
- package/dist/src/models/Member.d.ts.map +1 -1
- package/dist/src/models/Member.js +12 -9
- package/dist/src/models/Member.js.map +1 -1
- package/dist/src/models/Order.js +1 -1
- package/dist/src/models/Order.js.map +1 -1
- package/dist/src/models/Organization.d.ts +3 -11
- package/dist/src/models/Organization.d.ts.map +1 -1
- package/dist/src/models/Organization.js +4 -28
- package/dist/src/models/Organization.js.map +1 -1
- package/dist/src/models/Payment.d.ts +5 -7
- package/dist/src/models/Payment.d.ts.map +1 -1
- package/dist/src/models/Payment.js +8 -13
- package/dist/src/models/Payment.js.map +1 -1
- package/dist/src/models/Registration.d.ts +17 -2
- package/dist/src/models/Registration.d.ts.map +1 -1
- package/dist/src/models/Registration.js +59 -7
- package/dist/src/models/Registration.js.map +1 -1
- package/dist/src/models/StripeCheckoutSession.d.ts +4 -0
- package/dist/src/models/StripeCheckoutSession.d.ts.map +1 -1
- package/dist/src/models/StripeCheckoutSession.js +7 -0
- package/dist/src/models/StripeCheckoutSession.js.map +1 -1
- package/dist/src/models/StripePaymentIntent.d.ts +4 -0
- package/dist/src/models/StripePaymentIntent.d.ts.map +1 -1
- package/dist/src/models/StripePaymentIntent.js +7 -0
- package/dist/src/models/StripePaymentIntent.js.map +1 -1
- package/package.json +2 -2
- package/src/migrations/1722269236-group-waitinglist-id.sql +4 -0
- 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/1722845608-registration-stock-reservations.sql +2 -0
- package/src/migrations/1722845609-group-stock-reservations.sql +2 -0
- package/src/migrations/1722852362-stripe-intents-account-id.sql +2 -0
- package/src/migrations/1722852363-stripe-checkout-sessions-account-id.sql +2 -0
- package/src/models/BalanceItem.ts +78 -47
- package/src/models/DocumentTemplate.ts +1 -1
- package/src/models/Event.ts +31 -0
- package/src/models/Group.ts +53 -14
- package/src/models/Member.ts +13 -10
- package/src/models/Order.ts +2 -2
- package/src/models/Organization.ts +5 -34
- package/src/models/Payment.ts +10 -16
- package/src/models/Registration.ts +71 -11
- package/src/models/StripeAccount.ts +1 -1
- package/src/models/StripeCheckoutSession.ts +6 -0
- package/src/models/StripePaymentIntent.ts +6 -0
- package/dist/src/assets/assets/Metropolis-Black.woff2 +0 -0
- package/dist/src/assets/assets/Metropolis-BlackItalic.woff2 +0 -0
- package/dist/src/assets/assets/Metropolis-Bold.woff2 +0 -0
- package/dist/src/assets/assets/Metropolis-BoldItalic.woff2 +0 -0
- package/dist/src/assets/assets/Metropolis-ExtraBold.woff2 +0 -0
- package/dist/src/assets/assets/Metropolis-ExtraBoldItalic.woff2 +0 -0
- package/dist/src/assets/assets/Metropolis-ExtraLight.woff2 +0 -0
- package/dist/src/assets/assets/Metropolis-ExtraLightItalic.woff2 +0 -0
- package/dist/src/assets/assets/Metropolis-Light.woff2 +0 -0
- package/dist/src/assets/assets/Metropolis-LightItalic.woff2 +0 -0
- package/dist/src/assets/assets/Metropolis-Medium.woff2 +0 -0
- package/dist/src/assets/assets/Metropolis-MediumItalic.woff2 +0 -0
- package/dist/src/assets/assets/Metropolis-Regular.woff2 +0 -0
- package/dist/src/assets/assets/Metropolis-RegularItalic.woff2 +0 -0
- package/dist/src/assets/assets/Metropolis-SemiBold.woff2 +0 -0
- package/dist/src/assets/assets/Metropolis-SemiBoldItalic.woff2 +0 -0
- package/dist/src/assets/assets/Metropolis-Thin.woff2 +0 -0
- package/dist/src/assets/assets/Metropolis-ThinItalic.woff2 +0 -0
- package/dist/src/assets/assets/logo.png +0 -0
package/src/models/Payment.ts
CHANGED
|
@@ -110,39 +110,37 @@ export class Payment extends Model {
|
|
|
110
110
|
}
|
|
111
111
|
|
|
112
112
|
const {balanceItemPayments, balanceItems} = await Payment.loadBalanceItems(payments)
|
|
113
|
-
const {registrations, orders,
|
|
113
|
+
const {registrations, orders, groups} = await Payment.loadBalanceItemRelations(balanceItems);
|
|
114
114
|
|
|
115
|
-
return this.getGeneralStructureFromRelations({
|
|
115
|
+
return await this.getGeneralStructureFromRelations({
|
|
116
116
|
payments,
|
|
117
117
|
registrations,
|
|
118
118
|
orders,
|
|
119
|
-
members,
|
|
120
119
|
balanceItemPayments,
|
|
121
120
|
balanceItems,
|
|
122
121
|
groups
|
|
123
122
|
}, includeSettlements)
|
|
124
123
|
}
|
|
125
124
|
|
|
126
|
-
static getGeneralStructureFromRelations({payments, registrations, orders,
|
|
125
|
+
static async getGeneralStructureFromRelations({payments, registrations, orders, balanceItemPayments, balanceItems, groups}: {
|
|
127
126
|
payments: Payment[];
|
|
128
|
-
registrations: import("./
|
|
127
|
+
registrations: import("./Member").RegistrationWithMember[];
|
|
129
128
|
orders: import("./Order").Order[];
|
|
130
|
-
members: import("./Member").Member[];
|
|
131
129
|
balanceItemPayments: import("./BalanceItemPayment").BalanceItemPayment[];
|
|
132
130
|
balanceItems: import("./BalanceItem").BalanceItem[];
|
|
133
131
|
groups: import("./Group").Group[];
|
|
134
|
-
}, includeSettlements = false): PaymentGeneral[] {
|
|
132
|
+
}, includeSettlements = false): Promise<PaymentGeneral[]> {
|
|
135
133
|
if (payments.length === 0) {
|
|
136
134
|
return []
|
|
137
135
|
}
|
|
136
|
+
const {Member} = (await import("./Member"));
|
|
138
137
|
|
|
139
138
|
return payments.map(payment => {
|
|
140
139
|
return PaymentGeneral.create({
|
|
141
140
|
...payment,
|
|
142
141
|
balanceItemPayments: balanceItemPayments.filter(item => item.paymentId === payment.id).map((item) => {
|
|
143
142
|
const balanceItem = balanceItems.find(b => b.id === item.balanceItemId)
|
|
144
|
-
const registration = balanceItem?.registrationId
|
|
145
|
-
const member = balanceItem?.memberId ? members.find(r => r.id === balanceItem.memberId) : undefined
|
|
143
|
+
const registration = balanceItem?.registrationId ? registrations.find(r => r.id === balanceItem.registrationId) : null
|
|
146
144
|
const order = balanceItem?.orderId && orders.find(r => r.id === balanceItem.orderId)
|
|
147
145
|
const group = registration ? groups.find(g => g.id === registration.groupId) : null
|
|
148
146
|
|
|
@@ -154,8 +152,7 @@ export class Payment extends Model {
|
|
|
154
152
|
...item,
|
|
155
153
|
balanceItem: BalanceItemDetailed.create({
|
|
156
154
|
...balanceItem,
|
|
157
|
-
registration: registration ? registration.setRelation(Registration.group, group!)
|
|
158
|
-
member: member ? MemberStruct.create(member) : null,
|
|
155
|
+
registration: registration ? Member.getRegistrationWithMemberStructure(registration.setRelation(Registration.group, group!)) : null,
|
|
159
156
|
order: order ? OrderStruct.create({...order, payment: null}) : null
|
|
160
157
|
})
|
|
161
158
|
})
|
|
@@ -195,22 +192,19 @@ export class Payment extends Model {
|
|
|
195
192
|
}
|
|
196
193
|
|
|
197
194
|
static async loadBalanceItemRelations(balanceItems: import("./BalanceItem").BalanceItem[]) {
|
|
198
|
-
const {Registration} = await import("./Registration");
|
|
199
195
|
const {Order} = await import("./Order");
|
|
200
196
|
const {Member} = await import("./Member");
|
|
201
197
|
|
|
202
198
|
// Load members and orders
|
|
203
199
|
const registrationIds = Formatter.uniqueArray(balanceItems.flatMap(b => b.registrationId ? [b.registrationId] : []))
|
|
204
200
|
const orderIds = Formatter.uniqueArray(balanceItems.flatMap(b => b.orderId ? [b.orderId] : []))
|
|
205
|
-
const memberIds = Formatter.uniqueArray(balanceItems.flatMap(b => b.memberId ? [b.memberId] : []))
|
|
206
201
|
|
|
207
|
-
const registrations = await
|
|
202
|
+
const registrations = await Member.getRegistrationWithMembersByIDs(registrationIds)
|
|
208
203
|
const orders = await Order.getByIDs(...orderIds)
|
|
209
|
-
const members = await Member.getByIDs(...memberIds)
|
|
210
204
|
|
|
211
205
|
const groupIds = Formatter.uniqueArray(registrations.map(r => r.groupId))
|
|
212
206
|
const groups = await (await import("./Group")).Group.getByIDs(...groupIds)
|
|
213
207
|
|
|
214
|
-
return {registrations, orders,
|
|
208
|
+
return {registrations, orders, groups}
|
|
215
209
|
}
|
|
216
210
|
}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { column, Database, ManyToOneRelation, Model } from '@simonbackx/simple-database';
|
|
2
2
|
import { Email } from '@stamhoofd/email';
|
|
3
|
-
import { EmailTemplateType, PaymentMethod, PaymentMethodHelper, Recipient, Registration as RegistrationStructure, Replacement } from '@stamhoofd/structures';
|
|
3
|
+
import { EmailTemplateType, PaymentMethod, PaymentMethodHelper, Recipient, Registration as RegistrationStructure, Replacement, StockReservation } from '@stamhoofd/structures';
|
|
4
4
|
import { Formatter } from '@stamhoofd/utility';
|
|
5
5
|
import { v4 as uuidv4 } from "uuid";
|
|
6
6
|
|
|
7
7
|
import { getEmailBuilder } from '../helpers/EmailBuilder';
|
|
8
|
-
import { Document, EmailTemplate, Organization, User } from './';
|
|
8
|
+
import { Document, EmailTemplate, Group, Organization, User } from './';
|
|
9
|
+
import { ArrayDecoder } from '@simonbackx/simple-encoding';
|
|
10
|
+
import { QueueHandler } from '@stamhoofd/queues';
|
|
9
11
|
|
|
10
12
|
export class Registration extends Model {
|
|
11
13
|
static table = "registrations"
|
|
@@ -69,6 +71,9 @@ export class Registration extends Model {
|
|
|
69
71
|
@column({ type: "datetime", nullable: true })
|
|
70
72
|
reservedUntil: Date | null = null
|
|
71
73
|
|
|
74
|
+
/**
|
|
75
|
+
* @deprecated - replaced by group type
|
|
76
|
+
*/
|
|
72
77
|
@column({ type: "boolean" })
|
|
73
78
|
waitingList = false
|
|
74
79
|
|
|
@@ -88,6 +93,12 @@ export class Registration extends Model {
|
|
|
88
93
|
@column({ type: "integer" })
|
|
89
94
|
pricePaid = 0
|
|
90
95
|
|
|
96
|
+
/**
|
|
97
|
+
* Set to null if no reservations are made, to help faster querying
|
|
98
|
+
*/
|
|
99
|
+
@column({ type: "json", decoder: new ArrayDecoder(StockReservation), nullable: true })
|
|
100
|
+
stockReservations: StockReservation[] = []
|
|
101
|
+
|
|
91
102
|
static group: ManyToOneRelation<"group", import('./Group').Group>
|
|
92
103
|
|
|
93
104
|
getStructure(this: Registration & {group: import('./Group').Group}) {
|
|
@@ -101,7 +112,7 @@ export class Registration extends Model {
|
|
|
101
112
|
/**
|
|
102
113
|
* Update the outstanding balance of multiple members in one go (or all members)
|
|
103
114
|
*/
|
|
104
|
-
static async updateOutstandingBalance(registrationIds: string[] | 'all', organizationId
|
|
115
|
+
static async updateOutstandingBalance(registrationIds: string[] | 'all', organizationId?: string) {
|
|
105
116
|
if (registrationIds !== 'all' && registrationIds.length == 0) {
|
|
106
117
|
return
|
|
107
118
|
}
|
|
@@ -136,7 +147,7 @@ export class Registration extends Model {
|
|
|
136
147
|
|
|
137
148
|
await Database.update(query, params)
|
|
138
149
|
|
|
139
|
-
if (registrationIds !== 'all') {
|
|
150
|
+
if (registrationIds !== 'all' && organizationId) {
|
|
140
151
|
await Document.updateForRegistrations(registrationIds, organizationId)
|
|
141
152
|
}
|
|
142
153
|
}
|
|
@@ -149,7 +160,7 @@ export class Registration extends Model {
|
|
|
149
160
|
const query = `
|
|
150
161
|
SELECT COUNT(DISTINCT \`${Registration.table}\`.memberId) as c FROM \`${Registration.table}\`
|
|
151
162
|
JOIN \`groups\` ON \`groups\`.id = \`${Registration.table}\`.groupId
|
|
152
|
-
WHERE \`groups\`.organizationId = ? AND \`${Registration.table}\`.cycle = \`groups\`.cycle AND \`groups\`.deletedAt is null AND
|
|
163
|
+
WHERE \`groups\`.organizationId = ? AND \`${Registration.table}\`.cycle = \`groups\`.cycle AND \`groups\`.deletedAt is null AND \`${Registration.table}\`.registeredAt is not null AND \`${Registration.table}\`.deactivatedAt is null`
|
|
153
164
|
|
|
154
165
|
const [results] = await Database.select(query, [organizationId])
|
|
155
166
|
const count = results[0]['']['c'];
|
|
@@ -163,19 +174,17 @@ export class Registration extends Model {
|
|
|
163
174
|
}
|
|
164
175
|
|
|
165
176
|
async markValid(this: Registration) {
|
|
166
|
-
if (this.registeredAt !== null) {
|
|
177
|
+
if (this.registeredAt !== null && this.deactivatedAt === null) {
|
|
167
178
|
await this.save();
|
|
168
179
|
return false;
|
|
169
180
|
}
|
|
170
181
|
|
|
171
|
-
if (this.waitingList && this.canRegister) {
|
|
172
|
-
this.waitingList = false
|
|
173
|
-
}
|
|
174
|
-
|
|
175
182
|
this.reservedUntil = null
|
|
176
|
-
this.registeredAt = new Date()
|
|
183
|
+
this.registeredAt = this.registeredAt ?? new Date()
|
|
184
|
+
this.deactivatedAt = null
|
|
177
185
|
this.canRegister = false
|
|
178
186
|
await this.save();
|
|
187
|
+
this.scheduleStockUpdate()
|
|
179
188
|
|
|
180
189
|
await this.sendEmailTemplate({
|
|
181
190
|
type: EmailTemplateType.RegistrationConfirmation
|
|
@@ -408,4 +417,55 @@ export class Registration extends Model {
|
|
|
408
417
|
|
|
409
418
|
Email.schedule(builder)
|
|
410
419
|
}
|
|
420
|
+
|
|
421
|
+
shouldIncludeStock() {
|
|
422
|
+
return (this.registeredAt !== null && this.deactivatedAt === null) || this.canRegister || (this.reservedUntil && this.reservedUntil > new Date())
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
|
|
426
|
+
|
|
427
|
+
/**
|
|
428
|
+
* Adds or removes the order to the stock of the webshop (if it wasn't already included). If amounts were changed, only those
|
|
429
|
+
* changes will get added
|
|
430
|
+
* Should always happen in the webshop-stock queue to prevent multiple webshop writes at the same time
|
|
431
|
+
* + in combination with validation and reading the webshop
|
|
432
|
+
*/
|
|
433
|
+
scheduleStockUpdate() {
|
|
434
|
+
const id = this.id;
|
|
435
|
+
|
|
436
|
+
QueueHandler.cancel('registration-stock-update-'+id);
|
|
437
|
+
QueueHandler.schedule('registration-stock-update-'+id, async function(this: undefined) {
|
|
438
|
+
const updated = await Registration.getByID(id);
|
|
439
|
+
|
|
440
|
+
if (!updated) {
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
// Start with clearing all the stock reservations we've already made
|
|
445
|
+
if (updated.stockReservations) {
|
|
446
|
+
const groupIds = Formatter.uniqueArray(updated.stockReservations.flatMap(r => r.objectType === 'Group' ? [r.objectId] : []));
|
|
447
|
+
for (const groupId of groupIds) {
|
|
448
|
+
const stocks = StockReservation.filter('Group', groupId, updated.stockReservations);
|
|
449
|
+
|
|
450
|
+
// Technically we don't need to await this, but okay...
|
|
451
|
+
await Group.freeStockReservations(groupId, stocks);
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
if (updated.shouldIncludeStock()) {
|
|
456
|
+
const myStockReservations: StockReservation[] = [];
|
|
457
|
+
|
|
458
|
+
// todo: build
|
|
459
|
+
|
|
460
|
+
updated.stockReservations = myStockReservations;
|
|
461
|
+
await updated.save();
|
|
462
|
+
} else {
|
|
463
|
+
if (updated.stockReservations.length) {
|
|
464
|
+
updated.stockReservations = [];
|
|
465
|
+
await updated.save();
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
}).catch(console.error)
|
|
470
|
+
}
|
|
411
471
|
}
|
|
@@ -19,4 +19,10 @@ export class StripeCheckoutSession extends Model {
|
|
|
19
19
|
|
|
20
20
|
@column({ type: "string", nullable: true })
|
|
21
21
|
organizationId: string | null = null;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* For direct charges, this should be set
|
|
25
|
+
*/
|
|
26
|
+
@column({ type: "string", nullable: true })
|
|
27
|
+
accountId: string|null = null
|
|
22
28
|
}
|
|
@@ -19,4 +19,10 @@ export class StripePaymentIntent extends Model {
|
|
|
19
19
|
|
|
20
20
|
@column({ type: "string", nullable: true })
|
|
21
21
|
organizationId: string | null = null;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* For direct charges, this should be set
|
|
25
|
+
*/
|
|
26
|
+
@column({ type: "string", nullable: true })
|
|
27
|
+
accountId: string|null = null
|
|
22
28
|
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|