@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/search/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type Transport } from '@sixtyninecommerce/core';
|
|
2
2
|
import type { Call } from '../types.js';
|
|
3
3
|
/** What `admin.search.entities` searches. */
|
|
4
4
|
export type SearchEntityType = 'PRODUCTS' | 'ORDERS' | 'CUSTOMERS' | 'CONTENT';
|
|
@@ -76,6 +76,55 @@ export interface SearchEntitiesOptions extends Call {
|
|
|
76
76
|
export declare const SEARCH_ENTITIES_MIN_TERM_LENGTH = 2;
|
|
77
77
|
export declare const SEARCH_ENTITIES_MAX_TAKE = 10;
|
|
78
78
|
export declare const SEARCH_ACROSS_ENTITIES_QUERY = "\n query SearchAcrossEntities($input: CommandSearchInput!) {\n searchAcrossEntities(input: $input) {\n products {\n id\n name\n slug\n previewUrl\n }\n orders {\n id\n code\n state\n orderPlacedAt\n totalWithTax\n currencyCode\n lifecycleStatus\n }\n customers {\n id\n firstName\n lastName\n emailAddress\n company\n }\n content {\n id\n collectionId\n collectionSlug\n slug\n status\n title\n }\n skipped {\n type\n reason\n }\n }\n }\n";
|
|
79
|
+
/**
|
|
80
|
+
* The store's search indexes `search.index` reads, one per kind of record. Each holds the store's
|
|
81
|
+
* rows of that kind; the products index is the admin catalogue index, not the storefront's.
|
|
82
|
+
*/
|
|
83
|
+
export declare const SEARCH_INDEXES: readonly ["products", "orders", "customers", "facets", "promotions", "customer_groups", "stock_locations", "collections"];
|
|
84
|
+
export type SearchIndex = (typeof SEARCH_INDEXES)[number];
|
|
85
|
+
/** The engine's bound on the clauses of one `search.index` call, `filters` and groups together. */
|
|
86
|
+
export declare const SEARCH_INDEX_MAX_FILTERS = 32;
|
|
87
|
+
export interface SearchIndexInput {
|
|
88
|
+
/** Full text; `''` matches every row the filters keep. */
|
|
89
|
+
term: string;
|
|
90
|
+
/**
|
|
91
|
+
* Clauses, all of which must hold, each one of exactly these shapes on an attribute the index
|
|
92
|
+
* lets you filter on: `field = "value"`, `field = true|false`, `field STARTS WITH "value"`,
|
|
93
|
+
* `field CONTAINS "value"`, `field IN ["a", "b"]`, `field IS EMPTY`. Quote a string value with
|
|
94
|
+
* {@link escapeSearchFilterValue}: `code STARTS WITH "${escapeSearchFilterValue(prefix)}"`.
|
|
95
|
+
*/
|
|
96
|
+
filters?: readonly string[];
|
|
97
|
+
/** Groups of clauses: each group must hold, and holds when ANY of its own clauses does. */
|
|
98
|
+
filterGroups?: ReadonlyArray<readonly string[]>;
|
|
99
|
+
/** `field` ascending or `-field` descending, on a field the index sorts by; relevance otherwise. */
|
|
100
|
+
sort?: string;
|
|
101
|
+
/** Rows to skip, 0 when omitted. */
|
|
102
|
+
skip?: number;
|
|
103
|
+
/** Rows to answer, 25 when omitted. */
|
|
104
|
+
take?: number;
|
|
105
|
+
}
|
|
106
|
+
/** One hit: the record's id, how well it matched, and the index's copy of it. */
|
|
107
|
+
export interface SearchIndexHit {
|
|
108
|
+
id: string;
|
|
109
|
+
/** The search engine's ranking score, 0 to 1: higher is a better match. */
|
|
110
|
+
score: number;
|
|
111
|
+
/**
|
|
112
|
+
* The index's snapshot of the record, as the store may see it: written by a job after the
|
|
113
|
+
* record's change commits, so it can lag by seconds. Read the record itself for current values.
|
|
114
|
+
*/
|
|
115
|
+
document: Record<string, unknown>;
|
|
116
|
+
}
|
|
117
|
+
export interface SearchIndexResult {
|
|
118
|
+
items: SearchIndexHit[];
|
|
119
|
+
/** Every hit the term and filters match, not only this page's. */
|
|
120
|
+
total: number;
|
|
121
|
+
}
|
|
122
|
+
export declare const SEARCH_ENTITIES_QUERY = "\n query SearchIndex($input: EntitySearchInput!) {\n searchEntities(input: $input) {\n items {\n id\n score\n document\n }\n totalItems\n }\n }\n";
|
|
123
|
+
/**
|
|
124
|
+
* A string value inside a `search.index` filter's double quotes: its backslashes and quotes
|
|
125
|
+
* escaped, so what a person typed can never close the literal and add a clause.
|
|
126
|
+
*/
|
|
127
|
+
export declare function escapeSearchFilterValue(value: string): string;
|
|
79
128
|
/**
|
|
80
129
|
* One search across the store (spec §7 `search.entities`): products, orders, customers and
|
|
81
130
|
* content items matching a term, in one call.
|
|
@@ -94,6 +143,32 @@ export declare const SEARCH_ACROSS_ENTITIES_QUERY = "\n query SearchAcrossEntit
|
|
|
94
143
|
* outside 1..{@link SEARCH_ENTITIES_MAX_TAKE}, or an empty `types` list.
|
|
95
144
|
*/
|
|
96
145
|
export interface SearchModule {
|
|
146
|
+
/** @effect read */
|
|
97
147
|
entities(term: string, options?: SearchEntitiesOptions): Promise<EntitySearchResult>;
|
|
148
|
+
/**
|
|
149
|
+
* One page of one search index of the store: hits in relevance order (or `sort`'s), each with
|
|
150
|
+
* the index's copy of the record. Use it to find ids by text or by an indexed attribute the
|
|
151
|
+
* record's own list cannot filter on, then read the records themselves.
|
|
152
|
+
*
|
|
153
|
+
* - **The store is always the one you act on**: no filter reaches another store's rows.
|
|
154
|
+
* - **Documents are index snapshots**, updated by a job after each change: read the record for
|
|
155
|
+
* current values, and expect a just-written record to be missing for a few seconds.
|
|
156
|
+
* - Needs the read permission of the index's own list: `ReadCatalog` or `ReadProduct` for
|
|
157
|
+
* products; `ReadOrder` for orders; `ReadCustomer` for customers; `ReadCustomer` or
|
|
158
|
+
* `ReadCustomerGroup` for customer groups; `ReadCatalog`, `ReadProduct` or `ReadFacet` for
|
|
159
|
+
* facets; `ReadPromotion`; `ReadCatalog` or `ReadStockLocation`; `ReadCatalog` or
|
|
160
|
+
* `ReadCollection`. Without it: `PermissionDeniedError`.
|
|
161
|
+
* - An app reading customer data below `full` is refused the orders and customers indexes
|
|
162
|
+
* (`CUSTOMER_DATA_NOT_GRANTED`): the hits alone would say which customer matches a name.
|
|
163
|
+
*
|
|
164
|
+
* Refused: an index not in {@link SEARCH_INDEXES} (`ValidationError` `SEARCH_INPUT_INVALID`, before
|
|
165
|
+
* anything is asked); and by the engine with `SEARCH_INPUT_INVALID` (400) a clause on an attribute
|
|
166
|
+
* the index does not filter on or in another syntax, more than {@link SEARCH_INDEX_MAX_FILTERS}
|
|
167
|
+
* clauses, or a negative `skip`/`take`. A `sort` field the index cannot sort on is ignored.
|
|
168
|
+
* `SERVICE_UNAVAILABLE` (503, retryable) when the search service did not answer.
|
|
169
|
+
*
|
|
170
|
+
* @effect read
|
|
171
|
+
*/
|
|
172
|
+
index(index: SearchIndex, input: SearchIndexInput, options?: Call): Promise<SearchIndexResult>;
|
|
98
173
|
}
|
|
99
174
|
export declare function createSearchModule(transport: Transport): SearchModule;
|
package/dist/search/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ValidationError } from '@sixtyninecommerce/core';
|
|
1
2
|
/** The engine's bounds, as `searchAcrossEntities` documents them. */
|
|
2
3
|
export const SEARCH_ENTITIES_MIN_TERM_LENGTH = 2;
|
|
3
4
|
export const SEARCH_ENTITIES_MAX_TAKE = 10;
|
|
@@ -41,6 +42,41 @@ export const SEARCH_ACROSS_ENTITIES_QUERY = /* GraphQL */ `
|
|
|
41
42
|
}
|
|
42
43
|
}
|
|
43
44
|
`;
|
|
45
|
+
/**
|
|
46
|
+
* The store's search indexes `search.index` reads, one per kind of record. Each holds the store's
|
|
47
|
+
* rows of that kind; the products index is the admin catalogue index, not the storefront's.
|
|
48
|
+
*/
|
|
49
|
+
export const SEARCH_INDEXES = [
|
|
50
|
+
'products',
|
|
51
|
+
'orders',
|
|
52
|
+
'customers',
|
|
53
|
+
'facets',
|
|
54
|
+
'promotions',
|
|
55
|
+
'customer_groups',
|
|
56
|
+
'stock_locations',
|
|
57
|
+
'collections',
|
|
58
|
+
];
|
|
59
|
+
/** The engine's bound on the clauses of one `search.index` call, `filters` and groups together. */
|
|
60
|
+
export const SEARCH_INDEX_MAX_FILTERS = 32;
|
|
61
|
+
export const SEARCH_ENTITIES_QUERY = /* GraphQL */ `
|
|
62
|
+
query SearchIndex($input: EntitySearchInput!) {
|
|
63
|
+
searchEntities(input: $input) {
|
|
64
|
+
items {
|
|
65
|
+
id
|
|
66
|
+
score
|
|
67
|
+
document
|
|
68
|
+
}
|
|
69
|
+
totalItems
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
`;
|
|
73
|
+
/**
|
|
74
|
+
* A string value inside a `search.index` filter's double quotes: its backslashes and quotes
|
|
75
|
+
* escaped, so what a person typed can never close the literal and add a clause.
|
|
76
|
+
*/
|
|
77
|
+
export function escapeSearchFilterValue(value) {
|
|
78
|
+
return value.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
|
|
79
|
+
}
|
|
44
80
|
export function createSearchModule(transport) {
|
|
45
81
|
return {
|
|
46
82
|
async entities(term, options = {}) {
|
|
@@ -58,5 +94,32 @@ export function createSearchModule(transport) {
|
|
|
58
94
|
}, call);
|
|
59
95
|
return data.searchAcrossEntities;
|
|
60
96
|
},
|
|
97
|
+
async index(index, input, options) {
|
|
98
|
+
if (!SEARCH_INDEXES.includes(index)) {
|
|
99
|
+
throw new ValidationError({
|
|
100
|
+
code: 'SEARCH_INPUT_INVALID',
|
|
101
|
+
message: `The search index must be one of ${SEARCH_INDEXES.join(', ')}.`,
|
|
102
|
+
status: 400,
|
|
103
|
+
service: 'vendure',
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
const { term, filters, filterGroups, sort, skip, take } = input;
|
|
107
|
+
const data = await transport.graphql({
|
|
108
|
+
api: 'admin',
|
|
109
|
+
query: SEARCH_ENTITIES_QUERY,
|
|
110
|
+
variables: {
|
|
111
|
+
input: {
|
|
112
|
+
term,
|
|
113
|
+
entityType: index,
|
|
114
|
+
...(take === undefined ? {} : { take }),
|
|
115
|
+
...(skip === undefined ? {} : { skip }),
|
|
116
|
+
...(sort === undefined || sort === '' ? {} : { sort }),
|
|
117
|
+
...(filters?.length ? { filters: [...filters] } : {}),
|
|
118
|
+
...(filterGroups?.length ? { filterGroups: filterGroups.map((g) => [...g]) } : {}),
|
|
119
|
+
},
|
|
120
|
+
},
|
|
121
|
+
}, options);
|
|
122
|
+
return { items: data.searchEntities.items, total: data.searchEntities.totalItems };
|
|
123
|
+
},
|
|
61
124
|
};
|
|
62
125
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type Transport } from '@sixtyninecommerce/core';
|
|
2
|
+
import type { Call, ConfigurableOperationDefinition } from '../types.js';
|
|
3
|
+
/** What a shipping method's three operations may be, each with the arguments it takes. */
|
|
4
|
+
export interface ShippingDefinitions {
|
|
5
|
+
/** What a method's `calculator` may be: how it prices an order. */
|
|
6
|
+
calculators: ConfigurableOperationDefinition[];
|
|
7
|
+
/** What a method's `checker` may be: which orders it is offered for. */
|
|
8
|
+
eligibilityCheckers: ConfigurableOperationDefinition[];
|
|
9
|
+
/** What a method's `fulfillmentHandler` may be (`manual-fulfillment`, a carrier's handler). */
|
|
10
|
+
fulfillmentHandlers: ConfigurableOperationDefinition[];
|
|
11
|
+
}
|
|
12
|
+
/** `admin.shipping.definitions`. */
|
|
13
|
+
export interface ShippingDefinitionsModule {
|
|
14
|
+
/**
|
|
15
|
+
* The calculators, eligibility checkers and fulfillment handlers the engine has registered, in
|
|
16
|
+
* one request: the same whichever store the client is on (a handler whose plugin the store does
|
|
17
|
+
* not hold is listed, and refused `PLUGIN_ACCESS_DENIED` when a method picks it). Labels and
|
|
18
|
+
* descriptions are in the language of the request. Needs `ReadSettings`, `ReadOrder` or
|
|
19
|
+
* `ReadShippingMethod` (any one).
|
|
20
|
+
*
|
|
21
|
+
* `args[].required` is NOT the enforced rule (see `ConfigArgDefinition.required`); never gate
|
|
22
|
+
* a form on it.
|
|
23
|
+
*
|
|
24
|
+
* @effect read
|
|
25
|
+
*/
|
|
26
|
+
get(options?: Call): Promise<ShippingDefinitions>;
|
|
27
|
+
}
|
|
28
|
+
export declare const SHIPPING_DEFINITIONS_QUERY = "\n query ShippingDefinitions {\n shippingCalculators { \n code\n description\n args {\n name\n type\n list\n required\n defaultValue\n label\n description\n ui\n }\n }\n shippingEligibilityCheckers { \n code\n description\n args {\n name\n type\n list\n required\n defaultValue\n label\n description\n ui\n }\n }\n fulfillmentHandlers { \n code\n description\n args {\n name\n type\n list\n required\n defaultValue\n label\n description\n ui\n }\n }\n }\n";
|
|
29
|
+
export declare function createShippingDefinitionsModule(transport: Transport): ShippingDefinitionsModule;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { UpstreamError } from '@sixtyninecommerce/core';
|
|
2
|
+
const DEFINITION_FIELDS = /* GraphQL */ `
|
|
3
|
+
code
|
|
4
|
+
description
|
|
5
|
+
args {
|
|
6
|
+
name
|
|
7
|
+
type
|
|
8
|
+
list
|
|
9
|
+
required
|
|
10
|
+
defaultValue
|
|
11
|
+
label
|
|
12
|
+
description
|
|
13
|
+
ui
|
|
14
|
+
}
|
|
15
|
+
`;
|
|
16
|
+
export const SHIPPING_DEFINITIONS_QUERY = /* GraphQL */ `
|
|
17
|
+
query ShippingDefinitions {
|
|
18
|
+
shippingCalculators { ${DEFINITION_FIELDS} }
|
|
19
|
+
shippingEligibilityCheckers { ${DEFINITION_FIELDS} }
|
|
20
|
+
fulfillmentHandlers { ${DEFINITION_FIELDS} }
|
|
21
|
+
}
|
|
22
|
+
`;
|
|
23
|
+
export function createShippingDefinitionsModule(transport) {
|
|
24
|
+
return {
|
|
25
|
+
async get(options) {
|
|
26
|
+
const data = await transport.graphql({ api: 'admin', query: SHIPPING_DEFINITIONS_QUERY, variables: {} }, options);
|
|
27
|
+
// Each list is read by name, so a response missing one is refused, never answered empty.
|
|
28
|
+
const list = (field) => {
|
|
29
|
+
const value = data?.[field];
|
|
30
|
+
if (!Array.isArray(value)) {
|
|
31
|
+
throw new UpstreamError({
|
|
32
|
+
code: 'UNEXPECTED_RESPONSE',
|
|
33
|
+
message: `The engine answered without "${field}".`,
|
|
34
|
+
status: 502,
|
|
35
|
+
service: 'vendure',
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
return value;
|
|
39
|
+
};
|
|
40
|
+
return {
|
|
41
|
+
calculators: list('shippingCalculators'),
|
|
42
|
+
eligibilityCheckers: list('shippingEligibilityCheckers'),
|
|
43
|
+
fulfillmentHandlers: list('fulfillmentHandlers'),
|
|
44
|
+
};
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import type { Transport } from '@sixtyninecommerce/core';
|
|
2
|
+
import type { Call } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* A store's fulfillment profile: a named binding of a warehouse, a fulfillment handler, a
|
|
5
|
+
* shipping method and a minimum order. A fulfilment created with a profile is judged against its
|
|
6
|
+
* minimum and charged its shipping method's delivery cost (`fulfillments.profileChargePreview`
|
|
7
|
+
* prices it beforehand).
|
|
8
|
+
*/
|
|
9
|
+
export interface FulfillmentProfile {
|
|
10
|
+
id: string;
|
|
11
|
+
/** Stable per store; unique within the store. */
|
|
12
|
+
code: string;
|
|
13
|
+
name: string;
|
|
14
|
+
/** A disabled profile is not offered when fulfilling an order. */
|
|
15
|
+
enabled: boolean;
|
|
16
|
+
/** The warehouse (stock location) the profile ships from. */
|
|
17
|
+
stockLocationId: string;
|
|
18
|
+
/** The fulfillment handler (carrier) code, e.g. `manual-fulfillment`. */
|
|
19
|
+
defaultHandlerCode: string;
|
|
20
|
+
/** The shipping method whose price is the profile's delivery charge. */
|
|
21
|
+
shippingMethodId: string;
|
|
22
|
+
/**
|
|
23
|
+
* The minimum a fulfilment's selected lines must reach, in MINOR units of the store's default
|
|
24
|
+
* currency, NET of tax. `0` is no minimum.
|
|
25
|
+
*/
|
|
26
|
+
minOrder: number;
|
|
27
|
+
/** True for the store's default profile, the one storefront checkout applies. */
|
|
28
|
+
isDefault: boolean;
|
|
29
|
+
/** ISO-8601, UTC. */
|
|
30
|
+
createdAt: string;
|
|
31
|
+
/** ISO-8601, UTC. */
|
|
32
|
+
updatedAt: string;
|
|
33
|
+
}
|
|
34
|
+
export interface CreateFulfillmentProfileInput {
|
|
35
|
+
name: string;
|
|
36
|
+
code: string;
|
|
37
|
+
/** Default `true`. */
|
|
38
|
+
enabled?: boolean;
|
|
39
|
+
/** One of the store's own stock locations. */
|
|
40
|
+
stockLocationId: string;
|
|
41
|
+
defaultHandlerCode: string;
|
|
42
|
+
/** One of the store's own shipping methods. */
|
|
43
|
+
shippingMethodId: string;
|
|
44
|
+
/** Minor units, net, in the store's default currency. Default `0`. */
|
|
45
|
+
minOrder?: number;
|
|
46
|
+
}
|
|
47
|
+
/** A PATCH: a key left out keeps the stored value. */
|
|
48
|
+
export interface UpdateFulfillmentProfileInput {
|
|
49
|
+
name?: string;
|
|
50
|
+
code?: string;
|
|
51
|
+
enabled?: boolean;
|
|
52
|
+
stockLocationId?: string;
|
|
53
|
+
defaultHandlerCode?: string;
|
|
54
|
+
shippingMethodId?: string;
|
|
55
|
+
minOrder?: number;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Who is emailed when a fulfilment is created with a handler, in this store. One record per
|
|
59
|
+
* handler; a handler with no record notifies nobody.
|
|
60
|
+
*/
|
|
61
|
+
export interface FulfillmentHandlerNotification {
|
|
62
|
+
id: string;
|
|
63
|
+
handlerCode: string;
|
|
64
|
+
/** Off pauses the mails without forgetting the recipients. */
|
|
65
|
+
enabled: boolean;
|
|
66
|
+
/** Trimmed, de-duplicated (case-insensitive) addresses, at most 25. */
|
|
67
|
+
emails: string[];
|
|
68
|
+
/** ISO-8601, UTC. */
|
|
69
|
+
createdAt: string;
|
|
70
|
+
/** ISO-8601, UTC. */
|
|
71
|
+
updatedAt: string;
|
|
72
|
+
}
|
|
73
|
+
export interface SetFulfillmentHandlerNotificationInput {
|
|
74
|
+
handlerCode: string;
|
|
75
|
+
/** Left out: `true` for a new record, unchanged for an existing one. */
|
|
76
|
+
enabled?: boolean;
|
|
77
|
+
/** The WHOLE list: it replaces the stored one. `[]` clears it. */
|
|
78
|
+
emails: string[];
|
|
79
|
+
}
|
|
80
|
+
/** `admin.shipping.fulfillmentProfiles.handlerNotifications`. */
|
|
81
|
+
export interface FulfillmentHandlerNotificationsModule {
|
|
82
|
+
/**
|
|
83
|
+
* Every handler's recipients in the store, by handler code. Needs `ReadShippingMethod`.
|
|
84
|
+
*
|
|
85
|
+
* @effect read
|
|
86
|
+
* @permission ReadShippingMethod
|
|
87
|
+
*/
|
|
88
|
+
list(options?: Call): Promise<FulfillmentHandlerNotification[]>;
|
|
89
|
+
/**
|
|
90
|
+
* Create or replace one handler's recipients. Needs `UpdateShippingMethod`. Refused, with
|
|
91
|
+
* nothing saved, for a blank handler code, an address that is not one, or more than 25
|
|
92
|
+
* addresses (`USER_INPUT_ERROR`, a `ValidationError`). The handler code is not checked against
|
|
93
|
+
* the store's handlers: a record for a handler nothing uses is kept and never mails.
|
|
94
|
+
*
|
|
95
|
+
* @effect write
|
|
96
|
+
* @permission UpdateShippingMethod
|
|
97
|
+
*/
|
|
98
|
+
set(input: SetFulfillmentHandlerNotificationInput, options?: Call): Promise<FulfillmentHandlerNotification>;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* `admin.shipping.fulfillmentProfiles`: the fulfillment profiles of the store the client is
|
|
102
|
+
* scoped to. There is no channel argument; another store is addressed with
|
|
103
|
+
* `admin.withTenant(...)`.
|
|
104
|
+
*
|
|
105
|
+
* A well-formed profile id the store does not have (another store's, or none at all) is refused
|
|
106
|
+
* on every write with `FULFILLMENT_PROFILE_NOT_FOUND` (`NotFoundError`, 404), worded the same
|
|
107
|
+
* either way, and `get` answers `null` for it. An id that is not a uuid is refused by the engine
|
|
108
|
+
* before any of that, on every method `get` included, with `ENTITY_NOT_FOUND` (`NotFoundError`).
|
|
109
|
+
*/
|
|
110
|
+
export interface FulfillmentProfilesModule {
|
|
111
|
+
/**
|
|
112
|
+
* Every profile of the store, oldest first. Needs `ReadShippingMethod`.
|
|
113
|
+
*
|
|
114
|
+
* @effect read
|
|
115
|
+
* @permission ReadShippingMethod
|
|
116
|
+
*/
|
|
117
|
+
list(options?: Call): Promise<FulfillmentProfile[]>;
|
|
118
|
+
/**
|
|
119
|
+
* One profile, or `null` when the store has none with that id.
|
|
120
|
+
*
|
|
121
|
+
* @effect read
|
|
122
|
+
* @permission ReadShippingMethod
|
|
123
|
+
*/
|
|
124
|
+
get(id: string, options?: Call): Promise<FulfillmentProfile | null>;
|
|
125
|
+
/**
|
|
126
|
+
* Create a profile. Needs `UpdateShippingMethod`. A warehouse or shipping method the store
|
|
127
|
+
* does not have is refused `ENTITY_NOT_FOUND` (`NotFoundError`), the same for another store's
|
|
128
|
+
* id as for one that exists nowhere.
|
|
129
|
+
*
|
|
130
|
+
* @effect write
|
|
131
|
+
* @permission UpdateShippingMethod
|
|
132
|
+
*/
|
|
133
|
+
create(input: CreateFulfillmentProfileInput, options?: Call): Promise<FulfillmentProfile>;
|
|
134
|
+
/**
|
|
135
|
+
* Change a profile; a key left out keeps its value. Needs `UpdateShippingMethod`. Refused
|
|
136
|
+
* `FULFILLMENT_PROFILE_NOT_FOUND` for a profile the store does not have, and
|
|
137
|
+
* `ENTITY_NOT_FOUND` for a warehouse or shipping method it does not have. A changed minimum
|
|
138
|
+
* binds the next fulfilment; fulfilments already created keep what they were charged.
|
|
139
|
+
*
|
|
140
|
+
* @effect write
|
|
141
|
+
* @permission UpdateShippingMethod
|
|
142
|
+
*/
|
|
143
|
+
update(id: string, input: UpdateFulfillmentProfileInput, options?: Call): Promise<FulfillmentProfile>;
|
|
144
|
+
/**
|
|
145
|
+
* Delete a profile for good. When it was the store's default the store is left with NO
|
|
146
|
+
* default profile, so checkout applies no profile minimum until another is set. Fulfilments
|
|
147
|
+
* already created with it are unchanged. Needs `UpdateShippingMethod`; refused
|
|
148
|
+
* `FULFILLMENT_PROFILE_NOT_FOUND` for a profile the store does not have.
|
|
149
|
+
*
|
|
150
|
+
* @effect destructive
|
|
151
|
+
* @permission UpdateShippingMethod
|
|
152
|
+
*/
|
|
153
|
+
delete(id: string, options?: Call): Promise<void>;
|
|
154
|
+
/**
|
|
155
|
+
* Make a profile the store's default (the one storefront checkout applies); answers it.
|
|
156
|
+
* Needs `UpdateShippingMethod`; refused `FULFILLMENT_PROFILE_NOT_FOUND` for a profile the
|
|
157
|
+
* store does not have.
|
|
158
|
+
*
|
|
159
|
+
* @effect write
|
|
160
|
+
* @permission UpdateShippingMethod
|
|
161
|
+
*/
|
|
162
|
+
setDefault(id: string, options?: Call): Promise<FulfillmentProfile>;
|
|
163
|
+
/** Who is emailed when a fulfilment is created with a handler. */
|
|
164
|
+
handlerNotifications: FulfillmentHandlerNotificationsModule;
|
|
165
|
+
}
|
|
166
|
+
export declare const FULFILLMENT_PROFILES_QUERY = "\n query FulfillmentProfiles {\n fulfillmentProfiles { \n id\n code\n name\n enabled\n stockLocationId\n defaultHandlerCode\n shippingMethodId\n minOrder\n isDefault\n createdAt\n updatedAt\n }\n }\n";
|
|
167
|
+
export declare const FULFILLMENT_PROFILE_QUERY = "\n query FulfillmentProfile($id: ID!) {\n fulfillmentProfile(id: $id) { \n id\n code\n name\n enabled\n stockLocationId\n defaultHandlerCode\n shippingMethodId\n minOrder\n isDefault\n createdAt\n updatedAt\n }\n }\n";
|
|
168
|
+
export declare const CREATE_FULFILLMENT_PROFILE_MUTATION = "\n mutation CreateFulfillmentProfile($input: CreateFulfillmentProfileInput!) {\n createFulfillmentProfile(input: $input) { \n id\n code\n name\n enabled\n stockLocationId\n defaultHandlerCode\n shippingMethodId\n minOrder\n isDefault\n createdAt\n updatedAt\n }\n }\n";
|
|
169
|
+
export declare const UPDATE_FULFILLMENT_PROFILE_MUTATION = "\n mutation UpdateFulfillmentProfile($input: UpdateFulfillmentProfileInput!) {\n updateFulfillmentProfile(input: $input) { \n id\n code\n name\n enabled\n stockLocationId\n defaultHandlerCode\n shippingMethodId\n minOrder\n isDefault\n createdAt\n updatedAt\n }\n }\n";
|
|
170
|
+
export declare const DELETE_FULFILLMENT_PROFILE_MUTATION = "\n mutation DeleteFulfillmentProfile($id: ID!) {\n deleteFulfillmentProfile(id: $id) { result message }\n }\n";
|
|
171
|
+
export declare const SET_DEFAULT_FULFILLMENT_PROFILE_MUTATION = "\n mutation SetDefaultFulfillmentProfile($id: ID!) {\n setDefaultFulfillmentProfile(id: $id) { \n id\n code\n name\n enabled\n stockLocationId\n defaultHandlerCode\n shippingMethodId\n minOrder\n isDefault\n createdAt\n updatedAt\n }\n }\n";
|
|
172
|
+
export declare const FULFILLMENT_HANDLER_NOTIFICATIONS_QUERY = "\n query FulfillmentHandlerNotifications {\n fulfillmentHandlerNotifications { \n id\n handlerCode\n enabled\n emails\n createdAt\n updatedAt\n }\n }\n";
|
|
173
|
+
export declare const SET_FULFILLMENT_HANDLER_NOTIFICATION_MUTATION = "\n mutation SetFulfillmentHandlerNotification($input: SetFulfillmentHandlerNotificationInput!) {\n setFulfillmentHandlerNotification(input: $input) { \n id\n handlerCode\n enabled\n emails\n createdAt\n updatedAt\n }\n }\n";
|
|
174
|
+
export declare function createFulfillmentProfilesModule(transport: Transport): FulfillmentProfilesModule;
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { assertDeleted } from '../catalog/types.js';
|
|
2
|
+
const PROFILE_FIELDS = /* GraphQL */ `
|
|
3
|
+
id
|
|
4
|
+
code
|
|
5
|
+
name
|
|
6
|
+
enabled
|
|
7
|
+
stockLocationId
|
|
8
|
+
defaultHandlerCode
|
|
9
|
+
shippingMethodId
|
|
10
|
+
minOrder
|
|
11
|
+
isDefault
|
|
12
|
+
createdAt
|
|
13
|
+
updatedAt
|
|
14
|
+
`;
|
|
15
|
+
const NOTIFICATION_FIELDS = /* GraphQL */ `
|
|
16
|
+
id
|
|
17
|
+
handlerCode
|
|
18
|
+
enabled
|
|
19
|
+
emails
|
|
20
|
+
createdAt
|
|
21
|
+
updatedAt
|
|
22
|
+
`;
|
|
23
|
+
export const FULFILLMENT_PROFILES_QUERY = /* GraphQL */ `
|
|
24
|
+
query FulfillmentProfiles {
|
|
25
|
+
fulfillmentProfiles { ${PROFILE_FIELDS} }
|
|
26
|
+
}
|
|
27
|
+
`;
|
|
28
|
+
export const FULFILLMENT_PROFILE_QUERY = /* GraphQL */ `
|
|
29
|
+
query FulfillmentProfile($id: ID!) {
|
|
30
|
+
fulfillmentProfile(id: $id) { ${PROFILE_FIELDS} }
|
|
31
|
+
}
|
|
32
|
+
`;
|
|
33
|
+
export const CREATE_FULFILLMENT_PROFILE_MUTATION = /* GraphQL */ `
|
|
34
|
+
mutation CreateFulfillmentProfile($input: CreateFulfillmentProfileInput!) {
|
|
35
|
+
createFulfillmentProfile(input: $input) { ${PROFILE_FIELDS} }
|
|
36
|
+
}
|
|
37
|
+
`;
|
|
38
|
+
export const UPDATE_FULFILLMENT_PROFILE_MUTATION = /* GraphQL */ `
|
|
39
|
+
mutation UpdateFulfillmentProfile($input: UpdateFulfillmentProfileInput!) {
|
|
40
|
+
updateFulfillmentProfile(input: $input) { ${PROFILE_FIELDS} }
|
|
41
|
+
}
|
|
42
|
+
`;
|
|
43
|
+
export const DELETE_FULFILLMENT_PROFILE_MUTATION = /* GraphQL */ `
|
|
44
|
+
mutation DeleteFulfillmentProfile($id: ID!) {
|
|
45
|
+
deleteFulfillmentProfile(id: $id) { result message }
|
|
46
|
+
}
|
|
47
|
+
`;
|
|
48
|
+
export const SET_DEFAULT_FULFILLMENT_PROFILE_MUTATION = /* GraphQL */ `
|
|
49
|
+
mutation SetDefaultFulfillmentProfile($id: ID!) {
|
|
50
|
+
setDefaultFulfillmentProfile(id: $id) { ${PROFILE_FIELDS} }
|
|
51
|
+
}
|
|
52
|
+
`;
|
|
53
|
+
export const FULFILLMENT_HANDLER_NOTIFICATIONS_QUERY = /* GraphQL */ `
|
|
54
|
+
query FulfillmentHandlerNotifications {
|
|
55
|
+
fulfillmentHandlerNotifications { ${NOTIFICATION_FIELDS} }
|
|
56
|
+
}
|
|
57
|
+
`;
|
|
58
|
+
export const SET_FULFILLMENT_HANDLER_NOTIFICATION_MUTATION = /* GraphQL */ `
|
|
59
|
+
mutation SetFulfillmentHandlerNotification($input: SetFulfillmentHandlerNotificationInput!) {
|
|
60
|
+
setFulfillmentHandlerNotification(input: $input) { ${NOTIFICATION_FIELDS} }
|
|
61
|
+
}
|
|
62
|
+
`;
|
|
63
|
+
export function createFulfillmentProfilesModule(transport) {
|
|
64
|
+
const call = async (query, variables, options) => transport.graphql({ api: 'admin', query, variables }, options);
|
|
65
|
+
return {
|
|
66
|
+
async list(options) {
|
|
67
|
+
const data = await call(FULFILLMENT_PROFILES_QUERY, undefined, options);
|
|
68
|
+
return data.fulfillmentProfiles;
|
|
69
|
+
},
|
|
70
|
+
async get(id, options) {
|
|
71
|
+
const data = await call(FULFILLMENT_PROFILE_QUERY, { id }, options);
|
|
72
|
+
return data.fulfillmentProfile ?? null;
|
|
73
|
+
},
|
|
74
|
+
async create(input, options) {
|
|
75
|
+
const data = await call(CREATE_FULFILLMENT_PROFILE_MUTATION, { input }, options);
|
|
76
|
+
return data.createFulfillmentProfile;
|
|
77
|
+
},
|
|
78
|
+
async update(id, input, options) {
|
|
79
|
+
const data = await call(UPDATE_FULFILLMENT_PROFILE_MUTATION,
|
|
80
|
+
// The id goes last: an `id` key smuggled into the patch cannot redirect the write.
|
|
81
|
+
{ input: { ...input, id } }, options);
|
|
82
|
+
return data.updateFulfillmentProfile;
|
|
83
|
+
},
|
|
84
|
+
async delete(id, options) {
|
|
85
|
+
const data = await call(DELETE_FULFILLMENT_PROFILE_MUTATION, { id }, options);
|
|
86
|
+
// The engine refuses by throwing today; a NOT_DELETED answer must still never pass as done.
|
|
87
|
+
assertDeleted('FULFILLMENT_PROFILE_NOT_DELETED', [data.deleteFulfillmentProfile]);
|
|
88
|
+
},
|
|
89
|
+
async setDefault(id, options) {
|
|
90
|
+
const data = await call(SET_DEFAULT_FULFILLMENT_PROFILE_MUTATION, { id }, options);
|
|
91
|
+
return data.setDefaultFulfillmentProfile;
|
|
92
|
+
},
|
|
93
|
+
handlerNotifications: {
|
|
94
|
+
async list(options) {
|
|
95
|
+
const data = await call(FULFILLMENT_HANDLER_NOTIFICATIONS_QUERY, undefined, options);
|
|
96
|
+
return data.fulfillmentHandlerNotifications;
|
|
97
|
+
},
|
|
98
|
+
async set(input, options) {
|
|
99
|
+
const data = await call(SET_FULFILLMENT_HANDLER_NOTIFICATION_MUTATION, { input }, options);
|
|
100
|
+
return data.setFulfillmentHandlerNotification;
|
|
101
|
+
},
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import type { Transport } from '@sixtyninecommerce/core';
|
|
2
|
+
import type { Call } from '../types.js';
|
|
3
|
+
/** How the order reference sent to C.J. Hendriks is prefixed. */
|
|
4
|
+
export type HendriksWirePrefixMode = 'year' | 'custom';
|
|
5
|
+
/** A store's C.J. Hendriks 3PL settings: one record per store. */
|
|
6
|
+
export interface HendriksConfig {
|
|
7
|
+
id: string;
|
|
8
|
+
channelId: string;
|
|
9
|
+
/** Gates every Hendriks export of the store. */
|
|
10
|
+
enabled: boolean;
|
|
11
|
+
/** The plugins-service export pipeline that sends the orders; `null` is not linked. */
|
|
12
|
+
pipelineId: string | null;
|
|
13
|
+
/** `year` prefixes the current UTC year; `custom` prefixes {@link wirePrefixDigits}. */
|
|
14
|
+
wirePrefixMode: HendriksWirePrefixMode;
|
|
15
|
+
/** 1 to 4 digits without a leading zero. Only read in `custom` mode; `null` in `year` mode. */
|
|
16
|
+
wirePrefixDigits: string | null;
|
|
17
|
+
/**
|
|
18
|
+
* Refuse to export an order the source platform already sent to its own fulfillment
|
|
19
|
+
* provider. On by default: while a migrated shop is still live both systems feed the same
|
|
20
|
+
* warehouse, and neither can spot the other's reference, so the goods would ship twice.
|
|
21
|
+
*/
|
|
22
|
+
blockSourceFulfilledOrders: boolean;
|
|
23
|
+
/** ISO-8601, UTC. */
|
|
24
|
+
createdAt: string;
|
|
25
|
+
/** ISO-8601, UTC. */
|
|
26
|
+
updatedAt: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* A PATCH: a key left out keeps the stored value. The custom-prefix rule is judged on the
|
|
30
|
+
* RESULTING settings, so switching to `custom` needs `wirePrefixDigits` in the same call unless
|
|
31
|
+
* valid digits are already stored.
|
|
32
|
+
*/
|
|
33
|
+
export interface UpdateHendriksConfigInput {
|
|
34
|
+
enabled?: boolean;
|
|
35
|
+
/** `null` unlinks the pipeline. */
|
|
36
|
+
pipelineId?: string | null;
|
|
37
|
+
wirePrefixMode?: HendriksWirePrefixMode;
|
|
38
|
+
/** Cleared by the engine whenever the resulting mode is `year`. */
|
|
39
|
+
wirePrefixDigits?: string | null;
|
|
40
|
+
blockSourceFulfilledOrders?: boolean;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* The C.J. Hendriks 3PL settings of the store the client is scoped to
|
|
44
|
+
* (`admin.shipping.hendriks.config`). There is no channel argument: a SuperAdmin head configures
|
|
45
|
+
* ANOTHER store with `admin.withTenant({ scope: { kind: 'channel', code } })`, or a per-call
|
|
46
|
+
* `tenant`.
|
|
47
|
+
*/
|
|
48
|
+
export interface HendriksConfigModule {
|
|
49
|
+
/**
|
|
50
|
+
* The store's settings, or `null` when it never saved any. Needs `ReadSettings`, and is
|
|
51
|
+
* answered for a store without the Hendriks plugin too (a head reads it to decide whether to
|
|
52
|
+
* show the integration).
|
|
53
|
+
*
|
|
54
|
+
* @effect read
|
|
55
|
+
* @permission ReadSettings
|
|
56
|
+
*/
|
|
57
|
+
get(options?: Call): Promise<HendriksConfig | null>;
|
|
58
|
+
/**
|
|
59
|
+
* Save the settings; the first call creates the record (`enabled` off, `year` prefix,
|
|
60
|
+
* `blockSourceFulfilledOrders` on, unless given). Needs `UpdateSettings`.
|
|
61
|
+
*
|
|
62
|
+
* Refused, with nothing saved:
|
|
63
|
+
* - `HENDRIKS_CONFIG_INVALID` (`ValidationError`, 400): `custom` mode without 1 to 4 digits not
|
|
64
|
+
* starting with 0. `details[]` names each field (`wirePrefixDigits`, `wirePrefixMode`), so a
|
|
65
|
+
* form can put the reason on it;
|
|
66
|
+
* - `PLUGIN_ACCESS_DENIED` (`PermissionDeniedError`, 403): the store does not hold the
|
|
67
|
+
* Hendriks plugin. An ordinary caller only: the engine never refuses a SuperAdmin on this
|
|
68
|
+
* ground, so a SuperAdmin head that must know reads `tenant.entitlements()` on that store;
|
|
69
|
+
* - `ORGANIZATION_WORKSPACE_NOT_A_STORE` (`BusinessRuleError`, 422): switching the export on,
|
|
70
|
+
* or linking a pipeline, in an organization's workspace.
|
|
71
|
+
*
|
|
72
|
+
* `pipelineId` is not checked against the store's pipelines; an export through a pipeline
|
|
73
|
+
* that does not exist fails when it runs.
|
|
74
|
+
*
|
|
75
|
+
* @effect write
|
|
76
|
+
* @permission UpdateSettings
|
|
77
|
+
*/
|
|
78
|
+
update(input: UpdateHendriksConfigInput, options?: Call): Promise<HendriksConfig>;
|
|
79
|
+
/**
|
|
80
|
+
* Delete the store's settings record. Every Hendriks export of the store is refused until
|
|
81
|
+
* settings are saved again, and the prefix and pipeline link are gone with it. `true` when a
|
|
82
|
+
* record was deleted, `false` when the store had none. Needs `UpdateSettings`; allowed for a
|
|
83
|
+
* store that no longer holds the plugin, so it can always remove its connection.
|
|
84
|
+
*
|
|
85
|
+
* @effect destructive
|
|
86
|
+
* @permission UpdateSettings
|
|
87
|
+
*/
|
|
88
|
+
delete(options?: Call): Promise<boolean>;
|
|
89
|
+
}
|
|
90
|
+
/** `admin.shipping.hendriks`: the C.J. Hendriks 3PL integration of the store. */
|
|
91
|
+
export interface HendriksModule {
|
|
92
|
+
config: HendriksConfigModule;
|
|
93
|
+
}
|
|
94
|
+
export declare const HENDRIKS_CONFIG_QUERY = "\n query HendriksConfig {\n hendriksConfig { \n id\n channelId\n enabled\n pipelineId\n wirePrefixMode\n wirePrefixDigits\n blockSourceFulfilledOrders\n createdAt\n updatedAt\n }\n }\n";
|
|
95
|
+
export declare const UPDATE_HENDRIKS_CONFIG_MUTATION = "\n mutation UpdateHendriksConfig($input: UpdateHendriksConfigInput!) {\n updateHendriksConfig(input: $input) { \n id\n channelId\n enabled\n pipelineId\n wirePrefixMode\n wirePrefixDigits\n blockSourceFulfilledOrders\n createdAt\n updatedAt\n }\n }\n";
|
|
96
|
+
export declare const DELETE_HENDRIKS_CONFIG_MUTATION = "\n mutation DeleteHendriksConfig {\n deleteHendriksConfig\n }\n";
|
|
97
|
+
export declare function createHendriksModule(transport: Transport): HendriksModule;
|