@stamhoofd/backend 2.120.6 → 2.121.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.
Files changed (61) hide show
  1. package/package.json +12 -12
  2. package/src/audit-logs/RegistrationInvitationLogger.ts +46 -0
  3. package/src/audit-logs/init.ts +2 -0
  4. package/src/crons/index.ts +2 -0
  5. package/src/crons/invoices.ts +166 -0
  6. package/src/crons/mollie-chargebacks.ts +87 -0
  7. package/src/crons.ts +47 -10
  8. package/src/email-recipient-loaders/payments.ts +84 -41
  9. package/src/endpoints/global/groups/GetGroupsCountEndpoint.ts +51 -0
  10. package/src/endpoints/global/platform/PatchPlatformEnpoint.ts +22 -3
  11. package/src/endpoints/global/registration/RegisterMembersEndpoint.ts +4 -0
  12. package/src/endpoints/global/registration-invitations/GetRegistrationInvitationsCountEndpoint.ts +45 -0
  13. package/src/endpoints/global/registration-invitations/GetRegistrationInvitationsEndpoint.test.ts +495 -0
  14. package/src/endpoints/global/registration-invitations/GetRegistrationInvitationsEndpoint.ts +216 -0
  15. package/src/endpoints/global/registration-invitations/PatchRegistrationInvitationsEndpoint.test.ts +405 -0
  16. package/src/endpoints/global/registration-invitations/PatchRegistrationInvitationsEndpoint.ts +168 -0
  17. package/src/endpoints/organization/dashboard/balance-items/PatchBalanceItemsEndpoint.ts +15 -0
  18. package/src/endpoints/{global → organization/dashboard}/billing/DeactivatePackageEndpoint.ts +3 -4
  19. package/src/endpoints/organization/dashboard/billing/DeleteOrganizationMandateEndpoint.ts +62 -0
  20. package/src/endpoints/organization/dashboard/billing/GetOrganizationDetailedPayableBalanceCollectionEndpoint.ts +56 -0
  21. package/src/endpoints/organization/dashboard/billing/GetOrganizationDetailedPayableBalanceEndpoint.ts +42 -19
  22. package/src/endpoints/organization/dashboard/billing/GetOrganizationMandatesEndpoint.ts +64 -0
  23. package/src/endpoints/organization/dashboard/billing/GetPackagesEndpoint.ts +11 -3
  24. package/src/endpoints/organization/dashboard/billing/OrganizationCheckoutEndpoint.ts +308 -0
  25. package/src/endpoints/organization/dashboard/billing/PatchOrganizationMandatesEndpoint.ts +94 -0
  26. package/src/endpoints/organization/dashboard/invoices/GetInvoicesEndpoint.ts +7 -0
  27. package/src/endpoints/organization/dashboard/mollie/CheckMollieEndpoint.ts +5 -4
  28. package/src/endpoints/organization/dashboard/mollie/ConnectMollieEndpoint.ts +7 -2
  29. package/src/endpoints/organization/dashboard/organization/PatchOrganizationEndpoint.ts +17 -8
  30. package/src/endpoints/organization/dashboard/payments/PatchPaymentsEndpoint.ts +3 -3
  31. package/src/endpoints/organization/dashboard/receivable-balances/ChargeReceivableBalancesEndpoint.ts +127 -0
  32. package/src/endpoints/organization/dashboard/registration-periods/PatchOrganizationRegistrationPeriodsEndpoint.ts +13 -4
  33. package/src/endpoints/organization/dashboard/webshops/PatchWebshopEndpoint.ts +7 -1
  34. package/src/endpoints/organization/dashboard/webshops/PatchWebshopOrdersEndpoint.ts +1 -1
  35. package/src/endpoints/organization/shared/ExchangePaymentEndpoint.ts +13 -11
  36. package/src/endpoints/organization/webshops/PlaceOrderEndpoint.ts +14 -19
  37. package/src/helpers/AdminPermissionChecker.ts +11 -3
  38. package/src/helpers/AuthenticatedStructures.ts +94 -6
  39. package/src/helpers/FinancialSupportHelper.ts +21 -0
  40. package/src/helpers/RecordAnswerHelper.test.ts +746 -0
  41. package/src/helpers/RecordAnswerHelper.ts +116 -0
  42. package/src/helpers/StripeHelper.ts +2 -3
  43. package/src/helpers/ViesHelper.ts +7 -3
  44. package/src/seeds/1750090030-records-configuration.ts +68 -3
  45. package/src/seeds/1752848561-groups-registration-periods.ts +26 -2
  46. package/src/seeds/1779121239-default-invoice-email-template.sql +3 -0
  47. package/src/services/BalanceItemService.ts +12 -16
  48. package/src/services/InvoiceService.ts +372 -72
  49. package/src/services/MollieService.ts +537 -0
  50. package/src/services/PaymentMandateService.ts +214 -0
  51. package/src/services/PaymentService.ts +578 -222
  52. package/src/services/PlatformMembershipService.ts +1 -1
  53. package/src/services/RegistrationService.ts +66 -5
  54. package/src/services/STPackageService.ts +0 -7
  55. package/src/services/data/invoice.hbs.html +686 -0
  56. package/src/sql-filters/groups.ts +11 -1
  57. package/src/sql-filters/payments.ts +5 -0
  58. package/src/sql-filters/registration-invitations.ts +90 -0
  59. package/src/sql-sorters/registration-invitations.ts +36 -0
  60. package/vitest.config.js +1 -0
  61. package/src/endpoints/global/billing/ActivatePackagesEndpoint.ts +0 -216
