@stamhoofd/backend 2.39.1 → 2.40.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/eslint.config.mjs +5 -0
- package/index.ts +81 -74
- package/jest.config.cjs +10 -0
- package/migrations.ts +16 -14
- package/package.json +11 -11
- package/src/crons/clear-excel-cache.test.ts +48 -50
- package/src/crons/clear-excel-cache.ts +18 -18
- package/src/crons/setup-steps.ts +2 -2
- package/src/crons.ts +325 -306
- package/src/decoders/StringArrayDecoder.ts +7 -7
- package/src/decoders/StringNullableDecoder.ts +1 -2
- package/src/email-recipient-loaders/members.ts +22 -22
- package/src/endpoints/admin/memberships/ChargeMembershipsEndpoint.ts +8 -9
- package/src/endpoints/admin/memberships/GetChargeMembershipsSummaryEndpoint.ts +39 -40
- package/src/endpoints/admin/organizations/GetOrganizationsCountEndpoint.ts +8 -8
- package/src/endpoints/admin/organizations/GetOrganizationsEndpoint.ts +44 -45
- package/src/endpoints/admin/organizations/PatchOrganizationsEndpoint.ts +58 -57
- package/src/endpoints/auth/CreateAdminEndpoint.ts +48 -45
- package/src/endpoints/auth/CreateTokenEndpoint.test.ts +31 -31
- package/src/endpoints/auth/CreateTokenEndpoint.ts +146 -147
- package/src/endpoints/auth/DeleteTokenEndpoint.ts +7 -7
- package/src/endpoints/auth/DeleteUserEndpoint.ts +15 -15
- package/src/endpoints/auth/ForgotPasswordEndpoint.ts +17 -18
- package/src/endpoints/auth/GetOtherUserEndpoint.ts +9 -10
- package/src/endpoints/auth/GetUserEndpoint.test.ts +32 -35
- package/src/endpoints/auth/GetUserEndpoint.ts +5 -6
- package/src/endpoints/auth/PatchApiUserEndpoint.ts +35 -33
- package/src/endpoints/auth/PatchUserEndpoint.ts +55 -52
- package/src/endpoints/auth/PollEmailVerificationEndpoint.ts +9 -9
- package/src/endpoints/auth/RetryEmailVerificationEndpoint.ts +8 -8
- package/src/endpoints/auth/SignupEndpoint.ts +37 -36
- package/src/endpoints/auth/VerifyEmailEndpoint.ts +29 -28
- package/src/endpoints/global/addresses/SearchRegionsEndpoint.ts +33 -33
- package/src/endpoints/global/addresses/ValidateAddressEndpoint.ts +7 -7
- package/src/endpoints/global/caddy/CheckDomainCertEndpoint.ts +37 -37
- package/src/endpoints/global/email/CreateEmailEndpoint.ts +30 -30
- package/src/endpoints/global/email/GetEmailAddressEndpoint.ts +13 -13
- package/src/endpoints/global/email/GetEmailEndpoint.ts +13 -13
- package/src/endpoints/global/email/ManageEmailAddressEndpoint.ts +16 -16
- package/src/endpoints/global/email/PatchEmailEndpoint.ts +25 -25
- package/src/endpoints/global/events/GetEventsEndpoint.ts +43 -44
- package/src/endpoints/global/events/PatchEventsEndpoint.ts +127 -172
- package/src/endpoints/global/files/ExportToExcelEndpoint.ts +49 -50
- package/src/endpoints/global/files/GetFileCache.ts +13 -13
- package/src/endpoints/global/files/UploadFile.ts +51 -54
- package/src/endpoints/global/files/UploadImage.ts +53 -53
- package/src/endpoints/global/groups/GetGroupsEndpoint.ts +25 -25
- package/src/endpoints/global/members/GetMemberFamilyEndpoint.ts +24 -23
- package/src/endpoints/global/members/GetMembersCountEndpoint.ts +8 -8
- package/src/endpoints/global/members/GetMembersEndpoint.ts +105 -102
- package/src/endpoints/global/members/PatchOrganizationMembersEndpoint.ts +240 -239
- package/src/endpoints/global/organizations/CheckRegisterCodeEndpoint.ts +12 -14
- package/src/endpoints/global/organizations/CreateOrganizationEndpoint.test.ts +32 -33
- package/src/endpoints/global/organizations/CreateOrganizationEndpoint.ts +48 -57
- package/src/endpoints/global/organizations/GetOrganizationFromDomainEndpoint.test.ts +21 -22
- package/src/endpoints/global/organizations/GetOrganizationFromDomainEndpoint.ts +28 -28
- package/src/endpoints/global/organizations/GetOrganizationFromUriEndpoint.ts +18 -18
- package/src/endpoints/global/organizations/SearchOrganizationEndpoint.test.ts +20 -20
- package/src/endpoints/global/organizations/SearchOrganizationEndpoint.ts +17 -17
- package/src/endpoints/global/payments/StripeWebhookEndpoint.ts +81 -75
- package/src/endpoints/global/platform/GetPlatformAdminsEndpoint.ts +14 -14
- package/src/endpoints/global/platform/GetPlatformEnpoint.ts +11 -11
- package/src/endpoints/global/platform/PatchPlatformEnpoint.ts +71 -68
- package/src/endpoints/global/registration/GetPaymentRegistrations.ts +27 -27
- package/src/endpoints/global/registration/GetUserBillingStatusEndpoint.ts +30 -30
- package/src/endpoints/global/registration/GetUserDetailedBillingStatusEndpoint.ts +34 -34
- package/src/endpoints/global/registration/GetUserDocumentsEndpoint.ts +26 -26
- package/src/endpoints/global/registration/GetUserMembersEndpoint.ts +12 -12
- package/src/endpoints/global/registration/PatchUserMembersEndpoint.ts +90 -90
- package/src/endpoints/global/registration/RegisterMembersEndpoint.test.ts +118 -121
- package/src/endpoints/global/registration/RegisterMembersEndpoint.ts +362 -350
- package/src/endpoints/global/registration-periods/GetRegistrationPeriodsEndpoint.ts +8 -9
- package/src/endpoints/global/registration-periods/PatchRegistrationPeriodsEndpoint.ts +21 -21
- package/src/endpoints/global/webshops/GetWebshopFromDomainEndpoint.ts +65 -65
- package/src/endpoints/organization/dashboard/billing/GetOrganizationBillingStatusEndpoint.ts +9 -9
- package/src/endpoints/organization/dashboard/billing/GetOrganizationDetailedBillingStatusEndpoint.ts +14 -14
- package/src/endpoints/organization/dashboard/documents/GetDocumentTemplateXML.ts +17 -17
- package/src/endpoints/organization/dashboard/documents/GetDocumentTemplatesEndpoint.ts +21 -21
- package/src/endpoints/organization/dashboard/documents/GetDocumentsEndpoint.ts +15 -15
- package/src/endpoints/organization/dashboard/documents/PatchDocumentEndpoint.ts +52 -52
- package/src/endpoints/organization/dashboard/documents/PatchDocumentTemplateEndpoint.ts +37 -37
- package/src/endpoints/organization/dashboard/email/CheckEmailBouncesEndpoint.ts +14 -14
- package/src/endpoints/organization/dashboard/email/EmailEndpoint.ts +113 -112
- package/src/endpoints/organization/dashboard/email-templates/GetEmailTemplatesEndpoint.ts +29 -29
- package/src/endpoints/organization/dashboard/email-templates/PatchEmailTemplatesEndpoint.ts +48 -47
- package/src/endpoints/organization/dashboard/mollie/CheckMollieEndpoint.ts +22 -21
- package/src/endpoints/organization/dashboard/mollie/ConnectMollieEndpoint.ts +13 -14
- package/src/endpoints/organization/dashboard/mollie/DisconnectMollieEndpoint.ts +12 -13
- package/src/endpoints/organization/dashboard/mollie/GetMollieDashboardEndpoint.ts +24 -24
- package/src/endpoints/organization/dashboard/nolt/CreateNoltTokenEndpoint.ts +10 -12
- package/src/endpoints/organization/dashboard/organization/GetOrganizationArchivedGroups.ts +14 -14
- package/src/endpoints/organization/dashboard/organization/GetOrganizationDeletedGroups.ts +13 -13
- package/src/endpoints/organization/dashboard/organization/GetOrganizationSSOEndpoint.ts +12 -12
- package/src/endpoints/organization/dashboard/organization/PatchOrganizationEndpoint.test.ts +120 -124
- package/src/endpoints/organization/dashboard/organization/PatchOrganizationEndpoint.ts +172 -173
- package/src/endpoints/organization/dashboard/organization/SetOrganizationDomainEndpoint.ts +88 -89
- package/src/endpoints/organization/dashboard/organization/SetOrganizationSSOEndpoint.ts +12 -12
- package/src/endpoints/organization/dashboard/payments/GetMemberBalanceEndpoint.ts +17 -17
- package/src/endpoints/organization/dashboard/payments/GetPaymentsCountEndpoint.ts +8 -8
- package/src/endpoints/organization/dashboard/payments/GetPaymentsEndpoint.ts +66 -67
- package/src/endpoints/organization/dashboard/payments/PatchBalanceItemsEndpoint.ts +47 -47
- package/src/endpoints/organization/dashboard/payments/PatchPaymentsEndpoint.ts +93 -91
- package/src/endpoints/organization/dashboard/registration-periods/GetOrganizationRegistrationPeriodsEndpoint.ts +16 -17
- package/src/endpoints/organization/dashboard/registration-periods/PatchOrganizationRegistrationPeriodsEndpoint.ts +170 -167
- package/src/endpoints/organization/dashboard/registration-periods/SetupStepReviewEndpoint.ts +25 -24
- package/src/endpoints/organization/dashboard/stripe/ConnectStripeEndpoint.ts +22 -23
- package/src/endpoints/organization/dashboard/stripe/DeleteStripeAccountEndpoint.ts +22 -22
- package/src/endpoints/organization/dashboard/stripe/GetStripeAccountLinkEndpoint.ts +17 -18
- package/src/endpoints/organization/dashboard/stripe/GetStripeAccountsEndpoint.ts +8 -9
- package/src/endpoints/organization/dashboard/stripe/GetStripeLoginLinkEndpoint.ts +17 -18
- package/src/endpoints/organization/dashboard/stripe/UpdateStripeAccountEndpoint.ts +14 -15
- package/src/endpoints/organization/dashboard/users/CreateApiUserEndpoint.ts +19 -19
- package/src/endpoints/organization/dashboard/users/DeleteUserEndpoint.ts +19 -19
- package/src/endpoints/organization/dashboard/users/GetApiUsersEndpoint.ts +14 -14
- package/src/endpoints/organization/dashboard/users/GetOrganizationAdminsEndpoint.ts +12 -12
- package/src/endpoints/organization/dashboard/webshops/CreateWebshopEndpoint.ts +103 -100
- package/src/endpoints/organization/dashboard/webshops/DeleteWebshopEndpoint.ts +11 -12
- package/src/endpoints/organization/dashboard/webshops/GetDiscountCodesEndpoint.ts +15 -15
- package/src/endpoints/organization/dashboard/webshops/GetWebshopOrdersEndpoint.ts +14 -14
- package/src/endpoints/organization/dashboard/webshops/GetWebshopTicketsEndpoint.ts +14 -14
- package/src/endpoints/organization/dashboard/webshops/GetWebshopUriAvailabilityEndpoint.ts +23 -23
- package/src/endpoints/organization/dashboard/webshops/PatchDiscountCodesEndpoint.ts +54 -52
- package/src/endpoints/organization/dashboard/webshops/PatchWebshopEndpoint.ts +84 -81
- package/src/endpoints/organization/dashboard/webshops/PatchWebshopOrdersEndpoint.ts +120 -111
- package/src/endpoints/organization/dashboard/webshops/PatchWebshopTicketsEndpoint.ts +24 -24
- package/src/endpoints/organization/dashboard/webshops/VerifyWebshopDomainEndpoint.ts +18 -18
- package/src/endpoints/organization/shared/ExchangePaymentEndpoint.ts +141 -130
- package/src/endpoints/organization/shared/GetDocumentHtml.ts +25 -25
- package/src/endpoints/organization/shared/GetPaymentEndpoint.ts +18 -18
- package/src/endpoints/organization/shared/auth/GetOrganizationEndpoint.test.ts +36 -37
- package/src/endpoints/organization/shared/auth/GetOrganizationEndpoint.ts +9 -9
- package/src/endpoints/organization/shared/auth/OpenIDConnectCallbackEndpoint.ts +11 -11
- package/src/endpoints/organization/shared/auth/OpenIDConnectStartEndpoint.ts +28 -27
- package/src/endpoints/organization/webshops/CheckWebshopDiscountCodesEndpoint.ts +20 -20
- package/src/endpoints/organization/webshops/GetOrderByPaymentEndpoint.ts +22 -22
- package/src/endpoints/organization/webshops/GetOrderEndpoint.ts +14 -14
- package/src/endpoints/organization/webshops/GetTicketsEndpoint.ts +57 -56
- package/src/endpoints/organization/webshops/GetWebshopEndpoint.test.ts +65 -66
- package/src/endpoints/organization/webshops/GetWebshopEndpoint.ts +18 -17
- package/src/endpoints/organization/webshops/PlaceOrderEndpoint.test.ts +124 -128
- package/src/endpoints/organization/webshops/PlaceOrderEndpoint.ts +154 -145
- package/src/excel-loaders/members.ts +275 -273
- package/src/excel-loaders/payments.ts +155 -156
- package/src/helpers/AddressValidator.test.ts +32 -32
- package/src/helpers/AddressValidator.ts +128 -122
- package/src/helpers/AdminPermissionChecker.ts +339 -236
- package/src/helpers/AuthenticatedStructures.ts +233 -134
- package/src/helpers/BuckarooHelper.ts +134 -134
- package/src/helpers/CheckSettlements.ts +94 -88
- package/src/helpers/Context.ts +87 -86
- package/src/helpers/CookieHelper.ts +23 -22
- package/src/helpers/EmailResumer.ts +10 -10
- package/src/helpers/FileCache.ts +62 -62
- package/src/helpers/ForwardHandler.test.ts +122 -124
- package/src/helpers/ForwardHandler.ts +76 -70
- package/src/helpers/MemberUserSyncer.ts +101 -96
- package/src/helpers/MembershipCharger.ts +69 -69
- package/src/helpers/MembershipHelper.ts +11 -12
- package/src/helpers/OpenIDConnectHelper.ts +85 -82
- package/src/helpers/PeriodHelper.ts +65 -70
- package/src/helpers/StripeHelper.ts +146 -137
- package/src/helpers/StripePayoutChecker.ts +51 -52
- package/src/helpers/ViesHelper.ts +46 -44
- package/src/helpers/fetchToAsyncIterator.ts +14 -14
- package/src/helpers/xlsxAddressTransformerColumnFactory.ts +58 -60
- package/src/middleware/ContextMiddleware.ts +5 -5
- package/src/migrations/1646578856-validate-addresses.ts +6 -9
- package/src/seeds/0000000000-example.ts +3 -5
- package/src/seeds/1715028563-user-permissions.ts +16 -18
- package/src/seeds/1722256498-group-update-occupancy.ts +12 -12
- package/src/seeds/1722344162-sync-member-users.ts +14 -15
- package/src/seeds/1722344162-update-membership.ts +6 -6
- package/src/seeds/1726055544-balance-item-paid.ts +4 -4
- package/src/seeds/1726055545-balance-item-pending.ts +4 -4
- package/src/seeds/1726494419-update-cached-outstanding-balance.ts +16 -16
- package/src/seeds/1726494420-update-cached-outstanding-balance-from-items.ts +12 -12
- package/src/seeds/1726572303-schedule-stock-updates.ts +12 -12
- package/src/seeds/1726847064-setup-steps.ts +16 -0
- package/src/sql-filters/balance-item-payments.ts +7 -7
- package/src/sql-filters/events.ts +14 -14
- package/src/sql-filters/members.ts +96 -96
- package/src/sql-filters/organizations.ts +139 -75
- package/src/sql-filters/payments.ts +28 -28
- package/src/sql-filters/registrations.ts +14 -14
- package/src/sql-sorters/events.ts +25 -25
- package/src/sql-sorters/members.ts +26 -26
- package/src/sql-sorters/organizations.ts +36 -36
- package/src/sql-sorters/payments.ts +26 -26
- package/tests/e2e/stock.test.ts +616 -621
- package/tests/e2e/tickets.test.ts +255 -260
- package/tests/helpers/StripeMocker.ts +177 -179
- package/tests/helpers/TestServer.ts +9 -9
- package/tests/jest.global.setup.ts +14 -13
- package/tests/jest.setup.ts +33 -32
- package/.eslintrc.js +0 -61
- package/jest.config.js +0 -11
- package/src/helpers/SetupStepsUpdater.ts +0 -359
- package/src/seeds/1724076679-setup-steps.ts +0 -16
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { createMollieClient, PaymentMethod as molliePaymentMethod } from '@mollie/api-client';
|
|
2
2
|
import { Decoder } from '@simonbackx/simple-encoding';
|
|
3
|
-
import { DecodedRequest, Endpoint, Request, Response } from
|
|
3
|
+
import { DecodedRequest, Endpoint, Request, Response } from '@simonbackx/simple-endpoints';
|
|
4
4
|
import { SimpleError } from '@simonbackx/simple-errors';
|
|
5
5
|
import { I18n } from '@stamhoofd/backend-i18n';
|
|
6
6
|
import { Email } from '@stamhoofd/email';
|
|
7
7
|
import { BalanceItem, BalanceItemPayment, MolliePayment, MollieToken, Order, PayconiqPayment, Payment, RateLimiter, Webshop, WebshopDiscountCode } from '@stamhoofd/models';
|
|
8
8
|
import { QueueHandler } from '@stamhoofd/queues';
|
|
9
|
-
import { BalanceItemStatus, Order as OrderStruct, OrderData, OrderResponse, Payment as PaymentStruct, PaymentMethod, PaymentMethodHelper, PaymentProvider, PaymentStatus, Version, Webshop as WebshopStruct,WebshopAuthType, BalanceItemType, BalanceItemRelationType, BalanceItemRelation } from
|
|
9
|
+
import { BalanceItemStatus, Order as OrderStruct, OrderData, OrderResponse, Payment as PaymentStruct, PaymentMethod, PaymentMethodHelper, PaymentProvider, PaymentStatus, Version, Webshop as WebshopStruct, WebshopAuthType, BalanceItemType, BalanceItemRelationType, BalanceItemRelation } from '@stamhoofd/structures';
|
|
10
10
|
import { Formatter } from '@stamhoofd/utility';
|
|
11
11
|
|
|
12
12
|
import { BuckarooHelper } from '../../../helpers/BuckarooHelper';
|
|
@@ -15,36 +15,36 @@ import { StripeHelper } from '../../../helpers/StripeHelper';
|
|
|
15
15
|
|
|
16
16
|
type Params = { id: string };
|
|
17
17
|
type Query = undefined;
|
|
18
|
-
type Body = OrderData
|
|
19
|
-
type ResponseBody = OrderResponse
|
|
18
|
+
type Body = OrderData;
|
|
19
|
+
type ResponseBody = OrderResponse;
|
|
20
20
|
|
|
21
21
|
export const demoOrderLimiter = new RateLimiter({
|
|
22
22
|
limits: [
|
|
23
|
-
{
|
|
23
|
+
{
|
|
24
24
|
// Max 10 per hour
|
|
25
25
|
limit: STAMHOOFD.environment === 'development' ? 100 : 10,
|
|
26
|
-
duration: 60 * 1000 * 60
|
|
26
|
+
duration: 60 * 1000 * 60,
|
|
27
27
|
},
|
|
28
|
-
{
|
|
28
|
+
{
|
|
29
29
|
// Max 20 a day
|
|
30
30
|
limit: STAMHOOFD.environment === 'development' ? 1000 : 20,
|
|
31
|
-
duration: 24 * 60 * 1000 * 60
|
|
32
|
-
}
|
|
33
|
-
]
|
|
31
|
+
duration: 24 * 60 * 1000 * 60,
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
34
|
});
|
|
35
35
|
|
|
36
36
|
/**
|
|
37
37
|
* Allow to add, patch and delete multiple members simultaneously, which is needed in order to sync relational data that is saved encrypted in multiple members (e.g. parents)
|
|
38
38
|
*/
|
|
39
39
|
export class PlaceOrderEndpoint extends Endpoint<Params, Query, Body, ResponseBody> {
|
|
40
|
-
bodyDecoder = OrderData as Decoder<OrderData
|
|
40
|
+
bodyDecoder = OrderData as Decoder<OrderData>;
|
|
41
41
|
|
|
42
42
|
protected doesMatch(request: Request): [true, Params] | [false] {
|
|
43
|
-
if (request.method
|
|
43
|
+
if (request.method !== 'POST') {
|
|
44
44
|
return [false];
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
const params = Endpoint.parseParameters(request.url,
|
|
47
|
+
const params = Endpoint.parseParameters(request.url, '/webshop/@id/order', { id: String });
|
|
48
48
|
|
|
49
49
|
if (params) {
|
|
50
50
|
return [true, params as Params];
|
|
@@ -54,188 +54,192 @@ export class PlaceOrderEndpoint extends Endpoint<Params, Query, Body, ResponseBo
|
|
|
54
54
|
|
|
55
55
|
async handle(request: DecodedRequest<Params, Query, Body>) {
|
|
56
56
|
const organization = await Context.setOrganizationScope();
|
|
57
|
-
await Context.optionalAuthenticate()
|
|
57
|
+
await Context.optionalAuthenticate();
|
|
58
58
|
|
|
59
59
|
// Read + validate + update stock in one go, to prevent race conditions
|
|
60
|
-
const { webshop, order } = await QueueHandler.schedule(
|
|
61
|
-
const webshopWithoutOrganization = await Webshop.getByID(request.params.id)
|
|
60
|
+
const { webshop, order } = await QueueHandler.schedule('webshop-stock/' + request.params.id, async () => {
|
|
61
|
+
const webshopWithoutOrganization = await Webshop.getByID(request.params.id);
|
|
62
62
|
if (!webshopWithoutOrganization || webshopWithoutOrganization.organizationId !== organization.id) {
|
|
63
63
|
throw new SimpleError({
|
|
64
|
-
code:
|
|
65
|
-
message:
|
|
66
|
-
human:
|
|
67
|
-
})
|
|
64
|
+
code: 'not_found',
|
|
65
|
+
message: 'Webshop not found',
|
|
66
|
+
human: 'Deze webshop bestaat niet (meer)',
|
|
67
|
+
});
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
//const organization = (await Organization.getByID(webshopWithoutOrganization.organizationId))!
|
|
71
|
-
const webshop = webshopWithoutOrganization.setRelation(Webshop.organization, organization)
|
|
70
|
+
// const organization = (await Organization.getByID(webshopWithoutOrganization.organizationId))!
|
|
71
|
+
const webshop = webshopWithoutOrganization.setRelation(Webshop.organization, organization);
|
|
72
72
|
|
|
73
73
|
if (webshop.meta.authType === WebshopAuthType.Required && !Context.user) {
|
|
74
74
|
throw new SimpleError({
|
|
75
|
-
code:
|
|
76
|
-
message:
|
|
77
|
-
human:
|
|
78
|
-
statusCode: 401
|
|
79
|
-
})
|
|
75
|
+
code: 'not_authenticated',
|
|
76
|
+
message: 'Not authenticated',
|
|
77
|
+
human: 'Je moet inloggen om een bestelling te kunnen plaatsen.',
|
|
78
|
+
statusCode: 401,
|
|
79
|
+
});
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
// For non paid organizations, the limit is 10
|
|
83
83
|
if (!organization.meta.packages.isPaid && STAMHOOFD.environment !== 'test') {
|
|
84
|
-
const limiter = demoOrderLimiter
|
|
84
|
+
const limiter = demoOrderLimiter;
|
|
85
85
|
|
|
86
86
|
try {
|
|
87
87
|
limiter.track(organization.id, 1);
|
|
88
|
-
}
|
|
88
|
+
}
|
|
89
|
+
catch (e) {
|
|
89
90
|
Email.sendWebmaster({
|
|
90
|
-
subject:
|
|
91
|
-
text:
|
|
92
|
-
})
|
|
93
|
-
|
|
91
|
+
subject: '[Limiet] Limiet bereikt voor aantal bestellingen',
|
|
92
|
+
text: 'Beste, \nDe limiet werd bereikt voor het aantal bestellingen per dag. \nVereniging: ' + organization.id + ' (' + organization.name + ')' + '\n\n' + e.message + '\n\nStamhoofd',
|
|
93
|
+
});
|
|
94
|
+
|
|
94
95
|
throw new SimpleError({
|
|
95
|
-
code:
|
|
96
|
-
message:
|
|
97
|
-
human:
|
|
98
|
-
field:
|
|
99
|
-
})
|
|
96
|
+
code: 'too_many_emails_period',
|
|
97
|
+
message: 'Too many e-mails limited',
|
|
98
|
+
human: 'Oeps! Om spam te voorkomen limiteren we het aantal test bestellingen die je per uur of dag kan plaatsen. Probeer over een uur opnieuw of schakel over naar een betaald abonnement.',
|
|
99
|
+
field: 'recipients',
|
|
100
|
+
});
|
|
100
101
|
}
|
|
101
102
|
}
|
|
102
103
|
|
|
103
|
-
const webshopStruct = WebshopStruct.create(webshop)
|
|
104
|
+
const webshopStruct = WebshopStruct.create(webshop);
|
|
104
105
|
|
|
105
|
-
const usedCodes = request.body.discountCodes.map(c => c.code)
|
|
106
|
+
const usedCodes = request.body.discountCodes.map(c => c.code);
|
|
106
107
|
const uniqueCodes = Formatter.uniqueArray(usedCodes);
|
|
107
108
|
if (uniqueCodes.length !== usedCodes.length) {
|
|
108
109
|
// Duplicate code usage is not allowed
|
|
109
110
|
throw new SimpleError({
|
|
110
|
-
code:
|
|
111
|
-
message:
|
|
112
|
-
human:
|
|
113
|
-
field:
|
|
114
|
-
})
|
|
111
|
+
code: 'duplicate_codes',
|
|
112
|
+
message: 'Duplicate usage of discount codes',
|
|
113
|
+
human: 'Sommige kortingcodes werden dubbel toegepast op jouw bestelling. Kijk het even na, dit is niet toegestaan.',
|
|
114
|
+
field: 'cart.discountCodes',
|
|
115
|
+
});
|
|
115
116
|
}
|
|
116
117
|
if (uniqueCodes.length > 0) {
|
|
117
118
|
// Fetch new and update them
|
|
118
|
-
const codeModels = await WebshopDiscountCode.getActiveCodes(webshop.id, uniqueCodes)
|
|
119
|
+
const codeModels = await WebshopDiscountCode.getActiveCodes(webshop.id, uniqueCodes);
|
|
119
120
|
|
|
120
121
|
if (codeModels.length !== uniqueCodes.length) {
|
|
121
122
|
throw new SimpleError({
|
|
122
|
-
code:
|
|
123
|
-
message:
|
|
124
|
-
human:
|
|
125
|
-
field:
|
|
126
|
-
})
|
|
123
|
+
code: 'invalid_code',
|
|
124
|
+
message: 'Invalid discount code',
|
|
125
|
+
human: 'De kortingscode die je hebt toegevoegd is niet (meer) geldig',
|
|
126
|
+
field: 'cart.discountCodes',
|
|
127
|
+
});
|
|
127
128
|
}
|
|
128
|
-
request.body.discountCodes = codeModels.map(c => c.getStructure())
|
|
129
|
+
request.body.discountCodes = codeModels.map(c => c.getStructure());
|
|
129
130
|
}
|
|
130
131
|
|
|
131
|
-
request.body.validate(webshopStruct, organization.meta, request.i18n, false, Context.user?.getStructure())
|
|
132
|
-
request.body.update(webshopStruct)
|
|
132
|
+
request.body.validate(webshopStruct, organization.meta, request.i18n, false, Context.user?.getStructure());
|
|
133
|
+
request.body.update(webshopStruct);
|
|
133
134
|
|
|
134
|
-
const order = new Order().setRelation(Order.webshop, webshop)
|
|
135
|
-
order.data = request.body // TODO: validate
|
|
136
|
-
order.organizationId = organization.id
|
|
137
|
-
order.createdAt = new Date()
|
|
138
|
-
order.createdAt.setMilliseconds(0)
|
|
139
|
-
order.userId = Context.user?.id ?? null
|
|
135
|
+
const order = new Order().setRelation(Order.webshop, webshop);
|
|
136
|
+
order.data = request.body; // TODO: validate
|
|
137
|
+
order.organizationId = organization.id;
|
|
138
|
+
order.createdAt = new Date();
|
|
139
|
+
order.createdAt.setMilliseconds(0);
|
|
140
|
+
order.userId = Context.user?.id ?? null;
|
|
140
141
|
|
|
141
142
|
// Always reserve the stock
|
|
142
|
-
await order.updateStock()
|
|
143
|
-
return { webshop, order, organization }
|
|
144
|
-
})
|
|
143
|
+
await order.updateStock();
|
|
144
|
+
return { webshop, order, organization };
|
|
145
|
+
});
|
|
145
146
|
|
|
146
147
|
// The order now is valid, the stock is reserved for now (until the payment fails or expires)
|
|
147
|
-
const totalPrice = request.body.totalPrice
|
|
148
|
+
const totalPrice = request.body.totalPrice;
|
|
148
149
|
|
|
149
150
|
try {
|
|
150
151
|
if (totalPrice == 0) {
|
|
151
152
|
// Force unknown payment method
|
|
152
|
-
order.data.paymentMethod = PaymentMethod.Unknown
|
|
153
|
+
order.data.paymentMethod = PaymentMethod.Unknown;
|
|
153
154
|
|
|
154
155
|
// Mark this order as paid
|
|
155
|
-
await order.markPaid(null, organization, webshop)
|
|
156
|
-
await order.save()
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
payment
|
|
160
|
-
payment.
|
|
161
|
-
payment.
|
|
162
|
-
payment.
|
|
163
|
-
payment.
|
|
156
|
+
await order.markPaid(null, organization, webshop);
|
|
157
|
+
await order.save();
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
const payment = new Payment();
|
|
161
|
+
payment.organizationId = organization.id;
|
|
162
|
+
payment.method = request.body.paymentMethod;
|
|
163
|
+
payment.status = PaymentStatus.Created;
|
|
164
|
+
payment.price = totalPrice;
|
|
165
|
+
payment.paidAt = null;
|
|
164
166
|
|
|
165
167
|
// Determine the payment provider
|
|
166
168
|
// Throws if invalid
|
|
167
|
-
const {provider, stripeAccount} = await organization.getPaymentProviderFor(payment.method, webshop.privateMeta.paymentConfiguration)
|
|
168
|
-
payment.provider = provider
|
|
169
|
-
payment.stripeAccountId = stripeAccount?.id ?? null
|
|
169
|
+
const { provider, stripeAccount } = await organization.getPaymentProviderFor(payment.method, webshop.privateMeta.paymentConfiguration);
|
|
170
|
+
payment.provider = provider;
|
|
171
|
+
payment.stripeAccountId = stripeAccount?.id ?? null;
|
|
170
172
|
|
|
171
|
-
await payment.save()
|
|
173
|
+
await payment.save();
|
|
172
174
|
|
|
173
175
|
// Deprecated field
|
|
174
|
-
order.paymentId = payment.id
|
|
175
|
-
order.setRelation(Order.payment, payment)
|
|
176
|
+
order.paymentId = payment.id;
|
|
177
|
+
order.setRelation(Order.payment, payment);
|
|
176
178
|
|
|
177
179
|
// Save order to get the id
|
|
178
|
-
await order.save()
|
|
180
|
+
await order.save();
|
|
179
181
|
|
|
180
|
-
const balanceItemPayments: (BalanceItemPayment & { balanceItem: BalanceItem })[] = []
|
|
182
|
+
const balanceItemPayments: (BalanceItemPayment & { balanceItem: BalanceItem })[] = [];
|
|
181
183
|
|
|
182
184
|
// Create balance item
|
|
183
185
|
const balanceItem = new BalanceItem();
|
|
184
186
|
balanceItem.type = BalanceItemType.Order;
|
|
185
187
|
balanceItem.orderId = order.id;
|
|
186
|
-
balanceItem.unitPrice = totalPrice
|
|
187
|
-
balanceItem.description = webshop.meta.name
|
|
188
|
-
balanceItem.pricePaid = 0
|
|
188
|
+
balanceItem.unitPrice = totalPrice;
|
|
189
|
+
balanceItem.description = webshop.meta.name;
|
|
190
|
+
balanceItem.pricePaid = 0;
|
|
189
191
|
balanceItem.organizationId = organization.id;
|
|
190
192
|
balanceItem.status = BalanceItemStatus.Hidden;
|
|
191
193
|
balanceItem.relations = new Map([
|
|
192
194
|
[
|
|
193
|
-
BalanceItemRelationType.Webshop,
|
|
195
|
+
BalanceItemRelationType.Webshop,
|
|
194
196
|
BalanceItemRelation.create({
|
|
195
197
|
id: webshop.id,
|
|
196
198
|
name: webshop.meta.name,
|
|
197
|
-
})
|
|
198
|
-
]
|
|
199
|
-
])
|
|
199
|
+
}),
|
|
200
|
+
],
|
|
201
|
+
]);
|
|
200
202
|
await balanceItem.save();
|
|
201
203
|
|
|
202
204
|
// Create one balance item payment to pay it in one payment
|
|
203
|
-
const balanceItemPayment = new BalanceItemPayment()
|
|
205
|
+
const balanceItemPayment = new BalanceItemPayment();
|
|
204
206
|
balanceItemPayment.balanceItemId = balanceItem.id;
|
|
205
207
|
balanceItemPayment.paymentId = payment.id;
|
|
206
208
|
balanceItemPayment.organizationId = organization.id;
|
|
207
209
|
balanceItemPayment.price = balanceItem.price;
|
|
208
210
|
await balanceItemPayment.save();
|
|
209
|
-
balanceItemPayments.push(balanceItemPayment.setRelation(BalanceItemPayment.balanceItem, balanceItem))
|
|
211
|
+
balanceItemPayments.push(balanceItemPayment.setRelation(BalanceItemPayment.balanceItem, balanceItem));
|
|
210
212
|
|
|
211
|
-
let paymentUrl: string | null = null
|
|
212
|
-
const description = webshop.meta.name+
|
|
213
|
+
let paymentUrl: string | null = null;
|
|
214
|
+
const description = webshop.meta.name + ' - ' + payment.id;
|
|
213
215
|
|
|
214
216
|
if (payment.method == PaymentMethod.Transfer) {
|
|
215
|
-
await order.markValid(payment, [])
|
|
217
|
+
await order.markValid(payment, []);
|
|
216
218
|
|
|
217
219
|
if (order.number) {
|
|
218
|
-
balanceItem.description = order.generateBalanceDescription(webshop)
|
|
220
|
+
balanceItem.description = order.generateBalanceDescription(webshop);
|
|
219
221
|
}
|
|
220
222
|
|
|
221
223
|
balanceItem.status = BalanceItemStatus.Pending;
|
|
222
|
-
await balanceItem.save()
|
|
223
|
-
await payment.save()
|
|
224
|
-
}
|
|
224
|
+
await balanceItem.save();
|
|
225
|
+
await payment.save();
|
|
226
|
+
}
|
|
227
|
+
else if (payment.method == PaymentMethod.PointOfSale) {
|
|
225
228
|
// Not really paid, but needed to create the tickets if needed
|
|
226
|
-
await order.markPaid(payment, organization, webshop)
|
|
229
|
+
await order.markPaid(payment, organization, webshop);
|
|
227
230
|
|
|
228
231
|
if (order.number) {
|
|
229
|
-
balanceItem.description = order.generateBalanceDescription(webshop)
|
|
232
|
+
balanceItem.description = order.generateBalanceDescription(webshop);
|
|
230
233
|
}
|
|
231
|
-
|
|
234
|
+
|
|
232
235
|
balanceItem.status = BalanceItemStatus.Pending;
|
|
233
|
-
await balanceItem.save()
|
|
234
|
-
await payment.save()
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
const
|
|
238
|
-
const
|
|
236
|
+
await balanceItem.save();
|
|
237
|
+
await payment.save();
|
|
238
|
+
}
|
|
239
|
+
else {
|
|
240
|
+
const cancelUrl = 'https://' + webshop.getHost() + '/payment?id=' + encodeURIComponent(payment.id) + '&cancel=true';
|
|
241
|
+
const redirectUrl = 'https://' + webshop.getHost() + '/payment?id=' + encodeURIComponent(payment.id);
|
|
242
|
+
const exchangeUrl = 'https://' + organization.getApiHost() + '/v' + Version + '/payments/' + encodeURIComponent(payment.id) + '?exchange=true';
|
|
239
243
|
|
|
240
244
|
if (payment.provider === PaymentProvider.Stripe) {
|
|
241
245
|
const stripeResult = await StripeHelper.createPayment({
|
|
@@ -256,33 +260,34 @@ export class PlaceOrderEndpoint extends Endpoint<Params, Query, Body, ResponseBo
|
|
|
256
260
|
customer: {
|
|
257
261
|
name: order.data.customer.name,
|
|
258
262
|
email: order.data.customer.email,
|
|
259
|
-
}
|
|
263
|
+
},
|
|
260
264
|
});
|
|
261
|
-
paymentUrl = stripeResult.paymentUrl
|
|
262
|
-
}
|
|
265
|
+
paymentUrl = stripeResult.paymentUrl;
|
|
266
|
+
}
|
|
267
|
+
else if (payment.provider === PaymentProvider.Mollie) {
|
|
263
268
|
// Mollie payment
|
|
264
|
-
const token = await MollieToken.getTokenFor(webshop.organizationId)
|
|
269
|
+
const token = await MollieToken.getTokenFor(webshop.organizationId);
|
|
265
270
|
if (!token) {
|
|
266
|
-
throw new SimpleError({
|
|
267
|
-
code:
|
|
268
|
-
message:
|
|
269
|
-
})
|
|
271
|
+
throw new SimpleError({
|
|
272
|
+
code: '',
|
|
273
|
+
message: 'Betaling via ' + PaymentMethodHelper.getName(payment.method) + ' is onbeschikbaar',
|
|
274
|
+
});
|
|
270
275
|
}
|
|
271
|
-
const profileId = organization.privateMeta.mollieProfile?.id ?? await token.getProfileId(webshop.getHost())
|
|
276
|
+
const profileId = organization.privateMeta.mollieProfile?.id ?? await token.getProfileId(webshop.getHost());
|
|
272
277
|
if (!profileId) {
|
|
273
278
|
throw new SimpleError({
|
|
274
|
-
code:
|
|
275
|
-
message:
|
|
276
|
-
})
|
|
279
|
+
code: '',
|
|
280
|
+
message: 'Betaling via ' + PaymentMethodHelper.getName(payment.method) + ' is tijdelijk onbeschikbaar',
|
|
281
|
+
});
|
|
277
282
|
}
|
|
278
283
|
const mollieClient = createMollieClient({ accessToken: await token.getAccessToken() });
|
|
279
284
|
const molliePayment = await mollieClient.payments.create({
|
|
280
285
|
amount: {
|
|
281
286
|
currency: 'EUR',
|
|
282
|
-
value: (totalPrice / 100).toFixed(2)
|
|
287
|
+
value: (totalPrice / 100).toFixed(2),
|
|
283
288
|
},
|
|
284
289
|
method: payment.method == PaymentMethod.Bancontact ? molliePaymentMethod.bancontact : (payment.method == PaymentMethod.iDEAL ? molliePaymentMethod.ideal : molliePaymentMethod.creditcard),
|
|
285
|
-
testmode: organization.privateMeta.useTestPayments ?? STAMHOOFD.environment
|
|
290
|
+
testmode: organization.privateMeta.useTestPayments ?? STAMHOOFD.environment !== 'production',
|
|
286
291
|
profileId,
|
|
287
292
|
description,
|
|
288
293
|
redirectUrl,
|
|
@@ -291,54 +296,58 @@ export class PlaceOrderEndpoint extends Endpoint<Params, Query, Body, ResponseBo
|
|
|
291
296
|
order: order.id,
|
|
292
297
|
organization: organization.id,
|
|
293
298
|
webshop: webshop.id,
|
|
294
|
-
payment: payment.id
|
|
299
|
+
payment: payment.id,
|
|
295
300
|
},
|
|
296
301
|
});
|
|
297
|
-
console.log(molliePayment)
|
|
298
|
-
paymentUrl = molliePayment.getCheckoutUrl()
|
|
302
|
+
console.log(molliePayment);
|
|
303
|
+
paymentUrl = molliePayment.getCheckoutUrl();
|
|
299
304
|
|
|
300
305
|
// Save payment
|
|
301
|
-
const dbPayment = new MolliePayment()
|
|
302
|
-
dbPayment.paymentId = payment.id
|
|
303
|
-
dbPayment.mollieId = molliePayment.id
|
|
306
|
+
const dbPayment = new MolliePayment();
|
|
307
|
+
dbPayment.paymentId = payment.id;
|
|
308
|
+
dbPayment.mollieId = molliePayment.id;
|
|
304
309
|
await dbPayment.save();
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
|
|
310
|
+
}
|
|
311
|
+
else if (payment.provider == PaymentProvider.Payconiq) {
|
|
312
|
+
paymentUrl = await PayconiqPayment.createPayment(payment, organization, description, redirectUrl, exchangeUrl);
|
|
313
|
+
}
|
|
314
|
+
else if (payment.provider == PaymentProvider.Buckaroo) {
|
|
308
315
|
// Increase request timeout because buckaroo is super slow
|
|
309
|
-
request.request.request?.setTimeout(60 * 1000)
|
|
310
|
-
const buckaroo = new BuckarooHelper(organization.privateMeta?.buckarooSettings?.key ??
|
|
311
|
-
const ip = request.request.getIP()
|
|
312
|
-
paymentUrl = await buckaroo.createPayment(payment, ip, description, redirectUrl, exchangeUrl)
|
|
313
|
-
await payment.save()
|
|
316
|
+
request.request.request?.setTimeout(60 * 1000);
|
|
317
|
+
const buckaroo = new BuckarooHelper(organization.privateMeta?.buckarooSettings?.key ?? '', organization.privateMeta?.buckarooSettings?.secret ?? '', organization.privateMeta.useTestPayments ?? STAMHOOFD.environment !== 'production');
|
|
318
|
+
const ip = request.request.getIP();
|
|
319
|
+
paymentUrl = await buckaroo.createPayment(payment, ip, description, redirectUrl, exchangeUrl);
|
|
320
|
+
await payment.save();
|
|
314
321
|
|
|
315
322
|
// TypeScript doesn't understand that the status can change and isn't a const....
|
|
316
323
|
if ((payment.status as any) === PaymentStatus.Failed) {
|
|
317
324
|
throw new SimpleError({
|
|
318
|
-
code:
|
|
319
|
-
message:
|
|
320
|
-
})
|
|
325
|
+
code: 'payment_failed',
|
|
326
|
+
message: 'Betaling via ' + PaymentMethodHelper.getName(payment.method) + ' is onbeschikbaar',
|
|
327
|
+
});
|
|
321
328
|
}
|
|
322
|
-
}
|
|
323
|
-
|
|
329
|
+
}
|
|
330
|
+
else {
|
|
331
|
+
throw new Error('Unknown payment provider');
|
|
324
332
|
}
|
|
325
333
|
}
|
|
326
334
|
|
|
327
335
|
return new Response(OrderResponse.create({
|
|
328
336
|
paymentUrl: paymentUrl,
|
|
329
|
-
order: OrderStruct.create({...order, payment: PaymentStruct.create(payment) })
|
|
337
|
+
order: OrderStruct.create({ ...order, payment: PaymentStruct.create(payment) }),
|
|
330
338
|
}));
|
|
331
339
|
}
|
|
332
|
-
}
|
|
340
|
+
}
|
|
341
|
+
catch (e) {
|
|
333
342
|
// Mark order as failed to release stock
|
|
334
343
|
if (order) {
|
|
335
|
-
await order.deleteOrderBecauseOfCreationError()
|
|
344
|
+
await order.deleteOrderBecauseOfCreationError();
|
|
336
345
|
}
|
|
337
346
|
throw e;
|
|
338
347
|
}
|
|
339
|
-
|
|
348
|
+
|
|
340
349
|
return new Response(OrderResponse.create({
|
|
341
|
-
order: order.getStructureWithoutPayment()
|
|
350
|
+
order: order.getStructureWithoutPayment(),
|
|
342
351
|
}));
|
|
343
352
|
}
|
|
344
353
|
}
|