@sixtyninecommerce/admin 0.10.0 → 0.11.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/README.md +4347 -171
- package/dist/catalog/assets.d.ts +120 -8
- package/dist/catalog/assets.js +98 -12
- package/dist/catalog/collections.d.ts +279 -14
- package/dist/catalog/collections.js +246 -15
- package/dist/catalog/index.d.ts +9 -2
- package/dist/catalog/index.js +4 -0
- package/dist/catalog/products.d.ts +159 -19
- package/dist/catalog/products.js +88 -13
- package/dist/catalog/properties.d.ts +102 -14
- package/dist/catalog/properties.js +13 -0
- package/dist/catalog/recommendations.d.ts +261 -0
- package/dist/catalog/recommendations.js +145 -0
- package/dist/catalog/reviews.d.ts +368 -0
- package/dist/catalog/reviews.js +318 -0
- package/dist/catalog/types.d.ts +17 -1
- package/dist/catalog/types.js +10 -0
- package/dist/catalog/variant-find.d.ts +136 -0
- package/dist/catalog/variant-find.js +239 -0
- package/dist/catalog/variants.d.ts +233 -26
- package/dist/catalog/variants.js +125 -7
- package/dist/catalog/visibility.d.ts +20 -5
- package/dist/catalog/visibility.js +19 -1
- package/dist/client.d.ts +95 -9
- package/dist/client.js +35 -7
- package/dist/content/assets.d.ts +286 -0
- package/dist/content/assets.js +181 -0
- package/dist/content/items.d.ts +269 -0
- package/dist/content/items.js +170 -0
- package/dist/content/types.d.ts +282 -0
- package/dist/content/types.js +100 -0
- package/dist/customers/age-verification.d.ts +66 -0
- package/dist/customers/age-verification.js +79 -0
- package/dist/customers/credit.d.ts +263 -0
- package/dist/customers/credit.js +244 -0
- package/dist/customers/delivery-preferences.d.ts +120 -0
- package/dist/customers/delivery-preferences.js +97 -0
- package/dist/customers/groups.d.ts +207 -0
- package/dist/customers/groups.js +438 -0
- package/dist/customers/index.d.ts +447 -37
- package/dist/customers/index.js +313 -40
- package/dist/customers/invitation-status.d.ts +57 -0
- package/dist/customers/invitation-status.js +21 -0
- package/dist/customers/notes.d.ts +67 -0
- package/dist/customers/notes.js +51 -0
- package/dist/customers/notification-recipients.d.ts +97 -0
- package/dist/customers/notification-recipients.js +84 -0
- package/dist/customers/saved-lists.d.ts +42 -0
- package/dist/customers/saved-lists.js +61 -0
- package/dist/customers/vat.d.ts +83 -0
- package/dist/customers/vat.js +46 -0
- package/dist/customers/wire.d.ts +20 -0
- package/dist/customers/wire.js +35 -0
- package/dist/documents/ar.d.ts +307 -0
- package/dist/documents/ar.js +254 -0
- package/dist/documents/index.d.ts +731 -21
- package/dist/documents/index.js +436 -24
- package/dist/documents/pdf.d.ts +2 -0
- package/dist/documents/pdf.js +11 -0
- package/dist/fulfillments/create.d.ts +167 -0
- package/dist/fulfillments/create.js +216 -0
- package/dist/fulfillments/index.d.ts +44 -10
- package/dist/fulfillments/index.js +11 -2
- package/dist/fulfillments/payment-policy.d.ts +64 -0
- package/dist/fulfillments/payment-policy.js +140 -0
- package/dist/fulfillments/warehouse.d.ts +724 -0
- package/dist/fulfillments/warehouse.js +914 -0
- package/dist/geo/index.d.ts +119 -0
- package/dist/geo/index.js +107 -0
- package/dist/index.d.ts +123 -35
- package/dist/index.js +45 -12
- package/dist/integrations/afas-actions.d.ts +234 -0
- package/dist/integrations/afas-actions.js +310 -0
- package/dist/integrations/afas-types.d.ts +483 -0
- package/dist/integrations/afas-types.js +5 -0
- package/dist/integrations/afas.d.ts +234 -0
- package/dist/integrations/afas.js +290 -0
- package/dist/integrations/connections.d.ts +103 -0
- package/dist/integrations/connections.js +55 -0
- package/dist/integrations/esp.d.ts +313 -0
- package/dist/integrations/esp.js +169 -0
- package/dist/integrations/exact-online-types.d.ts +423 -0
- package/dist/integrations/exact-online-types.js +6 -0
- package/dist/integrations/exact-online.d.ts +248 -0
- package/dist/integrations/exact-online.js +376 -0
- package/dist/integrations/index.d.ts +29 -3
- package/dist/integrations/index.js +18 -3
- package/dist/integrations/pipeline-keys.d.ts +13 -0
- package/dist/integrations/pipeline-keys.js +22 -0
- package/dist/integrations/pipelines.d.ts +15 -14
- package/dist/integrations/pipelines.js +6 -22
- package/dist/integrations/types.d.ts +146 -0
- package/dist/locations/index.d.ts +66 -0
- package/dist/locations/index.js +31 -0
- package/dist/meta/index.d.ts +162 -0
- package/dist/orders/cancel-with-money.d.ts +227 -0
- package/dist/orders/cancel-with-money.js +153 -0
- package/dist/orders/commit-edit.d.ts +7 -1
- package/dist/orders/commit-edit.js +5 -1
- package/dist/orders/drafts.d.ts +800 -0
- package/dist/orders/drafts.js +771 -0
- package/dist/orders/fields.d.ts +245 -0
- package/dist/orders/fields.js +188 -0
- package/dist/orders/get.d.ts +29 -19
- package/dist/orders/get.js +17 -8
- package/dist/orders/index.d.ts +49 -9
- package/dist/orders/index.js +22 -2
- package/dist/orders/lifecycle.d.ts +128 -0
- package/dist/orders/lifecycle.js +158 -0
- package/dist/orders/line-price-preview.d.ts +7 -2
- package/dist/orders/list.d.ts +222 -0
- package/dist/orders/list.js +377 -0
- package/dist/orders/manual-pricing.d.ts +5 -0
- package/dist/orders/order-entry.d.ts +20 -7
- package/dist/orders/plan-edit.d.ts +1 -1
- package/dist/orders/plan-edit.js +4 -1
- package/dist/orders/settings.d.ts +201 -0
- package/dist/orders/settings.js +325 -0
- package/dist/orders/status.d.ts +159 -13
- package/dist/orders/status.js +21 -0
- package/dist/orders/surcharges.d.ts +8 -1
- package/dist/orders/surcharges.js +3 -2
- package/dist/payments/account-credit.d.ts +30 -0
- package/dist/payments/account-credit.js +19 -0
- package/dist/payments/ar.d.ts +292 -0
- package/dist/payments/ar.js +223 -0
- package/dist/payments/connected-account.d.ts +47 -0
- package/dist/payments/connected-account.js +61 -0
- package/dist/payments/credit-noted-fields.d.ts +12 -0
- package/dist/payments/credit-noted-fields.js +37 -0
- package/dist/payments/index.d.ts +257 -11
- package/dist/payments/index.js +131 -1
- package/dist/payments/methods.d.ts +303 -8
- package/dist/payments/methods.js +337 -7
- package/dist/payments/mollie-methods.d.ts +159 -0
- package/dist/payments/mollie-methods.js +141 -0
- package/dist/payments/payment-links.d.ts +180 -0
- package/dist/payments/payment-links.js +97 -0
- package/dist/payments/provider-keys.d.ts +150 -0
- package/dist/payments/provider-keys.js +118 -0
- package/dist/payments/providers.d.ts +86 -11
- package/dist/payments/providers.js +29 -0
- package/dist/payments/requests.d.ts +144 -0
- package/dist/payments/requests.js +92 -0
- package/dist/payments/store-credit-fields.d.ts +15 -0
- package/dist/payments/store-credit-fields.js +51 -0
- package/dist/pickups/index.d.ts +104 -0
- package/dist/pickups/index.js +105 -0
- package/dist/platform/channels.d.ts +132 -0
- package/dist/platform/channels.js +128 -0
- package/dist/platform/geo.d.ts +123 -0
- package/dist/platform/geo.js +144 -0
- package/dist/platform/tax.d.ts +154 -0
- package/dist/platform/tax.js +139 -0
- package/dist/pos/anomalies.d.ts +158 -0
- package/dist/pos/anomalies.js +64 -0
- package/dist/pos/assisted-selling.d.ts +79 -0
- package/dist/pos/assisted-selling.js +38 -0
- package/dist/pos/exchanges.d.ts +103 -0
- package/dist/pos/exchanges.js +22 -0
- package/dist/pos/gift-cards.d.ts +135 -0
- package/dist/pos/gift-cards.js +47 -0
- package/dist/pos/index.d.ts +2125 -32
- package/dist/pos/index.js +742 -4
- package/dist/pos/no-receipt.d.ts +94 -0
- package/dist/pos/no-receipt.js +25 -0
- package/dist/pos/offline-sales.d.ts +187 -0
- package/dist/pos/offline-sales.js +116 -0
- package/dist/pos/pay-by-link.d.ts +143 -0
- package/dist/pos/pay-by-link.js +57 -0
- package/dist/pos/quick-keys.d.ts +103 -0
- package/dist/pos/quick-keys.js +45 -0
- package/dist/pos/reports.d.ts +360 -0
- package/dist/pos/reports.js +62 -0
- package/dist/pos/returns.d.ts +217 -0
- package/dist/pos/returns.js +53 -0
- package/dist/pricing/bulk-coupons.d.ts +139 -0
- package/dist/pricing/bulk-coupons.js +112 -0
- package/dist/pricing/index.d.ts +174 -4
- package/dist/pricing/index.js +174 -1
- package/dist/pricing/price-lists.d.ts +604 -0
- package/dist/pricing/price-lists.js +600 -0
- package/dist/purchasing/alerts.d.ts +89 -0
- package/dist/purchasing/alerts.js +62 -0
- package/dist/purchasing/cost.d.ts +110 -0
- package/dist/purchasing/cost.js +86 -0
- package/dist/purchasing/index.d.ts +36 -0
- package/dist/purchasing/index.js +16 -0
- package/dist/purchasing/purchase-orders.d.ts +548 -0
- package/dist/purchasing/purchase-orders.js +491 -0
- package/dist/purchasing/replenishment.d.ts +281 -0
- package/dist/purchasing/replenishment.js +240 -0
- package/dist/purchasing/settings.d.ts +152 -0
- package/dist/purchasing/settings.js +181 -0
- package/dist/purchasing/suppliers.d.ts +476 -0
- package/dist/purchasing/suppliers.js +438 -0
- package/dist/quotes/index.d.ts +501 -0
- package/dist/quotes/index.js +439 -0
- package/dist/reports/index.d.ts +71 -8
- package/dist/reports/index.js +74 -11
- package/dist/returns/index.d.ts +614 -21
- package/dist/returns/index.js +695 -11
- package/dist/search/index.d.ts +76 -1
- package/dist/search/index.js +63 -0
- package/dist/shipping/definitions.d.ts +29 -0
- package/dist/shipping/definitions.js +47 -0
- package/dist/shipping/fulfillment-profiles.d.ts +174 -0
- package/dist/shipping/fulfillment-profiles.js +104 -0
- package/dist/shipping/hendriks.d.ts +97 -0
- package/dist/shipping/hendriks.js +50 -0
- package/dist/shipping/index.d.ts +48 -0
- package/dist/shipping/index.js +25 -0
- package/dist/shipping/methods.d.ts +198 -0
- package/dist/shipping/methods.js +240 -0
- package/dist/shipping/myparcel.d.ts +254 -0
- package/dist/shipping/myparcel.js +178 -0
- package/dist/shipping/parcel-count-suggestion.d.ts +2 -0
- package/dist/shipping/parcel-rule.d.ts +6 -5
- package/dist/shipping/parcel-rule.js +21 -23
- package/dist/shipping/rate-tables.d.ts +179 -0
- package/dist/shipping/rate-tables.js +184 -0
- package/dist/stock/index.d.ts +10 -3
- package/dist/stock/index.js +3 -0
- package/dist/stock/locations.d.ts +144 -0
- package/dist/stock/locations.js +168 -0
- package/dist/stock/transfers.d.ts +216 -43
- package/dist/stock/transfers.js +140 -13
- package/dist/stored-value/index.d.ts +214 -4
- package/dist/stored-value/index.js +152 -0
- package/dist/subscriptions/index.d.ts +682 -0
- package/dist/subscriptions/index.js +815 -0
- package/dist/tax/index.d.ts +76 -1
- package/dist/tax/index.js +50 -0
- package/dist/tenant/email-style.d.ts +102 -0
- package/dist/tenant/email-style.js +72 -0
- package/dist/tenant/email-templates.d.ts +66 -0
- package/dist/tenant/email-templates.js +54 -0
- package/dist/tenant/notifications.d.ts +23 -17
- package/dist/tenant/settings-sources.d.ts +1 -1
- package/dist/tenant/time-zone.d.ts +17 -0
- package/dist/tenant/time-zone.js +11 -0
- package/dist/types.d.ts +50 -3
- package/dist/users/index.d.ts +3 -0
- package/dist/users/index.js +2 -0
- package/dist/users/warehouses.d.ts +50 -0
- package/dist/users/warehouses.js +51 -0
- package/package.json +2 -2
package/dist/payments/methods.js
CHANGED
|
@@ -1,33 +1,363 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ConflictError, createPage, ValidationError, } from '@sixtyninecommerce/core';
|
|
2
|
+
import { assertDeleted, fieldOf, vendureListPage, } from '../catalog/types.js';
|
|
3
|
+
import { createMollieMethodsModule } from './mollie-methods.js';
|
|
4
|
+
import { createProviderKeysModule } from './provider-keys.js';
|
|
2
5
|
/** A store has a handful; one page holds them. */
|
|
3
6
|
const DEFAULT_PAGE_SIZE = 100;
|
|
7
|
+
const OPERATION_FIELDS = /* GraphQL */ `
|
|
8
|
+
code
|
|
9
|
+
args {
|
|
10
|
+
name
|
|
11
|
+
value
|
|
12
|
+
}
|
|
13
|
+
`;
|
|
14
|
+
/** One selection for the list and the single read, so both answer the same {@link PaymentMethod}. */
|
|
15
|
+
const METHOD_FIELDS = /* GraphQL */ `
|
|
16
|
+
id
|
|
17
|
+
createdAt
|
|
18
|
+
updatedAt
|
|
19
|
+
code
|
|
20
|
+
name
|
|
21
|
+
description
|
|
22
|
+
enabled
|
|
23
|
+
handler { ${OPERATION_FIELDS} }
|
|
24
|
+
checker { ${OPERATION_FIELDS} }
|
|
25
|
+
translations {
|
|
26
|
+
id
|
|
27
|
+
languageCode
|
|
28
|
+
name
|
|
29
|
+
description
|
|
30
|
+
}
|
|
31
|
+
customFields {
|
|
32
|
+
isNetTermsCredit
|
|
33
|
+
netTermsStaffAnyCustomer
|
|
34
|
+
enabledInStorefront
|
|
35
|
+
}
|
|
36
|
+
`;
|
|
4
37
|
export const PAYMENT_METHODS_QUERY = /* GraphQL */ `
|
|
5
38
|
query StorePaymentMethods($options: PaymentMethodListOptions) {
|
|
6
39
|
paymentMethods(options: $options) {
|
|
40
|
+
items { ${METHOD_FIELDS} }
|
|
41
|
+
totalItems
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
`;
|
|
45
|
+
export const PAYMENT_METHOD_QUERY = /* GraphQL */ `
|
|
46
|
+
query StorePaymentMethod($id: ID!) {
|
|
47
|
+
paymentMethod(id: $id) { ${METHOD_FIELDS} }
|
|
48
|
+
}
|
|
49
|
+
`;
|
|
50
|
+
const DEFINITION_FIELDS = /* GraphQL */ `
|
|
51
|
+
code
|
|
52
|
+
description
|
|
53
|
+
args {
|
|
54
|
+
name
|
|
55
|
+
type
|
|
56
|
+
list
|
|
57
|
+
required
|
|
58
|
+
defaultValue
|
|
59
|
+
label
|
|
60
|
+
description
|
|
61
|
+
ui
|
|
62
|
+
}
|
|
63
|
+
`;
|
|
64
|
+
export const PAYMENT_METHOD_HANDLERS_QUERY = /* GraphQL */ `
|
|
65
|
+
query PaymentMethodHandlers {
|
|
66
|
+
paymentMethodHandlers { ${DEFINITION_FIELDS} }
|
|
67
|
+
}
|
|
68
|
+
`;
|
|
69
|
+
export const PAYMENT_METHOD_CHECKERS_QUERY = /* GraphQL */ `
|
|
70
|
+
query PaymentMethodEligibilityCheckers {
|
|
71
|
+
paymentMethodEligibilityCheckers { ${DEFINITION_FIELDS} }
|
|
72
|
+
}
|
|
73
|
+
`;
|
|
74
|
+
export const PAYMENT_METHOD_CREDENTIAL_PATH_QUERY = /* GraphQL */ `
|
|
75
|
+
query PaymentMethodCredentialPath($code: String!) {
|
|
76
|
+
paymentMethods(options: { filter: { code: { eq: $code } }, take: 1 }) {
|
|
7
77
|
items {
|
|
8
|
-
id
|
|
9
78
|
code
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
handler {
|
|
13
|
-
code
|
|
79
|
+
customFields {
|
|
80
|
+
mollieCredentialPath
|
|
14
81
|
}
|
|
15
82
|
}
|
|
16
|
-
totalItems
|
|
17
83
|
}
|
|
18
84
|
}
|
|
19
85
|
`;
|
|
86
|
+
export const SET_PAYMENT_METHOD_CREDENTIAL_PATH_MUTATION = /* GraphQL */ `
|
|
87
|
+
mutation SetPaymentMethodCredentialPath(
|
|
88
|
+
$paymentMethodCode: String!
|
|
89
|
+
$path: PaymentMethodCredentialPath!
|
|
90
|
+
) {
|
|
91
|
+
setPaymentMethodCredentialPath(paymentMethodCode: $paymentMethodCode, path: $path) {
|
|
92
|
+
paymentMethodCode
|
|
93
|
+
credentialPath
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
`;
|
|
97
|
+
export const CREATE_PAYMENT_METHOD_MUTATION = /* GraphQL */ `
|
|
98
|
+
mutation CreateStorePaymentMethod($input: CreatePaymentMethodInput!) {
|
|
99
|
+
createPaymentMethod(input: $input) { ${METHOD_FIELDS} }
|
|
100
|
+
}
|
|
101
|
+
`;
|
|
102
|
+
export const UPDATE_PAYMENT_METHOD_MUTATION = /* GraphQL */ `
|
|
103
|
+
mutation UpdateStorePaymentMethod($input: UpdatePaymentMethodInput!) {
|
|
104
|
+
updatePaymentMethod(input: $input) { ${METHOD_FIELDS} }
|
|
105
|
+
}
|
|
106
|
+
`;
|
|
107
|
+
// `force: false`, written into the document: in the default channel `true` deletes a method
|
|
108
|
+
// other stores still hold, and no caller of this SDK may ask for that.
|
|
109
|
+
export const DELETE_PAYMENT_METHOD_MUTATION = /* GraphQL */ `
|
|
110
|
+
mutation DeleteStorePaymentMethod($id: ID!) {
|
|
111
|
+
deletePaymentMethod(id: $id, force: false) {
|
|
112
|
+
result
|
|
113
|
+
message
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
`;
|
|
117
|
+
export const DELETE_PAYMENT_METHODS_MUTATION = /* GraphQL */ `
|
|
118
|
+
mutation DeleteStorePaymentMethods($ids: [ID!]!) {
|
|
119
|
+
deletePaymentMethods(ids: $ids, force: false) {
|
|
120
|
+
result
|
|
121
|
+
message
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
`;
|
|
125
|
+
export const ASSIGN_PAYMENT_METHODS_TO_CHANNEL_MUTATION = /* GraphQL */ `
|
|
126
|
+
mutation AssignPaymentMethodsToStore($input: AssignPaymentMethodsToChannelInput!) {
|
|
127
|
+
assignPaymentMethodsToChannel(input: $input) { ${METHOD_FIELDS} }
|
|
128
|
+
}
|
|
129
|
+
`;
|
|
130
|
+
export const REMOVE_PAYMENT_METHODS_FROM_CHANNEL_MUTATION = /* GraphQL */ `
|
|
131
|
+
mutation RemovePaymentMethodsFromStore($input: RemovePaymentMethodsFromChannelInput!) {
|
|
132
|
+
removePaymentMethodsFromChannel(input: $input) { ${METHOD_FIELDS} }
|
|
133
|
+
}
|
|
134
|
+
`;
|
|
135
|
+
const invalidInput = (message) => new ValidationError({
|
|
136
|
+
code: 'INVALID_PAYMENT_METHOD_INPUT',
|
|
137
|
+
message,
|
|
138
|
+
status: 400,
|
|
139
|
+
service: 'vendure',
|
|
140
|
+
});
|
|
141
|
+
const isObject = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
142
|
+
const isIdList = (value) => Array.isArray(value) && value.every((id) => typeof id === 'string' && id !== '');
|
|
143
|
+
const FLAGS = ['isNetTermsCredit', 'netTermsStaffAnyCustomer', 'enabledInStorefront'];
|
|
144
|
+
/** A handler or checker as the engine takes it, checked here so a wrong shape never leaves. */
|
|
145
|
+
function operationInput(value, what) {
|
|
146
|
+
if (!isObject(value) || typeof value.code !== 'string' || value.code === '') {
|
|
147
|
+
throw invalidInput(`${what} needs a code.`);
|
|
148
|
+
}
|
|
149
|
+
const args = value.arguments;
|
|
150
|
+
if (!Array.isArray(args) ||
|
|
151
|
+
!args.every((arg) => isObject(arg) && typeof arg.name === 'string' && typeof arg.value === 'string')) {
|
|
152
|
+
throw invalidInput(`${what}.arguments must be a list of { name, value } strings (a list or a boolean JSON-encoded).`);
|
|
153
|
+
}
|
|
154
|
+
return {
|
|
155
|
+
code: value.code,
|
|
156
|
+
arguments: args.map((arg) => ({ name: String(arg.name), value: String(arg.value) })),
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
function translationsInput(value) {
|
|
160
|
+
if (!Array.isArray(value) ||
|
|
161
|
+
!value.every((row) => isObject(row) &&
|
|
162
|
+
typeof row.languageCode === 'string' &&
|
|
163
|
+
row.languageCode !== '' &&
|
|
164
|
+
typeof row.name === 'string' &&
|
|
165
|
+
(row.description === undefined || typeof row.description === 'string'))) {
|
|
166
|
+
throw invalidInput('translations must be a list of { languageCode, name, description? } with strings.');
|
|
167
|
+
}
|
|
168
|
+
return value.map((row) => ({
|
|
169
|
+
languageCode: String(row.languageCode),
|
|
170
|
+
name: String(row.name),
|
|
171
|
+
description: typeof row.description === 'string' ? row.description : '',
|
|
172
|
+
}));
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* The fields both writes share, in the engine's shape: the three flags under `customFields`,
|
|
176
|
+
* the checker kept as null (which an update reads as "take it away").
|
|
177
|
+
*/
|
|
178
|
+
function sharedInput(input) {
|
|
179
|
+
const out = {};
|
|
180
|
+
if (input.code !== undefined) {
|
|
181
|
+
if (typeof input.code !== 'string')
|
|
182
|
+
throw invalidInput('code must be a string.');
|
|
183
|
+
out.code = input.code;
|
|
184
|
+
}
|
|
185
|
+
if (input.enabled !== undefined) {
|
|
186
|
+
if (typeof input.enabled !== 'boolean')
|
|
187
|
+
throw invalidInput('enabled must be true or false.');
|
|
188
|
+
out.enabled = input.enabled;
|
|
189
|
+
}
|
|
190
|
+
if (input.handler !== undefined)
|
|
191
|
+
out.handler = operationInput(input.handler, 'handler');
|
|
192
|
+
if (input.checker === null)
|
|
193
|
+
out.checker = null;
|
|
194
|
+
else if (input.checker !== undefined)
|
|
195
|
+
out.checker = operationInput(input.checker, 'checker');
|
|
196
|
+
if (input.translations !== undefined)
|
|
197
|
+
out.translations = translationsInput(input.translations);
|
|
198
|
+
const customFields = {};
|
|
199
|
+
for (const flag of FLAGS) {
|
|
200
|
+
const value = input[flag];
|
|
201
|
+
if (value === undefined)
|
|
202
|
+
continue;
|
|
203
|
+
if (typeof value !== 'boolean')
|
|
204
|
+
throw invalidInput(`${flag} must be true or false.`);
|
|
205
|
+
customFields[flag] = value;
|
|
206
|
+
}
|
|
207
|
+
if (Object.keys(customFields).length > 0)
|
|
208
|
+
out.customFields = customFields;
|
|
209
|
+
return out;
|
|
210
|
+
}
|
|
211
|
+
function assignmentInput(ids, channelId) {
|
|
212
|
+
if (!isIdList(ids))
|
|
213
|
+
throw invalidInput('ids must be a list of payment method ids.');
|
|
214
|
+
if (typeof channelId !== 'string' || channelId === '') {
|
|
215
|
+
throw invalidInput("channelId must be the receiving store's channel id.");
|
|
216
|
+
}
|
|
217
|
+
return [...ids];
|
|
218
|
+
}
|
|
219
|
+
const asPath = (value) => value === 'connect' ? 'connect' : 'api_key';
|
|
20
220
|
const toMethod = (method) => ({
|
|
21
221
|
id: method.id,
|
|
22
222
|
code: method.code,
|
|
23
223
|
name: method.name,
|
|
224
|
+
description: method.description,
|
|
24
225
|
enabled: method.enabled,
|
|
25
226
|
handlerCode: method.handler.code,
|
|
227
|
+
// As answered: the engine has already masked each secret argument for this caller.
|
|
228
|
+
handler: method.handler,
|
|
229
|
+
checker: method.checker ?? null,
|
|
230
|
+
translations: method.translations,
|
|
231
|
+
// A flag the engine did not answer reads as its column's default: the two net-terms flags
|
|
232
|
+
// off, the storefront flag on.
|
|
233
|
+
isNetTermsCredit: method.customFields?.isNetTermsCredit === true,
|
|
234
|
+
netTermsStaffAnyCustomer: method.customFields?.netTermsStaffAnyCustomer === true,
|
|
235
|
+
enabledInStorefront: method.customFields?.enabledInStorefront !== false,
|
|
236
|
+
createdAt: method.createdAt,
|
|
237
|
+
updatedAt: method.updatedAt,
|
|
26
238
|
});
|
|
239
|
+
/** A complete array behind the SDK's page shape: the engine lists every definition at once. */
|
|
240
|
+
function wholeList(items, what) {
|
|
241
|
+
return createPage(items, { nextCursor: null, hasNext: false, total: items.length }, () => {
|
|
242
|
+
// Unreachable while `hasNext` is false: `Page.next()` short-circuits.
|
|
243
|
+
throw new Error(`${what} returns a complete list; there is no next page`);
|
|
244
|
+
});
|
|
245
|
+
}
|
|
27
246
|
export function createPaymentMethodsModule(transport) {
|
|
28
247
|
return {
|
|
248
|
+
providerKeys: createProviderKeysModule(transport),
|
|
249
|
+
mollie: createMollieMethodsModule(transport),
|
|
29
250
|
list(options) {
|
|
30
251
|
return vendureListPage(transport, PAYMENT_METHODS_QUERY, 'paymentMethods', (skip, take) => ({ options: { skip, take } }), { ...options, limit: options?.limit ?? DEFAULT_PAGE_SIZE }, toMethod);
|
|
31
252
|
},
|
|
253
|
+
async get(id, options) {
|
|
254
|
+
const method = await fieldOf(transport, PAYMENT_METHOD_QUERY, 'paymentMethod', { id }, options);
|
|
255
|
+
return method ? toMethod(method) : null;
|
|
256
|
+
},
|
|
257
|
+
async handlers(options) {
|
|
258
|
+
return wholeList(await fieldOf(transport, PAYMENT_METHOD_HANDLERS_QUERY, 'paymentMethodHandlers', {}, options), 'paymentMethodHandlers');
|
|
259
|
+
},
|
|
260
|
+
async checkers(options) {
|
|
261
|
+
return wholeList(await fieldOf(transport, PAYMENT_METHOD_CHECKERS_QUERY, 'paymentMethodEligibilityCheckers', {}, options), 'paymentMethodEligibilityCheckers');
|
|
262
|
+
},
|
|
263
|
+
async credentialPath(paymentMethodCode, options) {
|
|
264
|
+
const data = await transport.graphql({
|
|
265
|
+
api: 'admin',
|
|
266
|
+
query: PAYMENT_METHOD_CREDENTIAL_PATH_QUERY,
|
|
267
|
+
variables: { code: paymentMethodCode },
|
|
268
|
+
}, options);
|
|
269
|
+
// `eq` is not guaranteed case-sensitive on every driver: the code is matched here too.
|
|
270
|
+
const method = data.paymentMethods.items.find((item) => item.code === paymentMethodCode);
|
|
271
|
+
return method ? asPath(method.customFields?.mollieCredentialPath) : null;
|
|
272
|
+
},
|
|
273
|
+
async setCredentialPath(paymentMethodCode, path, options) {
|
|
274
|
+
const data = await transport.graphql({
|
|
275
|
+
api: 'admin',
|
|
276
|
+
query: SET_PAYMENT_METHOD_CREDENTIAL_PATH_MUTATION,
|
|
277
|
+
variables: { paymentMethodCode, path },
|
|
278
|
+
}, options);
|
|
279
|
+
return {
|
|
280
|
+
paymentMethodCode: data.setPaymentMethodCredentialPath.paymentMethodCode,
|
|
281
|
+
credentialPath: asPath(data.setPaymentMethodCredentialPath.credentialPath),
|
|
282
|
+
};
|
|
283
|
+
},
|
|
284
|
+
async create(input, options) {
|
|
285
|
+
if (!isObject(input))
|
|
286
|
+
throw invalidInput('A new payment method must be an object.');
|
|
287
|
+
if (typeof input.code !== 'string')
|
|
288
|
+
throw invalidInput('A payment method needs a code.');
|
|
289
|
+
if (typeof input.enabled !== 'boolean') {
|
|
290
|
+
throw invalidInput('A new payment method says whether it is enabled.');
|
|
291
|
+
}
|
|
292
|
+
if (input.handler === undefined)
|
|
293
|
+
throw invalidInput('A payment method needs a handler.');
|
|
294
|
+
if (input.translations === undefined) {
|
|
295
|
+
throw invalidInput('A payment method needs its name in at least one language.');
|
|
296
|
+
}
|
|
297
|
+
const wireInput = sharedInput(input);
|
|
298
|
+
// Core's create takes no null checker: "none" is leaving it out.
|
|
299
|
+
if (wireInput.checker === null)
|
|
300
|
+
delete wireInput.checker;
|
|
301
|
+
return toMethod(await fieldOf(transport, CREATE_PAYMENT_METHOD_MUTATION, 'createPaymentMethod', { input: wireInput }, options));
|
|
302
|
+
},
|
|
303
|
+
async update(id, patch, options) {
|
|
304
|
+
if (typeof id !== 'string' || id === '')
|
|
305
|
+
throw invalidInput('id must be a payment method id.');
|
|
306
|
+
if (!isObject(patch))
|
|
307
|
+
throw invalidInput('The change to a payment method must be an object.');
|
|
308
|
+
return toMethod(await fieldOf(transport, UPDATE_PAYMENT_METHOD_MUTATION, 'updatePaymentMethod', { input: { id, ...sharedInput(patch) } }, options));
|
|
309
|
+
},
|
|
310
|
+
async delete(id, options) {
|
|
311
|
+
if (typeof id !== 'string' || id === '')
|
|
312
|
+
throw invalidInput('id must be a payment method id.');
|
|
313
|
+
assertDeleted('PAYMENT_METHOD_NOT_DELETED', [
|
|
314
|
+
await fieldOf(transport, DELETE_PAYMENT_METHOD_MUTATION, 'deletePaymentMethod', { id }, options),
|
|
315
|
+
]);
|
|
316
|
+
},
|
|
317
|
+
async deleteMany(ids, options) {
|
|
318
|
+
if (!isIdList(ids))
|
|
319
|
+
throw invalidInput('ids must be a list of payment method ids.');
|
|
320
|
+
if (ids.length === 0)
|
|
321
|
+
return;
|
|
322
|
+
const responses = await fieldOf(transport, DELETE_PAYMENT_METHODS_MUTATION, 'deletePaymentMethods', { ids: [...ids] }, options);
|
|
323
|
+
// One answer per id, in the order sent. A missing answer is not a removal.
|
|
324
|
+
const kept = ids.flatMap((id, index) => {
|
|
325
|
+
const response = Array.isArray(responses) ? responses[index] : undefined;
|
|
326
|
+
return response?.result === 'DELETED'
|
|
327
|
+
? []
|
|
328
|
+
: [{ id, index, reason: response?.message ?? 'The server gave no reason.' }];
|
|
329
|
+
});
|
|
330
|
+
if (kept.length === 0)
|
|
331
|
+
return;
|
|
332
|
+
// Answered at HTTP 200, so the transport never throws for it: the ids not named here WERE
|
|
333
|
+
// removed.
|
|
334
|
+
throw new ConflictError({
|
|
335
|
+
code: 'PAYMENT_METHOD_NOT_DELETED',
|
|
336
|
+
message: kept.length === ids.length
|
|
337
|
+
? `No payment method was removed: ${kept[0]?.reason ?? ''}`
|
|
338
|
+
: `${String(kept.length)} of ${String(ids.length)} payment methods were not removed (the others were): ${kept[0]?.reason ?? ''}`,
|
|
339
|
+
status: 409,
|
|
340
|
+
service: 'vendure',
|
|
341
|
+
details: kept.map(({ id, index, reason }) => ({
|
|
342
|
+
field: `ids.${String(index)}`,
|
|
343
|
+
code: 'PAYMENT_METHOD_NOT_DELETED',
|
|
344
|
+
message: `${id}: ${reason}`,
|
|
345
|
+
})),
|
|
346
|
+
});
|
|
347
|
+
},
|
|
348
|
+
async assignToStores(ids, channelId, options) {
|
|
349
|
+
const paymentMethodIds = assignmentInput(ids, channelId);
|
|
350
|
+
if (paymentMethodIds.length === 0)
|
|
351
|
+
return [];
|
|
352
|
+
const methods = await fieldOf(transport, ASSIGN_PAYMENT_METHODS_TO_CHANNEL_MUTATION, 'assignPaymentMethodsToChannel', { input: { paymentMethodIds, channelId } }, options);
|
|
353
|
+
return methods.map(toMethod);
|
|
354
|
+
},
|
|
355
|
+
async removeFromStores(ids, channelId, options) {
|
|
356
|
+
const paymentMethodIds = assignmentInput(ids, channelId);
|
|
357
|
+
if (paymentMethodIds.length === 0)
|
|
358
|
+
return [];
|
|
359
|
+
const methods = await fieldOf(transport, REMOVE_PAYMENT_METHODS_FROM_CHANNEL_MUTATION, 'removePaymentMethodsFromChannel', { input: { paymentMethodIds, channelId } }, options);
|
|
360
|
+
return methods.map(toMethod);
|
|
361
|
+
},
|
|
32
362
|
};
|
|
33
363
|
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { type Transport } from '@sixtyninecommerce/core';
|
|
2
|
+
import type { Call } from '../types.js';
|
|
3
|
+
/** Why Mollie's own answer is missing: the method has nothing to ask with, or Mollie refused. */
|
|
4
|
+
export type MollieProbeErrorKind = 'no_key' | 'auth' | 'network' | 'provider';
|
|
5
|
+
/** What went wrong asking Mollie, in the engine's classification. */
|
|
6
|
+
export interface MollieProbeError {
|
|
7
|
+
/**
|
|
8
|
+
* `no_key`: nothing to ask with (no such method in the store, not a Mollie method, no key, or
|
|
9
|
+
* a Connect-path method whose store has no Mollie account connected); `auth`: Mollie refused
|
|
10
|
+
* the key or the Connect grant; `network`: Mollie did not answer; `provider`: Mollie answered
|
|
11
|
+
* with an error. An unknown kind reads `provider`.
|
|
12
|
+
*/
|
|
13
|
+
kind: MollieProbeErrorKind;
|
|
14
|
+
/** In the engine's or Mollie's words. */
|
|
15
|
+
message: string;
|
|
16
|
+
/** Mollie's real HTTP status when it answered; null otherwise. */
|
|
17
|
+
statusCode: number | null;
|
|
18
|
+
}
|
|
19
|
+
/** One checkout method of the Mollie account, with the store's choice to hide it. */
|
|
20
|
+
export interface MollieMethod {
|
|
21
|
+
/** Mollie's method id: `ideal`, `creditcard`, `klarnapaylater`, … */
|
|
22
|
+
id: string;
|
|
23
|
+
description: string | null;
|
|
24
|
+
/** Mollie's icon for it (SVG preferred); null when Mollie gave none. */
|
|
25
|
+
imageUrl: string | null;
|
|
26
|
+
/** The store hides it at checkout (`setMethods`). */
|
|
27
|
+
hidden: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Mollie's activation status: `activated`, `pending-boarding`, `pending-review`,
|
|
30
|
+
* `pending-external` or `rejected`; null when Mollie gave none.
|
|
31
|
+
*/
|
|
32
|
+
status: string | null;
|
|
33
|
+
/** Usable now: `activated`, or no status given. */
|
|
34
|
+
available: boolean;
|
|
35
|
+
}
|
|
36
|
+
/** The method list of one Mollie payment method, in the store's checkout order. */
|
|
37
|
+
export interface MollieMethodList {
|
|
38
|
+
/**
|
|
39
|
+
* Mollie's one-off (checkout) methods merged with the saved order, hidden ones included.
|
|
40
|
+
* Mandate-only methods (SEPA `directdebit`) are never here: see `diagnose`.
|
|
41
|
+
*/
|
|
42
|
+
methods: MollieMethod[];
|
|
43
|
+
/**
|
|
44
|
+
* Why Mollie's list is missing, or null. An empty `methods` with a null `error` means Mollie
|
|
45
|
+
* answered and offers no method on this profile.
|
|
46
|
+
*/
|
|
47
|
+
error: MollieProbeError | null;
|
|
48
|
+
}
|
|
49
|
+
/** The checkout order and the hidden methods, each as Mollie's method ids. */
|
|
50
|
+
export interface SetMollieMethodsInput {
|
|
51
|
+
/** Every method id, in the order the checkout shows them. */
|
|
52
|
+
order: string[];
|
|
53
|
+
/** The method ids the checkout hides. */
|
|
54
|
+
hidden: string[];
|
|
55
|
+
}
|
|
56
|
+
/** One method of the account across Mollie's three payment sequences. */
|
|
57
|
+
export interface MollieDiagnosisMethod {
|
|
58
|
+
id: string;
|
|
59
|
+
description: string | null;
|
|
60
|
+
/** Mollie's activation status, when its list of every method gave one. */
|
|
61
|
+
status: string | null;
|
|
62
|
+
/** Offered for a regular checkout payment. */
|
|
63
|
+
oneoff: boolean;
|
|
64
|
+
/** Offered as the first payment of a recurring sequence (it creates a mandate). */
|
|
65
|
+
first: boolean;
|
|
66
|
+
/** Offered for charging an existing mandate. */
|
|
67
|
+
recurring: boolean;
|
|
68
|
+
}
|
|
69
|
+
/** SEPA Direct Debit (`directdebit`) as each probe saw it. */
|
|
70
|
+
export interface MollieDirectDebitDiagnosis {
|
|
71
|
+
availableOneoff: boolean;
|
|
72
|
+
availableFirst: boolean;
|
|
73
|
+
availableRecurring: boolean;
|
|
74
|
+
status: string | null;
|
|
75
|
+
/** What Mollie answered for `directdebit` itself: `ok`, `forbidden`, `not_found` or `error`. */
|
|
76
|
+
getProbe: string;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* The headline answer, about SEPA Direct Debit at checkout:
|
|
80
|
+
* `CHECKOUT_TILE_AVAILABLE`, `CHECKOUT_TILE_PENDING_ACTIVATION`, `MANDATE_ONLY`,
|
|
81
|
+
* `NOT_ON_ACCOUNT`, `INDETERMINATE`, `REJECTED`, `UNKNOWN_KEY_ERROR` (every probe refused, or
|
|
82
|
+
* nothing to probe with) or `UNREACHABLE`. A verdict the engine adds later is passed through.
|
|
83
|
+
*/
|
|
84
|
+
export type MollieDiagnosisVerdict = 'CHECKOUT_TILE_AVAILABLE' | 'CHECKOUT_TILE_PENDING_ACTIVATION' | 'MANDATE_ONLY' | 'NOT_ON_ACCOUNT' | 'INDETERMINATE' | 'REJECTED' | 'UNKNOWN_KEY_ERROR' | 'UNREACHABLE';
|
|
85
|
+
/** What Mollie's account offers for each payment sequence, and the verdict drawn from it. */
|
|
86
|
+
export interface MollieDiagnosis {
|
|
87
|
+
/** Every probe succeeded. */
|
|
88
|
+
ok: boolean;
|
|
89
|
+
/** From the key's prefix only (`test_`, `live_`); `unknown` without a key. */
|
|
90
|
+
keyMode: 'test' | 'live' | 'unknown';
|
|
91
|
+
/** The first probe's failure, or null. */
|
|
92
|
+
error: MollieProbeError | null;
|
|
93
|
+
methods: MollieDiagnosisMethod[];
|
|
94
|
+
directDebit: MollieDirectDebitDiagnosis;
|
|
95
|
+
verdict: MollieDiagnosisVerdict;
|
|
96
|
+
/** When the probes ran (ISO 8601, UTC). */
|
|
97
|
+
probedAt: string;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* The checkout methods a Mollie payment method offers, their order and visibility, and a
|
|
101
|
+
* diagnosis of the Mollie account (headless spec §9.2 `payments`). Scoped to the store the
|
|
102
|
+
* client is on. Configuration only: nothing here moves money.
|
|
103
|
+
*
|
|
104
|
+
* Every call is refused `PLUGIN_ACCESS_DENIED` (`PermissionDeniedError`, 403) for a store that
|
|
105
|
+
* does not hold the Mollie plugin.
|
|
106
|
+
*/
|
|
107
|
+
export interface MollieMethodsModule {
|
|
108
|
+
/**
|
|
109
|
+
* Mollie's checkout methods for one payment method, merged with the store's saved order and
|
|
110
|
+
* hidden list. Asked with the method's own API key, or through the store's Mollie Connect
|
|
111
|
+
* account when the method pays through it (`credentialPath: 'connect'`). Goes to Mollie on
|
|
112
|
+
* every call. Needs `ReadPaymentMethod`.
|
|
113
|
+
*
|
|
114
|
+
* Never throws for Mollie's answer: a refused key or grant, Mollie not answering, a method
|
|
115
|
+
* with nothing to ask with, a code the store has no method for and a method that is not
|
|
116
|
+
* Mollie's all answer an empty or saved-only `methods` with `error` saying why.
|
|
117
|
+
*
|
|
118
|
+
* @effect read
|
|
119
|
+
* @permission ReadPaymentMethod
|
|
120
|
+
*/
|
|
121
|
+
methods(paymentMethodCode: string, options?: Call): Promise<MollieMethodList>;
|
|
122
|
+
/**
|
|
123
|
+
* Save the checkout order and the hidden methods of one payment method, and answer the list
|
|
124
|
+
* as {@link methods} reads it (so it asks Mollie again). The lists are stored as sent: an id
|
|
125
|
+
* Mollie does not offer is kept, and a method Mollie offers that `order` leaves out is shown
|
|
126
|
+
* after the ordered ones. Needs `UpdatePaymentMethod`.
|
|
127
|
+
*
|
|
128
|
+
* Refused, with nothing saved:
|
|
129
|
+
*
|
|
130
|
+
* - `USER_INPUT_ERROR` (`ValidationError`, 400): the store has no method with that code.
|
|
131
|
+
* - `SHARED_PAYMENT_METHOD_NOT_ALLOWED` (`PermissionDeniedError`, 403): another store holds
|
|
132
|
+
* the method and the caller may not change it there.
|
|
133
|
+
* - `INVALID_MOLLIE_METHODS_INPUT` (`ValidationError`, 400), before sending: `order` or
|
|
134
|
+
* `hidden` is not a list of strings.
|
|
135
|
+
*
|
|
136
|
+
* @effect write
|
|
137
|
+
* @permission UpdatePaymentMethod
|
|
138
|
+
*/
|
|
139
|
+
setMethods(paymentMethodCode: string, input: SetMollieMethodsInput, options?: Call): Promise<MollieMethodList>;
|
|
140
|
+
/**
|
|
141
|
+
* Ask Mollie, with the method's own API key, which methods it offers for each payment
|
|
142
|
+
* sequence (one-off, first, recurring), and draw a verdict on SEPA Direct Debit. Five calls
|
|
143
|
+
* to Mollie; changes nothing, here or at Mollie. A method paying through Mollie Connect is
|
|
144
|
+
* still diagnosed with its key: without one the answer is `UNKNOWN_KEY_ERROR`.
|
|
145
|
+
*
|
|
146
|
+
* Never throws for Mollie's answer (it is in `error` and `verdict`). It throws only when the
|
|
147
|
+
* call is refused: `USER_INPUT_ERROR` (`ValidationError`, 400) for a code the store has no
|
|
148
|
+
* method for, `FORBIDDEN` (`PermissionDeniedError`, 403) without `UpdatePaymentMethod`, which
|
|
149
|
+
* it needs because it uses the stored key, and `PLUGIN_ACCESS_DENIED` (403).
|
|
150
|
+
*
|
|
151
|
+
* @effect read
|
|
152
|
+
* @permission UpdatePaymentMethod
|
|
153
|
+
*/
|
|
154
|
+
diagnose(paymentMethodCode: string, options?: Call): Promise<MollieDiagnosis>;
|
|
155
|
+
}
|
|
156
|
+
export declare const MOLLIE_METHODS_QUERY = "\n query MollieMethodList($paymentMethodCode: String!) {\n mollieMethods(paymentMethodCode: $paymentMethodCode) { \n methods {\n id\n description\n imageUrl\n hidden\n status\n available\n }\n \n error {\n kind\n message\n statusCode\n }\n\n }\n }\n";
|
|
157
|
+
export declare const SET_MOLLIE_METHODS_MUTATION = "\n mutation SetMollieMethodList($input: SetMollieMethodsInput!) {\n setMollieMethods(input: $input) { \n methods {\n id\n description\n imageUrl\n hidden\n status\n available\n }\n \n error {\n kind\n message\n statusCode\n }\n\n }\n }\n";
|
|
158
|
+
export declare const MOLLIE_DIAGNOSTICS_QUERY = "\n query MollieDiagnosis($paymentMethodCode: String!) {\n mollieDiagnostics(paymentMethodCode: $paymentMethodCode) {\n ok\n keyMode\n \n error {\n kind\n message\n statusCode\n }\n\n methods {\n id\n description\n status\n oneoff\n first\n recurring\n }\n directDebit {\n availableOneoff\n availableFirst\n availableRecurring\n status\n getProbe\n }\n verdict\n probedAt\n }\n }\n";
|
|
159
|
+
export declare function createMollieMethodsModule(transport: Transport): MollieMethodsModule;
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { ValidationError } from '@sixtyninecommerce/core';
|
|
2
|
+
import { fieldOf } from '../catalog/types.js';
|
|
3
|
+
const PROBE_ERROR_FIELDS = /* GraphQL */ `
|
|
4
|
+
error {
|
|
5
|
+
kind
|
|
6
|
+
message
|
|
7
|
+
statusCode
|
|
8
|
+
}
|
|
9
|
+
`;
|
|
10
|
+
const LIST_FIELDS = /* GraphQL */ `
|
|
11
|
+
methods {
|
|
12
|
+
id
|
|
13
|
+
description
|
|
14
|
+
imageUrl
|
|
15
|
+
hidden
|
|
16
|
+
status
|
|
17
|
+
available
|
|
18
|
+
}
|
|
19
|
+
${PROBE_ERROR_FIELDS}
|
|
20
|
+
`;
|
|
21
|
+
export const MOLLIE_METHODS_QUERY = /* GraphQL */ `
|
|
22
|
+
query MollieMethodList($paymentMethodCode: String!) {
|
|
23
|
+
mollieMethods(paymentMethodCode: $paymentMethodCode) { ${LIST_FIELDS} }
|
|
24
|
+
}
|
|
25
|
+
`;
|
|
26
|
+
export const SET_MOLLIE_METHODS_MUTATION = /* GraphQL */ `
|
|
27
|
+
mutation SetMollieMethodList($input: SetMollieMethodsInput!) {
|
|
28
|
+
setMollieMethods(input: $input) { ${LIST_FIELDS} }
|
|
29
|
+
}
|
|
30
|
+
`;
|
|
31
|
+
export const MOLLIE_DIAGNOSTICS_QUERY = /* GraphQL */ `
|
|
32
|
+
query MollieDiagnosis($paymentMethodCode: String!) {
|
|
33
|
+
mollieDiagnostics(paymentMethodCode: $paymentMethodCode) {
|
|
34
|
+
ok
|
|
35
|
+
keyMode
|
|
36
|
+
${PROBE_ERROR_FIELDS}
|
|
37
|
+
methods {
|
|
38
|
+
id
|
|
39
|
+
description
|
|
40
|
+
status
|
|
41
|
+
oneoff
|
|
42
|
+
first
|
|
43
|
+
recurring
|
|
44
|
+
}
|
|
45
|
+
directDebit {
|
|
46
|
+
availableOneoff
|
|
47
|
+
availableFirst
|
|
48
|
+
availableRecurring
|
|
49
|
+
status
|
|
50
|
+
getProbe
|
|
51
|
+
}
|
|
52
|
+
verdict
|
|
53
|
+
probedAt
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
`;
|
|
57
|
+
const invalidInput = (message) => new ValidationError({
|
|
58
|
+
code: 'INVALID_MOLLIE_METHODS_INPUT',
|
|
59
|
+
message,
|
|
60
|
+
status: 400,
|
|
61
|
+
service: 'vendure',
|
|
62
|
+
});
|
|
63
|
+
const requireCode = (value) => {
|
|
64
|
+
if (typeof value !== 'string' || value === '') {
|
|
65
|
+
throw invalidInput('paymentMethodCode must be the code of a payment method.');
|
|
66
|
+
}
|
|
67
|
+
return value;
|
|
68
|
+
};
|
|
69
|
+
const requireIds = (value, name) => {
|
|
70
|
+
if (!Array.isArray(value) || value.some((id) => typeof id !== 'string')) {
|
|
71
|
+
throw invalidInput(`${name} must be a list of Mollie method ids.`);
|
|
72
|
+
}
|
|
73
|
+
return [...value];
|
|
74
|
+
};
|
|
75
|
+
const KINDS = ['no_key', 'auth', 'network', 'provider'];
|
|
76
|
+
const toError = (wire) => wire
|
|
77
|
+
? {
|
|
78
|
+
kind: KINDS.includes(wire.kind)
|
|
79
|
+
? wire.kind
|
|
80
|
+
: 'provider',
|
|
81
|
+
message: wire.message,
|
|
82
|
+
statusCode: wire.statusCode ?? null,
|
|
83
|
+
}
|
|
84
|
+
: null;
|
|
85
|
+
const toList = (wire) => ({
|
|
86
|
+
methods: wire.methods.map((method) => ({
|
|
87
|
+
id: method.id,
|
|
88
|
+
description: method.description ?? null,
|
|
89
|
+
imageUrl: method.imageUrl ?? null,
|
|
90
|
+
hidden: method.hidden,
|
|
91
|
+
status: method.status ?? null,
|
|
92
|
+
available: method.available,
|
|
93
|
+
})),
|
|
94
|
+
error: toError(wire.error),
|
|
95
|
+
});
|
|
96
|
+
const toDiagnosis = (wire) => ({
|
|
97
|
+
ok: wire.ok,
|
|
98
|
+
keyMode: wire.keyMode === 'test' || wire.keyMode === 'live' ? wire.keyMode : 'unknown',
|
|
99
|
+
error: toError(wire.error),
|
|
100
|
+
methods: wire.methods.map((method) => ({
|
|
101
|
+
id: method.id,
|
|
102
|
+
description: method.description ?? null,
|
|
103
|
+
status: method.status ?? null,
|
|
104
|
+
oneoff: method.oneoff,
|
|
105
|
+
first: method.first,
|
|
106
|
+
recurring: method.recurring,
|
|
107
|
+
})),
|
|
108
|
+
directDebit: {
|
|
109
|
+
availableOneoff: wire.directDebit.availableOneoff,
|
|
110
|
+
availableFirst: wire.directDebit.availableFirst,
|
|
111
|
+
availableRecurring: wire.directDebit.availableRecurring,
|
|
112
|
+
status: wire.directDebit.status ?? null,
|
|
113
|
+
getProbe: wire.directDebit.getProbe,
|
|
114
|
+
},
|
|
115
|
+
// Passed through: a verdict the engine adds later is still the engine's answer.
|
|
116
|
+
verdict: wire.verdict,
|
|
117
|
+
probedAt: wire.probedAt,
|
|
118
|
+
});
|
|
119
|
+
export function createMollieMethodsModule(transport) {
|
|
120
|
+
return {
|
|
121
|
+
async methods(paymentMethodCode, options) {
|
|
122
|
+
return toList(await fieldOf(transport, MOLLIE_METHODS_QUERY, 'mollieMethods', { paymentMethodCode: requireCode(paymentMethodCode) }, options));
|
|
123
|
+
},
|
|
124
|
+
async setMethods(paymentMethodCode, input, options) {
|
|
125
|
+
const code = requireCode(paymentMethodCode);
|
|
126
|
+
if (typeof input !== 'object' || input === null || Array.isArray(input)) {
|
|
127
|
+
throw invalidInput('setMethods takes { order, hidden }.');
|
|
128
|
+
}
|
|
129
|
+
return toList(await fieldOf(transport, SET_MOLLIE_METHODS_MUTATION, 'setMollieMethods', {
|
|
130
|
+
input: {
|
|
131
|
+
paymentMethodCode: code,
|
|
132
|
+
order: requireIds(input.order, 'order'),
|
|
133
|
+
hidden: requireIds(input.hidden, 'hidden'),
|
|
134
|
+
},
|
|
135
|
+
}, options));
|
|
136
|
+
},
|
|
137
|
+
async diagnose(paymentMethodCode, options) {
|
|
138
|
+
return toDiagnosis(await fieldOf(transport, MOLLIE_DIAGNOSTICS_QUERY, 'mollieDiagnostics', { paymentMethodCode: requireCode(paymentMethodCode) }, options));
|
|
139
|
+
},
|
|
140
|
+
};
|
|
141
|
+
}
|