@@ -0,0 +1,537 @@
1
+ import type { Mandate , Payment as MolliePaymentType} from '@mollie/api-client';
2
+ import { ApiMode, createMollieClient, MandateMethod, MandateStatus, PaymentMethod as molliePaymentMethod, PaymentStatus as molliePaymentStatus, OnboardingStatus, ProfileStatus, SequenceType } from '@mollie/api-client';
3
+ import { SimpleError } from '@simonbackx/simple-errors';
4
+ import type { Payment, User } from '@stamhoofd/models';
5
+ import type { Organization } from '@stamhoofd/models';
6
+ import { MolliePayment, MollieToken, Platform } from '@stamhoofd/models';
7
+ import type { PaymentCustomer } from '@stamhoofd/structures';
8
+ import { MollieOnboarding, MollieProfile, MollieProfileMode, MollieProfileStatus, MollieStatus, PaymentMethod, PaymentMethodHelper, PaymentProvider, PaymentStatus } from '@stamhoofd/structures';
9
+ import { PaymentMandate, PaymentMandateDetails, PaymentMandateStatus, PaymentMandateType } from '@stamhoofd/structures/PaymentMandate.js';
10
+ import { Formatter } from '@stamhoofd/utility';
11
+ import { DateTime } from 'luxon';
12
+ import { Context } from '../helpers/Context.js';
13
+
14
+ export class MollieService {
15
+ client: ReturnType<typeof createMollieClient>;
16
+ sellingOrganization: Organization;
17
+ createdAt: Date
18
+
19
+ private constructor({sellingOrganization, accessToken}: {sellingOrganization: Organization, accessToken: string}) {
20
+ this.sellingOrganization = sellingOrganization
21
+ this.client = createMollieClient({ accessToken });
22
+ this.createdAt = new Date()
23
+ }
24
+
25
+ static #cachedServices: Map<string, MollieService> = new Map()
26
+
27
+ /**
28
+ * Cached instances can be used for maximum 30 seconds
29
+ */
30
+ isOutdated() {
31
+ return this.createdAt.getTime() < Date.now() - 30_000
32
+ }
33
+
34
+ static async create({sellingOrganization}: {sellingOrganization: Organization}) {
35
+ const cached = this.#cachedServices.get(sellingOrganization.id);
36
+ if (cached && !cached.isOutdated()) {
37
+ return cached;
38
+ }
39
+ const token = await MollieToken.getTokenFor(sellingOrganization.id);
40
+ if (!token) {
41
+ if (cached) {
42
+ this.#cachedServices.delete(sellingOrganization.id)
43
+ }
44
+ return null;
45
+ }
46
+ const service = new MollieService({ sellingOrganization, accessToken: await token.getAccessToken() });
47
+ this.#cachedServices.set(sellingOrganization.id, service);
48
+ return service;
49
+ }
50
+
51
+ /**
52
+ * Set initial onboarding values + enable bancontact
53
+ */
54
+ async setupOnboarding() {
55
+ // Submit onboarding data
56
+ this.sellingOrganization.privateMeta.mollieOnboarding = await this.getOnboardingStatus();
57
+
58
+ if (this.sellingOrganization.privateMeta.mollieOnboarding && this.sellingOrganization.privateMeta.mollieOnboarding.status === MollieStatus.NeedsData) {
59
+ try {
60
+ await this.client.onboarding.submit({
61
+ organization: {
62
+ name: this.sellingOrganization.name,
63
+ address: {
64
+ streetAndNumber: this.sellingOrganization.address.street + ' ' + this.sellingOrganization.address.number,
65
+ postalCode: this.sellingOrganization.address.postalCode,
66
+ city: this.sellingOrganization.address.city,
67
+ country: this.sellingOrganization.address.country,
68
+ },
69
+
70
+ vatRegulation: 'shifted',
71
+ },
72
+ profile: {
73
+ name: this.sellingOrganization.name + ' via Stamhoofd',
74
+ description: $t(`%x1`),
75
+ categoryCode: 8398,
76
+ },
77
+ })
78
+ } catch (e) {
79
+ console.error('Failed to submit onboarding data', e);
80
+ }
81
+ }
82
+ }
83
+
84
+ #verifiedCustomerIds: Set<string> = new Set()
85
+
86
+ /**
87
+ * Gets the customer id for a given payingOrganization or user.
88
+ * If no customer exists, it will create a new mollie customer if customer (payment customer) is set as parameter
89
+ */
90
+ async getCustomerId({ payingOrganization, user, customer }: {
91
+ payingOrganization: Organization | null,
92
+ user: User | null,
93
+
94
+ /**
95
+ * Required to be able to create a new customer
96
+ */
97
+ customer?: PaymentCustomer
98
+ }): Promise<string | null> {
99
+ if (!payingOrganization) {
100
+ // Not yet supported for users
101
+ return null;
102
+ }
103
+
104
+ if (this.sellingOrganization.id !== (await Platform.getShared()).membershipOrganizationId) {
105
+ // Not yet supported
106
+ return null;
107
+ }
108
+
109
+
110
+ if (payingOrganization.serverMeta.mollieCustomerId) {
111
+ const customerId = payingOrganization.serverMeta.mollieCustomerId
112
+ if (this.#verifiedCustomerIds.has(customerId)) {
113
+ return customerId;
114
+ }
115
+
116
+ // check still valid
117
+ try {
118
+ const c = await this.client.customers.get(customerId, {testmode: this.testMode});
119
+
120
+ if ((c.mode === ApiMode.test) === this.testMode) {
121
+ this.#verifiedCustomerIds.add(customerId);
122
+ return customerId;
123
+ }
124
+ } catch (e) {
125
+ console.error('Error getting customer', e)
126
+ // Customer is not valid anymore, we need to create a new one
127
+ }
128
+ }
129
+
130
+ if (!customer) {
131
+ // No existing customer exists
132
+ // won't create a new one if customer is not set
133
+ return null;
134
+ }
135
+
136
+ const mollieCustomer = await this.client.customers.create({
137
+ name: payingOrganization.name,
138
+ email: customer.email ?? undefined,
139
+ metadata: {
140
+ organizationId: payingOrganization.id,
141
+ userId: user?.id,
142
+ },
143
+ testmode: this.testMode
144
+ })
145
+
146
+ const customerId = mollieCustomer.id
147
+ this.#verifiedCustomerIds.add(customerId);
148
+
149
+ payingOrganization.serverMeta.mollieCustomerId = mollieCustomer.id
150
+ console.log('Saving new mollie customer', mollieCustomer, 'for organization', payingOrganization.id)
151
+ await payingOrganization.save()
152
+
153
+ return customerId
154
+ }
155
+
156
+ #cachedMandates: Map<string, PaymentMandate[]> = new Map()
157
+
158
+ async getMandates({ payingOrganization, user }: {
159
+ payingOrganization: Organization | null,
160
+ user: User | null,
161
+ }): Promise<PaymentMandate[]> {
162
+ const customerId = await this.getCustomerId({payingOrganization, user});
163
+ if (!customerId) {
164
+ return [];
165
+ }
166
+
167
+ const cached = this.#cachedMandates.get(customerId);
168
+ if (cached) {
169
+ //return cached;
170
+ }
171
+
172
+ // Poll mollie status
173
+ // Mollie payment is required
174
+ const mandates: PaymentMandate[] = []
175
+
176
+ try {
177
+ const m = await this.client.customerMandates.page({
178
+ customerId,
179
+ limit: 250,
180
+ testmode: this.testMode
181
+ })
182
+
183
+ for (const mandate of m) {
184
+ const paymentMandate = MollieService.mollieManateToStamhoofd({mandate, payingOrganization, user});
185
+ if (paymentMandate) {
186
+ mandates.push(paymentMandate)
187
+ }
188
+ }
189
+ } catch (e) {
190
+ console.error(e)
191
+ }
192
+
193
+ // todo: remove duplicate mandates?
194
+ return mandates;
195
+ }
196
+
197
+ async deleteMandate({ mandateId, payingOrganization, user }: {
198
+ mandateId: string,
199
+ payingOrganization: Organization | null,
200
+ user: User | null,
201
+ }) {
202
+ const customerId = await this.getCustomerId({payingOrganization, user});
203
+ if (!customerId) {
204
+ return
205
+ }
206
+
207
+ await this.client.customerMandates.revoke(
208
+ mandateId,
209
+ {
210
+ customerId,
211
+ testmode: this.testMode
212
+ }
213
+ )
214
+ }
215
+
216
+ private static mollieManateToStamhoofd({ mandate, payingOrganization, user }: {
217
+ mandate: Mandate,
218
+ payingOrganization: Organization | null,
219
+ user: User | null,
220
+ }): PaymentMandate | null {
221
+ let type: PaymentMandateType;
222
+ switch (mandate.method) {
223
+ case MandateMethod.creditcard: {
224
+ type = PaymentMandateType.CreditCard
225
+ break;
226
+ }
227
+
228
+ case MandateMethod.directdebit: {
229
+ type = PaymentMandateType.DirectDebit
230
+ break;
231
+ }
232
+
233
+ default: {
234
+ // Not supported
235
+ return null;
236
+ }
237
+ }
238
+ const details = mandate.details;
239
+ return PaymentMandate.create({
240
+ id: mandate.id,
241
+ status: MollieService.mollieMandateStatusToStamhoofd(mandate),
242
+
243
+ // Todo: support for user default mandates
244
+ isDefault: mandate.id === payingOrganization?.serverMeta.mollieMandateId,
245
+
246
+ createdAt: new Date(mandate.createdAt),
247
+
248
+ provider: PaymentProvider.Mollie,
249
+
250
+ type,
251
+
252
+ details: PaymentMandateDetails.create({
253
+ name: ('consumerName' in details ? details.consumerName : details.cardHolder) ?? undefined,
254
+ cardNumber: 'cardNumber' in details ? details.cardNumber : null,
255
+ iban: 'consumerAccount' in details ? details.consumerAccount : null,
256
+ bic: ('consumerBic' in details ? details.consumerBic : undefined),
257
+ expiryDate: ('cardExpiryDate' in details ? DateTime.fromISO(details.cardExpiryDate, {zone: Formatter.timezone}).toJSDate() : null), // todo: parse date correctly in Brussels timezone!
258
+ brand: ('cardLabel' in details ? details.cardLabel : null),
259
+ })
260
+ })
261
+ }
262
+
263
+ private static mollieMandateStatusToStamhoofd(mandate: Mandate): PaymentMandateStatus {
264
+ switch (mandate.status) {
265
+ case MandateStatus.valid: {
266
+ return PaymentMandateStatus.Valid
267
+ }
268
+ case MandateStatus.invalid: {
269
+ return PaymentMandateStatus.Invalid
270
+ }
271
+ case MandateStatus.pending: {
272
+ return PaymentMandateStatus.Pending
273
+ }
274
+ }
275
+ }
276
+
277
+ private static paymentMethodToMollie(method: PaymentMethod) {
278
+ switch (method) {
279
+ case PaymentMethod.Bancontact:
280
+ return molliePaymentMethod.bancontact
281
+ case PaymentMethod.CreditCard:
282
+ return molliePaymentMethod.creditcard
283
+ case PaymentMethod.DirectDebit:
284
+ return molliePaymentMethod.directdebit
285
+ case PaymentMethod.iDEAL:
286
+ return molliePaymentMethod.ideal
287
+ case PaymentMethod.Transfer:
288
+ return molliePaymentMethod.banktransfer
289
+ }
290
+
291
+ return null;
292
+ }
293
+
294
+ async getProfiles(): Promise<MollieProfile[]> {
295
+ try {
296
+ const response = await this.client.profiles.page({
297
+ limit: 250
298
+ })
299
+ return response.map(p => MollieProfile.create({
300
+ ...p,
301
+ mode: p.mode === ApiMode.live ? MollieProfileMode.Live : MollieProfileMode.Test,
302
+ status: p.status === ProfileStatus.unverified ? MollieProfileStatus.Unverified : (p.status === ProfileStatus.blocked ? MollieProfileStatus.Blocked : MollieProfileStatus.Verified)
303
+ }));
304
+ }
305
+ catch (e) {
306
+ console.error('Failed to parse mollie profiles', e);
307
+ return [];
308
+ }
309
+ }
310
+
311
+ async getOnboardingStatus() {
312
+ try {
313
+ const response = await this.client.onboarding.get();
314
+ return MollieOnboarding.create({
315
+ canReceivePayments: !!response.canReceivePayments,
316
+ canReceiveSettlements: !!response.canReceiveSettlements,
317
+ status: response.status === OnboardingStatus.needsData ? MollieStatus.NeedsData : (response.status === OnboardingStatus.inReview ? MollieStatus.InReview : (MollieStatus.Completed)),
318
+ });
319
+ }
320
+ catch (e) {
321
+ console.error('Error when requesting Mollie onboarding status:');
322
+ console.error(e);
323
+ return null;
324
+ }
325
+ }
326
+
327
+ async getProfileId(website?: string): Promise<string | undefined> {
328
+ if (this.sellingOrganization.privateMeta.mollieProfile?.id) {
329
+ return this.sellingOrganization.privateMeta.mollieProfile.id
330
+ }
331
+
332
+ try {
333
+ const profiles = await this.client.profiles.page({
334
+ limit: 250,
335
+ })
336
+
337
+ // Search profile with Stamhoofd as name
338
+ if (website) {
339
+ for (const profile of profiles) {
340
+ if (profile.website.toLowerCase().includes(website)) {
341
+ return profile.id;
342
+ }
343
+ }
344
+ }
345
+
346
+ // Search profile with Stamhoofd as name
347
+ for (const profile of profiles) {
348
+ if (profile.name.toLowerCase().includes('stamhoofd')) {
349
+ return profile.id;
350
+ }
351
+ }
352
+
353
+ return profiles[0]?.id ?? undefined;
354
+ }
355
+ catch (e) {
356
+ console.error('Error when requesting Mollie profile id:');
357
+ console.error(e);
358
+ return undefined;
359
+ }
360
+ }
361
+
362
+ get locale() {
363
+ const preferredLocale = Context.i18n.locale.replace('-', '_');
364
+ return ['en_US', 'en_GB', 'nl_NL', 'nl_BE', 'fr_FR', 'fr_BE', 'de_DE', 'de_AT', 'de_CH', 'es_ES', 'ca_ES', 'pt_PT', 'it_IT', 'nb_NO', 'sv_SE', 'fi_FI', 'da_DK', 'is_IS', 'hu_HU', 'pl_PL', 'lv_LV', 'lt_LT'].includes(preferredLocale) ? (preferredLocale as any) : null;
365
+ }
366
+
367
+ get testMode() {
368
+ return this.sellingOrganization.privateMeta.useTestPayments ?? STAMHOOFD.environment !== 'production';
369
+ }
370
+
371
+ static async createPayment(
372
+ { sellingOrganization, payment, mandate, redirectUrl, webhookUrl, cancelUrl, description, metadata, payingOrganization, user, customer}: {
373
+ payment: Payment;
374
+ mandate: PaymentMandate | null;
375
+ redirectUrl: string;
376
+ cancelUrl: string;
377
+ webhookUrl: string;
378
+ description: string;
379
+ metadata: { [key: string]: string | undefined };
380
+ sellingOrganization: Organization,
381
+ payingOrganization: Organization | null,
382
+ user: User | null,
383
+ customer: PaymentCustomer,
384
+ },
385
+ ): Promise<{ paymentUrl: string | null }> {
386
+ const mollieService = await MollieService.create({sellingOrganization});
387
+ const profileId = await mollieService?.getProfileId();
388
+ const method = MollieService.paymentMethodToMollie(payment.method);
389
+
390
+ if (!mollieService || !profileId || !method) {
391
+ throw new SimpleError({
392
+ code: '',
393
+ message: $t(`%w3`, { method: PaymentMethodHelper.getName(payment.method) }),
394
+ });
395
+ }
396
+
397
+ const customerId = await mollieService.getCustomerId({
398
+ payingOrganization: payingOrganization ?? null,
399
+ user,
400
+ customer,
401
+ }) ?? undefined
402
+
403
+
404
+ const data: Parameters<typeof mollieService.client.payments.create>[0] = {
405
+ amount: {
406
+ currency: 'EUR',
407
+ value: (Math.round(payment.price / 100) / 100).toFixed(2),
408
+ },
409
+ method,
410
+ testmode: mollieService.testMode,
411
+ mandateId: mandate?.id,
412
+ sequenceType: mandate ? SequenceType.recurring : (payment.createMandate ? SequenceType.first : SequenceType.oneoff),
413
+ customerId,
414
+ profileId,
415
+ description,
416
+ redirectUrl,
417
+ cancelUrl,
418
+ webhookUrl,
419
+ metadata: {
420
+ paymentId: payment.id,
421
+ ...metadata
422
+ },
423
+ locale: mollieService.locale,
424
+ };
425
+ console.log('Creating payment', data)
426
+ const molliePayment = await mollieService.client.payments.create(data);
427
+ console.log('Payment response', molliePayment)
428
+
429
+ const paymentUrl = molliePayment.getCheckoutUrl();
430
+
431
+ // Save payment
432
+ const dbPayment = new MolliePayment();
433
+ dbPayment.paymentId = payment.id;
434
+ dbPayment.mollieId = molliePayment.id;
435
+ await dbPayment.save();
436
+
437
+ const {status} = await mollieService.getStatusFor(molliePayment, payment, false)
438
+ payment.status = status;
439
+
440
+ return {
441
+ paymentUrl: paymentUrl,
442
+ }
443
+ }
444
+
445
+ static async saveChargeInfo(mollieData: MolliePaymentType, payment: Payment) {
446
+ try {
447
+ const details = mollieData.details;
448
+ if (details) {
449
+ if ('consumerName' in details) {
450
+ payment.ibanName = details.consumerName;
451
+ }
452
+ if ('consumerAccount' in details) {
453
+ payment.iban = details.consumerAccount;
454
+ }
455
+ if ('cardHolder' in details) {
456
+ payment.ibanName = details.cardHolder;
457
+ }
458
+ if ('cardNumber' in details) {
459
+ payment.iban = '•••• ' + details.cardNumber;
460
+ }
461
+
462
+ payment.mandateId = mollieData.mandateId ?? null
463
+ await payment.save();
464
+ }
465
+ }
466
+ catch (e) {
467
+ console.error('Failed processing charge', e);
468
+ }
469
+ }
470
+
471
+ async getStatusFor(mollieData: MolliePaymentType, payment: Payment, cancel = false): Promise<{status: PaymentStatus}> {
472
+ await MollieService.saveChargeInfo(mollieData, payment)
473
+
474
+ if (mollieData.status === molliePaymentStatus.paid) {
475
+ return {
476
+ status: PaymentStatus.Succeeded,
477
+ }
478
+ } else if (mollieData.status === molliePaymentStatus.failed) {
479
+ return {
480
+ status: PaymentStatus.Failed,
481
+ }
482
+ } else if (mollieData.status === molliePaymentStatus.expired) {
483
+ return {
484
+ status: PaymentStatus.Failed,
485
+ }
486
+ } else if (mollieData.status === molliePaymentStatus.canceled) {
487
+ return {
488
+ status: PaymentStatus.Failed,
489
+ }
490
+ }
491
+
492
+ // Pending payments should be cancellable
493
+ if (cancel && mollieData.isCancelable) {
494
+ console.log('Cancelling Mollie Payment ' + payment.id);
495
+
496
+ // Try to cancel
497
+ try {
498
+ const newData = await this.client.payments.cancel(mollieData.id, {
499
+ testmode: this.testMode
500
+ });
501
+ console.log('Cancelled Mollie Payment ' + payment.id);
502
+ return await this.getStatusFor(newData, payment, false)
503
+ } catch (e) {
504
+ console.error('Failed to cancel Mollie Payment ' + payment.id, {cause: e})
505
+ }
506
+
507
+ } else if (cancel) {
508
+ console.log('Cannot cancel Mollie Payment ' + payment.id);
509
+ }
510
+
511
+ if (mollieData.status === molliePaymentStatus.open ) {
512
+ // Nothink happend yet
513
+ return {
514
+ status: PaymentStatus.Created,
515
+ }
516
+ }
517
+
518
+ return {
519
+ status: PaymentStatus.Pending,
520
+ }
521
+ }
522
+
523
+ async getStatus(payment: Payment, cancel = false) {
524
+ const molliePayment = await MolliePayment.select().where('paymentId', payment.id).first(false);
525
+ if (!molliePayment) {
526
+ throw new Error('Mollie Payment not found for payment ' + payment.id)
527
+ }
528
+
529
+ const mollieData = await this.client.payments.get(molliePayment.mollieId, {
530
+ testmode: this.testMode
531
+ });
532
+
533
+ console.log(mollieData)
534
+
535
+ return this.getStatusFor(mollieData, payment, cancel)
536
+ }
537
+ }