@sixtyninecommerce/admin 0.9.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 +4598 -128
- 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 +318 -17
- package/dist/catalog/products.js +182 -14
- 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 +282 -25
- package/dist/catalog/variants.js +173 -25
- package/dist/catalog/visibility.d.ts +20 -5
- package/dist/catalog/visibility.js +19 -1
- package/dist/client.d.ts +116 -9
- package/dist/client.js +41 -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 +121 -10
- package/dist/fulfillments/index.js +120 -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 +129 -30
- package/dist/index.js +47 -9
- 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 +40 -0
- package/dist/integrations/index.js +24 -0
- package/dist/integrations/pipeline-keys.d.ts +13 -0
- package/dist/integrations/pipeline-keys.js +22 -0
- package/dist/integrations/pipelines.d.ts +114 -0
- package/dist/integrations/pipelines.js +46 -0
- package/dist/integrations/types.d.ts +322 -0
- package/dist/integrations/types.js +8 -0
- package/dist/jobs/bulk-action-run.d.ts +11 -2
- package/dist/jobs/bulk-action-run.js +4 -5
- 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/bulk.d.ts +75 -0
- package/dist/orders/bulk.js +150 -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/deposit-policy.d.ts +103 -0
- package/dist/orders/deposit-policy.js +202 -0
- 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 +125 -5
- package/dist/orders/index.js +35 -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-discounts.d.ts +11 -2
- package/dist/orders/manual-discounts.js +2 -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 +263 -10
- package/dist/payments/index.js +133 -1
- package/dist/payments/methods.d.ts +332 -0
- package/dist/payments/methods.js +363 -0
- 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 +177 -4
- package/dist/pricing/index.js +176 -1
- package/dist/pricing/price-lists.d.ts +604 -0
- package/dist/pricing/price-lists.js +600 -0
- package/dist/pricing/vouchers.d.ts +103 -0
- package/dist/pricing/vouchers.js +69 -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 +818 -0
- package/dist/returns/index.js +844 -0
- package/dist/search/index.d.ts +174 -0
- package/dist/search/index.js +125 -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 +51 -4
- 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
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
import { errorFromErrorResult, isErrorResult, NotFoundError, ValidationError, } from '@sixtyninecommerce/core';
|
|
2
|
+
import { storeCreditAware } from '../payments/store-credit-fields.js';
|
|
3
|
+
import { createFulfillmentCreateMethods } from './create.js';
|
|
4
|
+
import { createFulfillmentPaymentPolicyModule, } from './payment-policy.js';
|
|
5
|
+
import { createWarehouseFulfillmentsModule, } from './warehouse.js';
|
|
6
|
+
/** The longest override reason the engine stores. */
|
|
7
|
+
export const FULFILLMENT_COVERAGE_REASON_MAX_LENGTH = 500;
|
|
2
8
|
/** Every field of `OrderOverpaymentOption`. */
|
|
3
9
|
const OVERPAYMENT_OPTION_FIELDS = /* GraphQL */ `
|
|
4
10
|
available
|
|
5
11
|
code
|
|
6
12
|
message
|
|
13
|
+
book
|
|
7
14
|
`;
|
|
8
15
|
/**
|
|
9
16
|
* Its own document, like every call here: on an engine without the query this call alone fails
|
|
@@ -46,10 +53,86 @@ export const CANCEL_FULFILLMENT_MUTATION = /* GraphQL */ `
|
|
|
46
53
|
amount
|
|
47
54
|
currencyCode
|
|
48
55
|
choice
|
|
56
|
+
book
|
|
49
57
|
}
|
|
50
58
|
}
|
|
51
59
|
}
|
|
52
60
|
`;
|
|
61
|
+
/** Every field of `OrderFulfillmentCoverageOverride`. */
|
|
62
|
+
const COVERAGE_OVERRIDE_FIELDS = /* GraphQL */ `
|
|
63
|
+
id
|
|
64
|
+
orderId
|
|
65
|
+
reason
|
|
66
|
+
actorKind
|
|
67
|
+
actorId
|
|
68
|
+
outstandingAtGrant
|
|
69
|
+
currencyCode
|
|
70
|
+
createdAt
|
|
71
|
+
active
|
|
72
|
+
`;
|
|
73
|
+
/** Its own document: on an engine without the query this call alone fails validation. */
|
|
74
|
+
export const ORDER_FULFILLMENT_COVERAGE_QUERY = /* GraphQL */ `
|
|
75
|
+
query OrderFulfillmentCoverage($orderId: ID!) {
|
|
76
|
+
orderFulfillmentCoverage(orderId: $orderId) {
|
|
77
|
+
orderId
|
|
78
|
+
orderCode
|
|
79
|
+
currencyCode
|
|
80
|
+
policyActive
|
|
81
|
+
covered
|
|
82
|
+
outstanding
|
|
83
|
+
exempt
|
|
84
|
+
exemptReason
|
|
85
|
+
allowed
|
|
86
|
+
override { ${COVERAGE_OVERRIDE_FIELDS} }
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
`;
|
|
90
|
+
/** `$idempotencyKey` is optional and left out of the variables when not given. */
|
|
91
|
+
export const ALLOW_UNCOVERED_FULFILLMENT_MUTATION = /* GraphQL */ `
|
|
92
|
+
mutation AllowUncoveredFulfillment($orderId: ID!, $reason: String!, $idempotencyKey: String) {
|
|
93
|
+
allowUncoveredFulfillment(orderId: $orderId, reason: $reason, idempotencyKey: $idempotencyKey) {
|
|
94
|
+
${COVERAGE_OVERRIDE_FIELDS}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
`;
|
|
98
|
+
function invalidCoverage(field, message) {
|
|
99
|
+
return new ValidationError({
|
|
100
|
+
code: 'FULFILLMENT_COVERAGE_OVERRIDE_INVALID',
|
|
101
|
+
message,
|
|
102
|
+
status: 400,
|
|
103
|
+
service: 'vendure',
|
|
104
|
+
details: [{ field, code: 'FULFILLMENT_COVERAGE_OVERRIDE_INVALID', message }],
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
function assertOrderId(orderId) {
|
|
108
|
+
if (typeof orderId !== 'string' || orderId.trim() === '') {
|
|
109
|
+
throw invalidCoverage('orderId', 'An order id is required.');
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
/** Refused before any request: the engine would refuse it the same way. */
|
|
113
|
+
function assertOverrideReason(reason) {
|
|
114
|
+
const text = typeof reason === 'string' ? reason.trim() : '';
|
|
115
|
+
if (text === '') {
|
|
116
|
+
throw invalidCoverage('reason', 'Say why this order may be handed over before it is paid: a reason is required.');
|
|
117
|
+
}
|
|
118
|
+
if (text.length > FULFILLMENT_COVERAGE_REASON_MAX_LENGTH) {
|
|
119
|
+
throw invalidCoverage('reason', `The reason is at most ${FULFILLMENT_COVERAGE_REASON_MAX_LENGTH} characters.`);
|
|
120
|
+
}
|
|
121
|
+
return text;
|
|
122
|
+
}
|
|
123
|
+
function toCoverageOverride(raw) {
|
|
124
|
+
return {
|
|
125
|
+
id: raw.id,
|
|
126
|
+
orderId: raw.orderId,
|
|
127
|
+
reason: raw.reason,
|
|
128
|
+
actorKind: raw.actorKind,
|
|
129
|
+
actorId: raw.actorId,
|
|
130
|
+
outstandingAtGrant: raw.outstandingAtGrant,
|
|
131
|
+
currencyCode: raw.currencyCode,
|
|
132
|
+
createdAt: raw.createdAt,
|
|
133
|
+
active: raw.active,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
53
136
|
const OVERPAYMENT_CHOICES = new Set([
|
|
54
137
|
'REFUND',
|
|
55
138
|
'ACCOUNT_CREDIT',
|
|
@@ -283,6 +366,9 @@ function assertLabelRequest(fulfillmentId, format) {
|
|
|
283
366
|
}
|
|
284
367
|
export function createFulfillmentsModule(transport) {
|
|
285
368
|
return {
|
|
369
|
+
...createFulfillmentCreateMethods(transport),
|
|
370
|
+
paymentPolicy: createFulfillmentPaymentPolicyModule(transport),
|
|
371
|
+
warehouse: createWarehouseFulfillmentsModule(transport),
|
|
286
372
|
async parcelsOfOrder(orderId, options) {
|
|
287
373
|
const data = await transport.graphql({ api: 'admin', query: ORDER_FULFILLMENT_PARCELS_QUERY, variables: { id: orderId } }, options);
|
|
288
374
|
if (!data.order)
|
|
@@ -365,7 +451,7 @@ export function createFulfillmentsModule(transport) {
|
|
|
365
451
|
if (typeof fulfillmentId !== 'string' || fulfillmentId.trim() === '') {
|
|
366
452
|
throw invalidCancel('fulfillmentId', 'A fulfillment id is required.');
|
|
367
453
|
}
|
|
368
|
-
const data = await transport.graphql({ api: 'admin', query: FULFILLMENT_CANCEL_PREVIEW_QUERY, variables: { fulfillmentId } }, options);
|
|
454
|
+
const data = await storeCreditAware(transport).graphql({ api: 'admin', query: FULFILLMENT_CANCEL_PREVIEW_QUERY, variables: { fulfillmentId } }, options);
|
|
369
455
|
const preview = data.fulfillmentCancelPreview;
|
|
370
456
|
return {
|
|
371
457
|
fulfillmentId: preview.fulfillmentId,
|
|
@@ -382,7 +468,7 @@ export function createFulfillmentsModule(transport) {
|
|
|
382
468
|
async cancel(fulfillmentId, input = {}, options) {
|
|
383
469
|
assertCancelRequest(fulfillmentId, input);
|
|
384
470
|
const overpayment = input.overpayment ?? [];
|
|
385
|
-
const data = await transport.graphql({
|
|
471
|
+
const data = await storeCreditAware(transport).graphql({
|
|
386
472
|
api: 'admin',
|
|
387
473
|
query: CANCEL_FULFILLMENT_MUTATION,
|
|
388
474
|
// A variable, not a header: the Admin API takes the key as an argument.
|
|
@@ -406,6 +492,38 @@ export function createFulfillmentsModule(transport) {
|
|
|
406
492
|
})),
|
|
407
493
|
};
|
|
408
494
|
},
|
|
495
|
+
async coverage(orderId, options) {
|
|
496
|
+
assertOrderId(orderId);
|
|
497
|
+
const data = await transport.graphql({ api: 'admin', query: ORDER_FULFILLMENT_COVERAGE_QUERY, variables: { orderId } }, options);
|
|
498
|
+
const coverage = data.orderFulfillmentCoverage;
|
|
499
|
+
return {
|
|
500
|
+
orderId: coverage.orderId,
|
|
501
|
+
orderCode: coverage.orderCode,
|
|
502
|
+
currencyCode: coverage.currencyCode,
|
|
503
|
+
policyActive: coverage.policyActive,
|
|
504
|
+
covered: coverage.covered,
|
|
505
|
+
outstanding: coverage.outstanding,
|
|
506
|
+
exempt: coverage.exempt,
|
|
507
|
+
exemptReason: coverage.exemptReason ?? null,
|
|
508
|
+
allowed: coverage.allowed,
|
|
509
|
+
override: coverage.override ? toCoverageOverride(coverage.override) : null,
|
|
510
|
+
};
|
|
511
|
+
},
|
|
512
|
+
async allowUncovered(orderId, reason, options) {
|
|
513
|
+
assertOrderId(orderId);
|
|
514
|
+
const text = assertOverrideReason(reason);
|
|
515
|
+
const data = await transport.graphql({
|
|
516
|
+
api: 'admin',
|
|
517
|
+
query: ALLOW_UNCOVERED_FULFILLMENT_MUTATION,
|
|
518
|
+
// A variable, not a header: the Admin API takes the key as an argument.
|
|
519
|
+
variables: {
|
|
520
|
+
orderId,
|
|
521
|
+
reason: text,
|
|
522
|
+
...(options?.idempotencyKey ? { idempotencyKey: options.idempotencyKey } : {}),
|
|
523
|
+
},
|
|
524
|
+
}, options);
|
|
525
|
+
return toCoverageOverride(data.allowUncoveredFulfillment);
|
|
526
|
+
},
|
|
409
527
|
async reportAppFulfillment(fulfillmentId, input, options) {
|
|
410
528
|
const data = await transport.graphql({
|
|
411
529
|
api: 'admin',
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { type Transport } from '@sixtyninecommerce/core';
|
|
2
|
+
import type { Call } from '../types.js';
|
|
3
|
+
/** The most payment method codes `exemptMethodCodes` may name. */
|
|
4
|
+
export declare const FULFILLMENT_PAYMENT_POLICY_EXEMPT_METHODS_MAX = 50;
|
|
5
|
+
/** The longest payment method code the list accepts (`PaymentMethod.code` is a varchar(255)). */
|
|
6
|
+
export declare const FULFILLMENT_PAYMENT_POLICY_METHOD_CODE_MAX_LENGTH = 255;
|
|
7
|
+
/**
|
|
8
|
+
* The store's fulfilment payment policy (`Channel.customFields.fulfillmentPaymentPolicy`):
|
|
9
|
+
* whether goods are handed over before an order is paid in full. Every field present: this is
|
|
10
|
+
* what the engine APPLIES, absent and malformed fields read as their defaults (OFF).
|
|
11
|
+
*/
|
|
12
|
+
export interface FulfillmentPaymentPolicy {
|
|
13
|
+
/**
|
|
14
|
+
* On: a fulfilment is created, extended or shipped only once the money COLLECTED for the
|
|
15
|
+
* order (settled, or held by a payment provider) covers what it bills, unless the order is
|
|
16
|
+
* exempt or an override was recorded (`fulfillments.allowUncovered`). Otherwise refused
|
|
17
|
+
* `ORDER_NOT_COVERED`.
|
|
18
|
+
*/
|
|
19
|
+
requireFullPayment: boolean;
|
|
20
|
+
/**
|
|
21
|
+
* Payment method CODES whose orders are handed over unpaid as a matter of course (cash on
|
|
22
|
+
* delivery, a bank transfer the store ships against), judged on the order's latest live
|
|
23
|
+
* payment. Read as the engine compares them: trimmed, lower-cased, once each.
|
|
24
|
+
*/
|
|
25
|
+
exemptMethodCodes: string[];
|
|
26
|
+
}
|
|
27
|
+
/** The policy of a store that never set one, and of a column that cannot be read: off. */
|
|
28
|
+
export declare const DEFAULT_FULFILLMENT_PAYMENT_POLICY: Readonly<FulfillmentPaymentPolicy>;
|
|
29
|
+
/**
|
|
30
|
+
* The ACTIVE store's fulfilment payment policy (`admin.fulfillments.paymentPolicy`), stored as a
|
|
31
|
+
* Channel custom field and written through core `updateChannel`.
|
|
32
|
+
*
|
|
33
|
+
* Reading needs an authenticated administrator on the store; writing needs `UpdateChannel`.
|
|
34
|
+
*/
|
|
35
|
+
export interface FulfillmentPaymentPolicyModule {
|
|
36
|
+
/**
|
|
37
|
+
* The policy the engine applies, read as tolerantly as the engine reads it
|
|
38
|
+
* (`resolveFulfillmentPaymentPolicy`): a store that never set one, a malformed column and a
|
|
39
|
+
* field of the wrong type all answer OFF ({@link DEFAULT_FULFILLMENT_PAYMENT_POLICY}); the
|
|
40
|
+
* exempt codes are the non-blank ones, trimmed, lower-cased and once each.
|
|
41
|
+
*/
|
|
42
|
+
get(options?: Call): Promise<FulfillmentPaymentPolicy>;
|
|
43
|
+
/**
|
|
44
|
+
* Replace the whole policy, and answer it as the engine now applies it.
|
|
45
|
+
*
|
|
46
|
+
* Both fields are required: read it with {@link get}, change what you mean to, and send it
|
|
47
|
+
* back. Only the schema's fields are stored, the codes trimmed.
|
|
48
|
+
*
|
|
49
|
+
* Refused before any request with `FULFILLMENT_PAYMENT_POLICY_INVALID` ({@link ValidationError},
|
|
50
|
+
* one `details[]` entry per failing field): a non-boolean switch, an exempt list that is not a
|
|
51
|
+
* list, holds a blank or over-long code, names one code twice in any case, or more than 50.
|
|
52
|
+
* The engine's own write validator refuses the same values (a `ValidationError` too, carrying
|
|
53
|
+
* its sentence), so a value that slips past this check is still never stored.
|
|
54
|
+
*
|
|
55
|
+
* Absent and "set to the defaults" mean the same thing to the engine, and a store's column is
|
|
56
|
+
* never backfilled: write the policy when a merchant changed it.
|
|
57
|
+
*/
|
|
58
|
+
set(policy: FulfillmentPaymentPolicy, options?: Call): Promise<FulfillmentPaymentPolicy>;
|
|
59
|
+
}
|
|
60
|
+
export declare const FULFILLMENT_PAYMENT_POLICY_QUERY = "\n query FulfillmentPaymentPolicy {\n activeChannel { \n id\n customFields {\n fulfillmentPaymentPolicy\n }\n }\n }\n";
|
|
61
|
+
export declare const SET_FULFILLMENT_PAYMENT_POLICY_MUTATION = "\n mutation SetFulfillmentPaymentPolicy($input: UpdateChannelInput!) {\n updateChannel(input: $input) {\n ... on Channel { \n id\n customFields {\n fulfillmentPaymentPolicy\n }\n }\n ... on ErrorResult { errorCode message }\n }\n }\n";
|
|
62
|
+
/** A payment method code as the engine compares it (`normalizeMethodCode`). */
|
|
63
|
+
export declare function normalizeFulfillmentPolicyMethodCode(code: string): string;
|
|
64
|
+
export declare function createFulfillmentPaymentPolicyModule(transport: Transport): FulfillmentPaymentPolicyModule;
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { errorFromErrorResult, isErrorResult, ValidationError, } from '@sixtyninecommerce/core';
|
|
2
|
+
// The bounds of the meta catalog's `fulfillment_payment_policy` schema
|
|
3
|
+
// (`packages/shared/src/meta-catalog/settings-schemas.ts`), which the spec reads
|
|
4
|
+
// back from that schema, and of the engine's write validator
|
|
5
|
+
// (`validateFulfillmentPaymentPolicyValue`), which refuses the same values.
|
|
6
|
+
/** The most payment method codes `exemptMethodCodes` may name. */
|
|
7
|
+
export const FULFILLMENT_PAYMENT_POLICY_EXEMPT_METHODS_MAX = 50;
|
|
8
|
+
/** The longest payment method code the list accepts (`PaymentMethod.code` is a varchar(255)). */
|
|
9
|
+
export const FULFILLMENT_PAYMENT_POLICY_METHOD_CODE_MAX_LENGTH = 255;
|
|
10
|
+
/** The policy of a store that never set one, and of a column that cannot be read: off. */
|
|
11
|
+
export const DEFAULT_FULFILLMENT_PAYMENT_POLICY = Object.freeze({
|
|
12
|
+
requireFullPayment: false,
|
|
13
|
+
exemptMethodCodes: [],
|
|
14
|
+
});
|
|
15
|
+
const POLICY_FIELDS = /* GraphQL */ `
|
|
16
|
+
id
|
|
17
|
+
customFields {
|
|
18
|
+
fulfillmentPaymentPolicy
|
|
19
|
+
}
|
|
20
|
+
`;
|
|
21
|
+
export const FULFILLMENT_PAYMENT_POLICY_QUERY = /* GraphQL */ `
|
|
22
|
+
query FulfillmentPaymentPolicy {
|
|
23
|
+
activeChannel { ${POLICY_FIELDS} }
|
|
24
|
+
}
|
|
25
|
+
`;
|
|
26
|
+
export const SET_FULFILLMENT_PAYMENT_POLICY_MUTATION = /* GraphQL */ `
|
|
27
|
+
mutation SetFulfillmentPaymentPolicy($input: UpdateChannelInput!) {
|
|
28
|
+
updateChannel(input: $input) {
|
|
29
|
+
... on Channel { ${POLICY_FIELDS} }
|
|
30
|
+
... on ErrorResult { errorCode message }
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
`;
|
|
34
|
+
function isRecord(value) {
|
|
35
|
+
return typeof value === 'object' && value !== null && !Array.isArray(value);
|
|
36
|
+
}
|
|
37
|
+
/** A payment method code as the engine compares it (`normalizeMethodCode`). */
|
|
38
|
+
export function normalizeFulfillmentPolicyMethodCode(code) {
|
|
39
|
+
return code.trim().toLowerCase();
|
|
40
|
+
}
|
|
41
|
+
/** The column, read as the engine reads it: anything unreadable is OFF. */
|
|
42
|
+
function readFulfillmentPaymentPolicy(raw) {
|
|
43
|
+
let parsed = raw;
|
|
44
|
+
if (typeof raw === 'string') {
|
|
45
|
+
try {
|
|
46
|
+
parsed = JSON.parse(raw);
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
parsed = null;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
if (!isRecord(parsed))
|
|
53
|
+
return { requireFullPayment: false, exemptMethodCodes: [] };
|
|
54
|
+
const codes = Array.isArray(parsed.exemptMethodCodes)
|
|
55
|
+
? [
|
|
56
|
+
...new Set(parsed.exemptMethodCodes
|
|
57
|
+
.filter((code) => typeof code === 'string' && code.trim() !== '')
|
|
58
|
+
.map(normalizeFulfillmentPolicyMethodCode)),
|
|
59
|
+
].slice(0, FULFILLMENT_PAYMENT_POLICY_EXEMPT_METHODS_MAX)
|
|
60
|
+
: [];
|
|
61
|
+
return { requireFullPayment: parsed.requireFullPayment === true, exemptMethodCodes: codes };
|
|
62
|
+
}
|
|
63
|
+
/** Every way `policy` breaks the schema, one entry per field. */
|
|
64
|
+
function problemsOf(policy) {
|
|
65
|
+
const problems = [];
|
|
66
|
+
const add = (field, message) => problems.push({ field, code: 'FULFILLMENT_PAYMENT_POLICY_INVALID', message });
|
|
67
|
+
if (!isRecord(policy)) {
|
|
68
|
+
add('policy', 'Pass the whole policy as an object: read it with get(), change it, send it back.');
|
|
69
|
+
return problems;
|
|
70
|
+
}
|
|
71
|
+
if (typeof policy.requireFullPayment !== 'boolean') {
|
|
72
|
+
add('requireFullPayment', 'requireFullPayment must be true or false.');
|
|
73
|
+
}
|
|
74
|
+
const codes = policy.exemptMethodCodes;
|
|
75
|
+
if (!Array.isArray(codes)) {
|
|
76
|
+
add('exemptMethodCodes', 'exemptMethodCodes must be a list of payment method codes.');
|
|
77
|
+
}
|
|
78
|
+
else if (codes.some((code) => typeof code !== 'string' || code.trim() === '')) {
|
|
79
|
+
add('exemptMethodCodes', 'exemptMethodCodes may hold only non-blank payment method codes.');
|
|
80
|
+
}
|
|
81
|
+
else if (codes.some((code) => code.trim().length > FULFILLMENT_PAYMENT_POLICY_METHOD_CODE_MAX_LENGTH)) {
|
|
82
|
+
add('exemptMethodCodes', `A payment method code is at most ${String(FULFILLMENT_PAYMENT_POLICY_METHOD_CODE_MAX_LENGTH)} characters.`);
|
|
83
|
+
}
|
|
84
|
+
else if (new Set(codes.map((code) => normalizeFulfillmentPolicyMethodCode(code))).size !==
|
|
85
|
+
codes.length) {
|
|
86
|
+
add('exemptMethodCodes', 'exemptMethodCodes names a payment method code more than once (codes are compared ignoring case).');
|
|
87
|
+
}
|
|
88
|
+
else if (codes.length > FULFILLMENT_PAYMENT_POLICY_EXEMPT_METHODS_MAX) {
|
|
89
|
+
add('exemptMethodCodes', `exemptMethodCodes may name at most ${String(FULFILLMENT_PAYMENT_POLICY_EXEMPT_METHODS_MAX)} payment methods.`);
|
|
90
|
+
}
|
|
91
|
+
return problems;
|
|
92
|
+
}
|
|
93
|
+
/** Exactly the schema's fields, in its order, codes trimmed: what the column stores. */
|
|
94
|
+
function storedOf(policy) {
|
|
95
|
+
return {
|
|
96
|
+
requireFullPayment: policy.requireFullPayment,
|
|
97
|
+
exemptMethodCodes: policy.exemptMethodCodes.map((code) => code.trim()),
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
export function createFulfillmentPaymentPolicyModule(transport) {
|
|
101
|
+
const read = async (options) => {
|
|
102
|
+
const data = await transport.graphql({ api: 'admin', query: FULFILLMENT_PAYMENT_POLICY_QUERY }, options);
|
|
103
|
+
return data.activeChannel;
|
|
104
|
+
};
|
|
105
|
+
return {
|
|
106
|
+
async get(options) {
|
|
107
|
+
const channel = await read(options);
|
|
108
|
+
return readFulfillmentPaymentPolicy(channel.customFields?.fulfillmentPaymentPolicy ?? null);
|
|
109
|
+
},
|
|
110
|
+
async set(policy, options) {
|
|
111
|
+
const problems = problemsOf(policy);
|
|
112
|
+
if (problems.length > 0) {
|
|
113
|
+
throw new ValidationError({
|
|
114
|
+
code: 'FULFILLMENT_PAYMENT_POLICY_INVALID',
|
|
115
|
+
message: problems.map((problem) => problem.message).join(' '),
|
|
116
|
+
status: 400,
|
|
117
|
+
service: 'vendure',
|
|
118
|
+
details: problems,
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
// `updateChannel` needs the id, and the active channel is the one the client is scoped
|
|
122
|
+
// to: read it with the SAME call options, so a per-call tenant writes its own channel.
|
|
123
|
+
const { id } = await read(options);
|
|
124
|
+
const data = await transport.graphql({
|
|
125
|
+
api: 'admin',
|
|
126
|
+
query: SET_FULFILLMENT_PAYMENT_POLICY_MUTATION,
|
|
127
|
+
variables: {
|
|
128
|
+
// The column is `text` holding JSON, so it is sent as a string.
|
|
129
|
+
input: {
|
|
130
|
+
id,
|
|
131
|
+
customFields: { fulfillmentPaymentPolicy: JSON.stringify(storedOf(policy)) },
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
}, options);
|
|
135
|
+
if (isErrorResult(data.updateChannel))
|
|
136
|
+
throw errorFromErrorResult(data.updateChannel);
|
|
137
|
+
return readFulfillmentPaymentPolicy(data.updateChannel.customFields?.fulfillmentPaymentPolicy ?? null);
|
|
138
|
+
},
|
|
139
|
+
};
|
|
140
|
+
}
|