@sixtyninecommerce/admin 0.10.0 → 0.12.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 +5772 -118
- package/dist/auth/index.d.ts +7 -1
- package/dist/auth/index.js +8 -1
- 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/documents.d.ts +142 -0
- package/dist/catalog/documents.js +114 -0
- package/dist/catalog/index.d.ts +54 -6
- package/dist/catalog/index.js +10 -1
- package/dist/catalog/metadata.d.ts +244 -0
- package/dist/catalog/metadata.js +220 -0
- package/dist/catalog/products.d.ts +159 -19
- package/dist/catalog/products.js +88 -13
- package/dist/catalog/properties.d.ts +140 -14
- package/dist/catalog/properties.js +65 -1
- package/dist/catalog/recommendations.d.ts +288 -0
- package/dist/catalog/recommendations.js +237 -0
- package/dist/catalog/reviews.d.ts +381 -0
- package/dist/catalog/reviews.js +325 -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 +293 -26
- package/dist/catalog/variants.js +164 -7
- package/dist/catalog/visibility.d.ts +38 -7
- package/dist/catalog/visibility.js +19 -1
- package/dist/client.d.ts +121 -9
- package/dist/client.js +53 -14
- package/dist/content/assets.d.ts +285 -0
- package/dist/content/assets.js +181 -0
- package/dist/content/forms.d.ts +332 -1
- package/dist/content/forms.js +140 -4
- package/dist/content/items.d.ts +292 -0
- package/dist/content/items.js +170 -0
- package/dist/content/menus.d.ts +254 -0
- package/dist/content/menus.js +70 -0
- package/dist/content/strings.d.ts +137 -0
- package/dist/content/strings.js +82 -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/delivery-terms.d.ts +44 -0
- package/dist/customers/delivery-terms.js +32 -0
- package/dist/customers/groups.d.ts +207 -0
- package/dist/customers/groups.js +438 -0
- package/dist/customers/index.d.ts +462 -37
- package/dist/customers/index.js +317 -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/emails.d.ts +150 -0
- package/dist/documents/emails.js +220 -0
- package/dist/documents/index.d.ts +744 -21
- package/dist/documents/index.js +438 -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 +163 -11
- package/dist/fulfillments/index.js +135 -6
- 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 +147 -39
- package/dist/index.js +51 -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 +965 -0
- package/dist/integrations/exact-online-types.js +6 -0
- package/dist/integrations/exact-online.d.ts +784 -0
- package/dist/integrations/exact-online.js +1089 -0
- package/dist/integrations/index.d.ts +44 -3
- package/dist/integrations/index.js +23 -3
- package/dist/integrations/pipeline-discoveries.d.ts +65 -0
- package/dist/integrations/pipeline-discoveries.js +65 -0
- package/dist/integrations/pipeline-keys.d.ts +13 -0
- package/dist/integrations/pipeline-keys.js +22 -0
- package/dist/integrations/pipeline-runs.d.ts +119 -0
- package/dist/integrations/pipeline-runs.js +87 -0
- package/dist/integrations/pipelines.d.ts +87 -15
- package/dist/integrations/pipelines.js +41 -22
- package/dist/integrations/price-import.d.ts +223 -0
- package/dist/integrations/price-import.js +124 -0
- package/dist/integrations/types.d.ts +367 -3
- package/dist/integrations/types.js +4 -3
- package/dist/locations/index.d.ts +66 -0
- package/dist/locations/index.js +31 -0
- package/dist/meta/index.d.ts +172 -0
- package/dist/metafields/index.d.ts +8 -1
- package/dist/metafields/index.js +10 -0
- package/dist/orders/cancel-with-money.d.ts +237 -0
- package/dist/orders/cancel-with-money.js +155 -0
- package/dist/orders/commit-edit.d.ts +23 -1
- package/dist/orders/commit-edit.js +19 -2
- package/dist/orders/deposit-policy.d.ts +3 -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 +66 -15
- package/dist/orders/index.js +25 -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 +243 -0
- package/dist/orders/list.js +487 -0
- package/dist/orders/manual-discounts.d.ts +13 -5
- package/dist/orders/manual-pricing.d.ts +5 -0
- package/dist/orders/money-view.d.ts +149 -0
- package/dist/orders/money-view.js +99 -0
- package/dist/orders/order-entry.d.ts +20 -7
- package/dist/orders/plan-edit.d.ts +34 -2
- package/dist/orders/plan-edit.js +112 -11
- 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 +20 -1
- package/dist/orders/surcharges.js +37 -11
- package/dist/payments/account-credit.d.ts +46 -0
- package/dist/payments/account-credit.js +42 -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 +19 -0
- package/dist/payments/credit-noted-fields.js +69 -0
- package/dist/payments/customer-consent.d.ts +30 -0
- package/dist/payments/customer-consent.js +49 -0
- package/dist/payments/index.d.ts +340 -19
- package/dist/payments/index.js +151 -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 +147 -0
- package/dist/payments/requests.js +93 -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 +106 -0
- package/dist/pickups/index.js +108 -0
- package/dist/platform/channels.d.ts +132 -0
- package/dist/platform/channels.js +128 -0
- package/dist/platform/email-gateways.d.ts +165 -0
- package/dist/platform/email-gateways.js +78 -0
- package/dist/platform/geo.d.ts +123 -0
- package/dist/platform/geo.js +144 -0
- package/dist/platform/tax.d.ts +162 -0
- package/dist/platform/tax.js +169 -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 +108 -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 +2370 -58
- package/dist/pos/index.js +854 -7
- package/dist/pos/no-receipt.d.ts +94 -0
- package/dist/pos/no-receipt.js +25 -0
- package/dist/pos/offline-sales.d.ts +228 -0
- package/dist/pos/offline-sales.js +170 -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 +244 -0
- package/dist/pos/returns.js +83 -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 +606 -0
- package/dist/pricing/price-lists.js +600 -0
- package/dist/purchasing/alerts.d.ts +104 -0
- package/dist/purchasing/alerts.js +88 -0
- package/dist/purchasing/backorders.d.ts +61 -0
- package/dist/purchasing/backorders.js +92 -0
- package/dist/purchasing/cost.d.ts +110 -0
- package/dist/purchasing/cost.js +86 -0
- package/dist/purchasing/index.d.ts +54 -0
- package/dist/purchasing/index.js +24 -0
- package/dist/purchasing/links.d.ts +263 -0
- package/dist/purchasing/links.js +192 -0
- package/dist/purchasing/purchase-orders.d.ts +551 -0
- package/dist/purchasing/purchase-orders.js +491 -0
- package/dist/purchasing/receipts.d.ts +396 -0
- package/dist/purchasing/receipts.js +287 -0
- package/dist/purchasing/replenishment.d.ts +281 -0
- package/dist/purchasing/replenishment.js +240 -0
- package/dist/purchasing/returns.d.ts +273 -0
- package/dist/purchasing/returns.js +229 -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 +518 -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 +675 -21
- package/dist/returns/index.js +756 -11
- package/dist/search/index.d.ts +76 -1
- package/dist/search/index.js +63 -0
- package/dist/seo/config.d.ts +128 -0
- package/dist/seo/config.js +95 -0
- package/dist/seo/redirects.d.ts +125 -0
- package/dist/seo/redirects.js +60 -1
- package/dist/seo/settings.d.ts +147 -0
- package/dist/seo/settings.js +209 -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 +54 -0
- package/dist/shipping/index.js +27 -0
- package/dist/shipping/methods.d.ts +205 -0
- package/dist/shipping/methods.js +240 -0
- package/dist/shipping/myparcel.d.ts +668 -0
- package/dist/shipping/myparcel.js +466 -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 +324 -0
- package/dist/shipping/rate-tables.js +390 -0
- package/dist/shipping/ship-to-countries.d.ts +75 -0
- package/dist/shipping/ship-to-countries.js +47 -0
- package/dist/stock/by-location.d.ts +86 -0
- package/dist/stock/by-location.js +94 -0
- package/dist/stock/index.d.ts +18 -4
- package/dist/stock/index.js +7 -0
- package/dist/stock/locations.d.ts +144 -0
- package/dist/stock/locations.js +168 -0
- package/dist/stock/settings.d.ts +106 -0
- package/dist/stock/settings.js +103 -0
- package/dist/stock/transfers.d.ts +386 -52
- package/dist/stock/transfers.js +222 -17
- package/dist/stored-value/index.d.ts +312 -11
- package/dist/stored-value/index.js +223 -4
- package/dist/subscriptions/index.d.ts +682 -0
- package/dist/subscriptions/index.js +815 -0
- package/dist/tax/display-policy.d.ts +105 -0
- package/dist/tax/display-policy.js +84 -0
- package/dist/tax/index.d.ts +79 -1
- package/dist/tax/index.js +52 -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 +287 -0
- package/dist/tenant/email-templates.js +271 -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
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `admin.fulfillments.create` and `admin.fulfillments.profileChargePreview`: the shared create
|
|
3
|
+
* flow's write and its office-only delivery-charge preview (headless W10-38; spec
|
|
4
|
+
* `decoupling-fulfillments` §13, §15.4).
|
|
5
|
+
*
|
|
6
|
+
* The create answers the warehouse API's union: a refusal of the WHOLE call is thrown through
|
|
7
|
+
* `warehouseRefusalError`, so a code reaches a caller as the same class from `create` as from
|
|
8
|
+
* `fulfillments.warehouse.append` and the warehouse reads (`INVALID_INPUT` a `ValidationError`
|
|
9
|
+
* 400, never a 422). Each group's own refusal is data in `results[].error`.
|
|
10
|
+
*/
|
|
11
|
+
import { type Transport } from '@sixtyninecommerce/core';
|
|
12
|
+
import type { Call } from '../types.js';
|
|
13
|
+
import { type KeyedWarehouseCall, type WarehouseFulfillment, type WarehouseFulfillmentLineInput, type WarehouseHandlerArg, type WarehouseRefusal } from './warehouse.js';
|
|
14
|
+
/** One fulfilment to create: the lines it ships and its carrier. */
|
|
15
|
+
export interface CreateFulfillmentGroupInput {
|
|
16
|
+
/** 1–500 lines, each a whole quantity of 1 or more, at most what is left to ship. */
|
|
17
|
+
lines: WarehouseFulfillmentLineInput[];
|
|
18
|
+
/** The carrier (fulfilment handler) code; `fulfillments.warehouse.handlers()` lists them. */
|
|
19
|
+
handlerCode: string;
|
|
20
|
+
/**
|
|
21
|
+
* The carrier's own arguments, as text. Send every name in the carrier's
|
|
22
|
+
* `argsRequiredForCreate`; the warehouse, profile and pick override are set by the engine.
|
|
23
|
+
*/
|
|
24
|
+
handlerArgs?: WarehouseHandlerArg[];
|
|
25
|
+
/** Office staff only (`OFFICE_ONLY` otherwise): the profile whose minimum and delivery charge apply. */
|
|
26
|
+
fulfillmentProfileId?: string;
|
|
27
|
+
}
|
|
28
|
+
/** What `create` sends: one fulfilment per group, all shipping from one warehouse. */
|
|
29
|
+
export interface CreateFulfillmentsInput {
|
|
30
|
+
/** The warehouse every group ships from; it must be in the caller's scope. */
|
|
31
|
+
stockLocationId: string;
|
|
32
|
+
/** 1–50 groups. */
|
|
33
|
+
groups: CreateFulfillmentGroupInput[];
|
|
34
|
+
/**
|
|
35
|
+
* Claim each created in-house fulfilment for the caller (`Picking`). Only on a store with the
|
|
36
|
+
* warehouse workspace (`WAREHOUSE_NOT_ENABLED` otherwise).
|
|
37
|
+
*/
|
|
38
|
+
startPicking?: boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Office staff with no location restriction only: ship lines whose order picked another
|
|
41
|
+
* warehouse from this one (`OFFICE_ONLY` / `LOCATION_OUT_OF_SCOPE` otherwise).
|
|
42
|
+
*/
|
|
43
|
+
overridePreferredLocation?: boolean;
|
|
44
|
+
}
|
|
45
|
+
/** What became of one group, by its position in the input. */
|
|
46
|
+
export interface CreateFulfillmentGroupResult {
|
|
47
|
+
index: number;
|
|
48
|
+
/** The fulfilment as it now is; null when the group was refused. */
|
|
49
|
+
fulfillment: WarehouseFulfillment | null;
|
|
50
|
+
/** Why the group was refused; nothing of it was written. */
|
|
51
|
+
error: WarehouseRefusal | null;
|
|
52
|
+
/** Set when the fulfilment WAS created but `startPicking` could not claim it. */
|
|
53
|
+
claimError: WarehouseRefusal | null;
|
|
54
|
+
}
|
|
55
|
+
/** Every group of a `create`, each on its own. */
|
|
56
|
+
export interface CreateFulfillmentsResult {
|
|
57
|
+
results: CreateFulfillmentGroupResult[];
|
|
58
|
+
created: number;
|
|
59
|
+
failed: number;
|
|
60
|
+
}
|
|
61
|
+
/** What `profileChargePreview` prices: a profile and the lines one fulfilment would ship. */
|
|
62
|
+
export interface FulfillmentProfileChargePreviewInput {
|
|
63
|
+
fulfillmentProfileId: string;
|
|
64
|
+
/** 1–500 lines, each a whole quantity of 1 or more. */
|
|
65
|
+
lines: Array<{
|
|
66
|
+
orderLineId: string;
|
|
67
|
+
quantity: number;
|
|
68
|
+
}>;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* A fulfilment profile's minimum and delivery charge for a selection. Nothing was written. Money
|
|
72
|
+
* is integer MINOR UNITS of `currencyCode`.
|
|
73
|
+
*/
|
|
74
|
+
export interface FulfillmentProfileChargePreview {
|
|
75
|
+
profileName: string;
|
|
76
|
+
currencyCode: string;
|
|
77
|
+
/** The profile's minimum order value, NET. */
|
|
78
|
+
minOrder: number;
|
|
79
|
+
/**
|
|
80
|
+
* The net value the minimum is judged on: the selected lines' combined net, or, for a whole
|
|
81
|
+
* order that met the minimum when it was placed, its lines that count toward minimums.
|
|
82
|
+
*/
|
|
83
|
+
selectedNet: number;
|
|
84
|
+
/** How far the selection is below the minimum; 0 when it is met. */
|
|
85
|
+
shortfall: number;
|
|
86
|
+
/** What the profile's shipping method charges for these lines; null when none would be added. */
|
|
87
|
+
deliveryCharge: number | null;
|
|
88
|
+
/** Whether `deliveryCharge` includes tax; null with no charge. */
|
|
89
|
+
deliveryChargeIncludesTax: boolean | null;
|
|
90
|
+
/**
|
|
91
|
+
* Every order the delivery is for already paid delivery at checkout, so no charge is added.
|
|
92
|
+
* When nothing is delivered (`handedOver`), whether every order is fully paid.
|
|
93
|
+
*/
|
|
94
|
+
settled: boolean;
|
|
95
|
+
/**
|
|
96
|
+
* Nothing in the selection is delivered (collected, sold at a till, nothing to ship): the
|
|
97
|
+
* minimum and the delivery charge do not apply (`minOrder` and `shortfall` 0, no charge); the
|
|
98
|
+
* profile still picks the warehouse.
|
|
99
|
+
*/
|
|
100
|
+
handedOver: boolean;
|
|
101
|
+
}
|
|
102
|
+
export interface FulfillmentCreateMethods {
|
|
103
|
+
/**
|
|
104
|
+
* Create fulfilments at one warehouse: one per group, each in its own transaction, through the
|
|
105
|
+
* same create path as the order page. A group that is refused is reported in its
|
|
106
|
+
* `results[].error` and the rest go on, so the answer can mix created and refused groups.
|
|
107
|
+
* Needs `UpdateFulfillment` (warehouse staff, on a store with the warehouse workspace, at a
|
|
108
|
+
* warehouse assigned to them) or `UpdateOrder` (office staff, on any store, at any of its
|
|
109
|
+
* warehouses).
|
|
110
|
+
*
|
|
111
|
+
* MONEY and outside effects, per created fulfilment: a fulfilment profile (office only) can
|
|
112
|
+
* add a delivery charge to its orders, shared across a consolidation; on a store without the
|
|
113
|
+
* warehouse workspace the carrier is booked at create (a label bought, or a 3PL handed the
|
|
114
|
+
* order; with the workspace it is booked later, at Packed); the customer gets the
|
|
115
|
+
* `fulfillment_created` e-mail.
|
|
116
|
+
*
|
|
117
|
+
* A line nobody picked a warehouse for, whose stock is reserved at another warehouse, has its
|
|
118
|
+
* reservation moved here: released there and taken from this warehouse, as it is for
|
|
119
|
+
* warehouse staff assigned here (a line whose order picked another warehouse is refused
|
|
120
|
+
* `LINE_PREFERS_OTHER_LOCATION`, unless the office sets `overridePreferredLocation`).
|
|
121
|
+
*
|
|
122
|
+
* One key per attempt (`options.idempotencyKey`): a repeat under the same key answers the
|
|
123
|
+
* first call's result (each fulfilment as it is now) and creates nothing, however few of a
|
|
124
|
+
* line's units it asked for. Another request under that key is `IDEMPOTENCY_CONFLICT`
|
|
125
|
+
* (`ConflictError`, 409). The groups commit one by one, so the engine spends the key before the
|
|
126
|
+
* first: a repeat while the first is still running, or after it stopped without answering, is
|
|
127
|
+
* `IDEMPOTENCY_OUTCOME_UNKNOWN` (`outcomeUnknown`): read the orders' fulfilments, never create
|
|
128
|
+
* again under a new key blind; once the first has answered, the key replays its answer. A
|
|
129
|
+
* refusal of the whole call does not spend the key. Left out, a key is made up (a UUIDv7) and
|
|
130
|
+
* returned as `idempotencyKey` on the result, and on a thrown error as an untyped own property
|
|
131
|
+
* of the error.
|
|
132
|
+
*
|
|
133
|
+
* Refusals. Of the whole call, THROWN, with the classes of every warehouse refusal:
|
|
134
|
+
* `INVALID_INPUT` (a `ValidationError`, 400; also before any request for a missing warehouse,
|
|
135
|
+
* no groups, a group without a carrier or a line without an id or a whole quantity),
|
|
136
|
+
* `LOCATION_OUT_OF_SCOPE`, `OFFICE_ONLY`, `WAREHOUSE_NOT_ENABLED` (`BusinessRuleError`, 422).
|
|
137
|
+
* Of one group, as DATA: `COMBINE_RULE_VIOLATED` (the part of the rule that broke in
|
|
138
|
+
* `field`), `LINE_OVER_FULFILLED`, `INSUFFICIENT_STOCK_AT_LOCATION`, `ORDER_NOT_COVERED`,
|
|
139
|
+
* `PROFILE_MINIMUM_NOT_MET` (a consolidation short of the profile minimum; one order short of it
|
|
140
|
+
* is `INVALID_INPUT`, its sentence naming the minimum), `SOURCE_FULFILLED_BLOCKED`, a carrier's
|
|
141
|
+
* own refusal, … A missing
|
|
142
|
+
* permission is `FORBIDDEN` and a carrier of a plugin the store does not have
|
|
143
|
+
* `PLUGIN_ACCESS_DENIED` (both `PermissionDeniedError`, 403).
|
|
144
|
+
*
|
|
145
|
+
* @effect money
|
|
146
|
+
*/
|
|
147
|
+
create(input: CreateFulfillmentsInput, options?: KeyedWarehouseCall): Promise<CreateFulfillmentsResult & {
|
|
148
|
+
idempotencyKey: string;
|
|
149
|
+
}>;
|
|
150
|
+
/**
|
|
151
|
+
* What a fulfilment profile would ask of a selection before it is created: its minimum, how
|
|
152
|
+
* far the selection is below it, and the delivery charge it would add. Office staff only
|
|
153
|
+
* (`UpdateOrder`). Who pays which share of a consolidated charge is decided at create. Money in
|
|
154
|
+
* integer minor units.
|
|
155
|
+
*
|
|
156
|
+
* A malformed or unknown profile or line, no lines or more than 500, a bad quantity, or orders
|
|
157
|
+
* in different currencies are `FULFILLMENT_PROFILE_PREVIEW_INVALID` (a `ValidationError`,
|
|
158
|
+
* 400); a selection the create would refuse answers that code (`LOCATION_OUT_OF_SCOPE`,
|
|
159
|
+
* `COMBINE_RULE_VIOLATED`, `PROFILE_CURRENCY_MISMATCH`, `BusinessRuleError`).
|
|
160
|
+
*
|
|
161
|
+
* @effect read
|
|
162
|
+
*/
|
|
163
|
+
profileChargePreview(input: FulfillmentProfileChargePreviewInput, options?: Call): Promise<FulfillmentProfileChargePreview>;
|
|
164
|
+
}
|
|
165
|
+
export declare const CREATE_WAREHOUSE_FULFILLMENTS_MUTATION = "\n mutation CreateWarehouseFulfillments(\n $input: CreateWarehouseFulfillmentsInput!\n $idempotencyKey: String\n ) {\n createWarehouseFulfillments(input: $input, idempotencyKey: $idempotencyKey) {\n __typename\n ... on WarehouseCreateResult {\n created\n failed\n results {\n index\n fulfillment {\n \n id\n state\n handlerCode\n method\n mode\n trackingCode\n stockLocationId\n stockLocationName\n createdAt\n stateChangedAt\n overdue\n claimedBy {\n id\n name\n }\n claimedAt\n packedAt\n bookingStatus\n bookingError\n parcels {\n weightGrams\n lengthMm\n widthMm\n heightMm\n }\n orders {\n id\n code\n poNumber\n orderNotes\n requestedDeliveryDate\n deliveryDue\n paymentBadge\n hold {\n reason\n note\n }\n }\n customer {\n id\n name\n phone\n }\n shippingAddress {\n \n fullName\n company\n streetLine1\n streetLine2\n city\n province\n postalCode\n countryCode\n\n }\n lineCount\n unitCount\n\n }\n error {\n code\n message\n field\n }\n claimError {\n code\n message\n field\n }\n }\n }\n ... on WarehouseError {\n errorCode\n code\n message\n field\n }\n }\n }\n";
|
|
166
|
+
export declare const FULFILLMENT_PROFILE_CHARGE_PREVIEW_QUERY = "\n query FulfillmentProfileChargePreview($input: FulfillmentProfileChargePreviewInput!) {\n fulfillmentProfileChargePreview(input: $input) {\n profileName\n currencyCode\n minOrder\n selectedNet\n shortfall\n deliveryCharge\n deliveryChargeIncludesTax\n settled\n handedOver\n }\n }\n";
|
|
167
|
+
export declare function createFulfillmentCreateMethods(transport: Transport): FulfillmentCreateMethods;
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `admin.fulfillments.create` and `admin.fulfillments.profileChargePreview`: the shared create
|
|
3
|
+
* flow's write and its office-only delivery-charge preview (headless W10-38; spec
|
|
4
|
+
* `decoupling-fulfillments` §13, §15.4).
|
|
5
|
+
*
|
|
6
|
+
* The create answers the warehouse API's union: a refusal of the WHOLE call is thrown through
|
|
7
|
+
* `warehouseRefusalError`, so a code reaches a caller as the same class from `create` as from
|
|
8
|
+
* `fulfillments.warehouse.append` and the warehouse reads (`INVALID_INPUT` a `ValidationError`
|
|
9
|
+
* 400, never a 422). Each group's own refusal is data in `results[].error`.
|
|
10
|
+
*/
|
|
11
|
+
import { idempotencyKey as mintIdempotencyKey, ValidationError, } from '@sixtyninecommerce/core';
|
|
12
|
+
import { assertId, FULFILLMENT_FIELDS, invalid, isWarehouseErrorMember, toFulfillment, toRefusal, warehouseRefusalError, withAttemptKey, } from './warehouse.js';
|
|
13
|
+
export const CREATE_WAREHOUSE_FULFILLMENTS_MUTATION = /* GraphQL */ `
|
|
14
|
+
mutation CreateWarehouseFulfillments(
|
|
15
|
+
$input: CreateWarehouseFulfillmentsInput!
|
|
16
|
+
$idempotencyKey: String
|
|
17
|
+
) {
|
|
18
|
+
createWarehouseFulfillments(input: $input, idempotencyKey: $idempotencyKey) {
|
|
19
|
+
__typename
|
|
20
|
+
... on WarehouseCreateResult {
|
|
21
|
+
created
|
|
22
|
+
failed
|
|
23
|
+
results {
|
|
24
|
+
index
|
|
25
|
+
fulfillment {
|
|
26
|
+
${FULFILLMENT_FIELDS}
|
|
27
|
+
}
|
|
28
|
+
error {
|
|
29
|
+
code
|
|
30
|
+
message
|
|
31
|
+
field
|
|
32
|
+
}
|
|
33
|
+
claimError {
|
|
34
|
+
code
|
|
35
|
+
message
|
|
36
|
+
field
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
... on WarehouseError {
|
|
41
|
+
errorCode
|
|
42
|
+
code
|
|
43
|
+
message
|
|
44
|
+
field
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
`;
|
|
49
|
+
export const FULFILLMENT_PROFILE_CHARGE_PREVIEW_QUERY = /* GraphQL */ `
|
|
50
|
+
query FulfillmentProfileChargePreview($input: FulfillmentProfileChargePreviewInput!) {
|
|
51
|
+
fulfillmentProfileChargePreview(input: $input) {
|
|
52
|
+
profileName
|
|
53
|
+
currencyCode
|
|
54
|
+
minOrder
|
|
55
|
+
selectedNet
|
|
56
|
+
shortfall
|
|
57
|
+
deliveryCharge
|
|
58
|
+
deliveryChargeIncludesTax
|
|
59
|
+
settled
|
|
60
|
+
handedOver
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
`;
|
|
64
|
+
const isObject = (value) => typeof value === 'object' && value !== null;
|
|
65
|
+
/**
|
|
66
|
+
* Refused before any request: each of these would otherwise fail GraphQL validation with no code.
|
|
67
|
+
* Bounds the engine checks (group and line counts, quantities, ids that are not uuids) are left
|
|
68
|
+
* to it.
|
|
69
|
+
*/
|
|
70
|
+
function assertCreateInput(input) {
|
|
71
|
+
if (!isObject(input))
|
|
72
|
+
throw invalid('input', 'Name the warehouse and the groups to create.');
|
|
73
|
+
assertId(input.stockLocationId, 'stockLocationId');
|
|
74
|
+
const groups = input.groups;
|
|
75
|
+
if (!Array.isArray(groups) || groups.length === 0) {
|
|
76
|
+
throw invalid('groups', 'Add at least one group of lines to fulfill.');
|
|
77
|
+
}
|
|
78
|
+
for (const [index, group] of groups.entries()) {
|
|
79
|
+
const at = `groups[${String(index)}]`;
|
|
80
|
+
if (!isObject(group))
|
|
81
|
+
throw invalid(at, `Group ${String(index + 1)} is not a group of lines.`);
|
|
82
|
+
if (typeof group.handlerCode !== 'string' || group.handlerCode.trim() === '') {
|
|
83
|
+
throw invalid(`${at}.handlerCode`, `Group ${String(index + 1)}: choose a carrier (fulfillment handler).`);
|
|
84
|
+
}
|
|
85
|
+
if (!Array.isArray(group.lines)) {
|
|
86
|
+
throw invalid(`${at}.lines`, `Group ${String(index + 1)}: list the lines it ships.`);
|
|
87
|
+
}
|
|
88
|
+
for (const [lineIndex, line] of group.lines.entries()) {
|
|
89
|
+
const lineAt = `${at}.lines[${String(lineIndex)}]`;
|
|
90
|
+
assertId(isObject(line) ? line.orderLineId : undefined, `${lineAt}.orderLineId`);
|
|
91
|
+
if (!Number.isInteger(line.quantity)) {
|
|
92
|
+
throw invalid(`${lineAt}.quantity`, 'A quantity is a whole number.');
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (group.handlerArgs !== undefined && !Array.isArray(group.handlerArgs)) {
|
|
96
|
+
throw invalid(`${at}.handlerArgs`, 'The carrier arguments are a list of names and values.');
|
|
97
|
+
}
|
|
98
|
+
for (const [argIndex, arg] of (group.handlerArgs ?? []).entries()) {
|
|
99
|
+
if (!isObject(arg) || typeof arg.name !== 'string' || typeof arg.value !== 'string') {
|
|
100
|
+
throw invalid(`${at}.handlerArgs[${String(argIndex)}]`, 'Each carrier argument has a name and a value, both text.');
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
function invalidPreview(field, message) {
|
|
106
|
+
return new ValidationError({
|
|
107
|
+
code: 'FULFILLMENT_PROFILE_PREVIEW_INVALID',
|
|
108
|
+
message,
|
|
109
|
+
status: 400,
|
|
110
|
+
service: 'vendure',
|
|
111
|
+
details: [{ field, code: 'FULFILLMENT_PROFILE_PREVIEW_INVALID', message }],
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
/** Refused before any request, with the engine's own code: each would fail GraphQL validation. */
|
|
115
|
+
function assertPreviewInput(input) {
|
|
116
|
+
if (!isObject(input))
|
|
117
|
+
throw invalidPreview('input', 'Name a profile and the lines to preview.');
|
|
118
|
+
const profileId = input.fulfillmentProfileId;
|
|
119
|
+
if (typeof profileId !== 'string' || profileId.trim() === '') {
|
|
120
|
+
throw invalidPreview('fulfillmentProfileId', 'A fulfillment profile id is required.');
|
|
121
|
+
}
|
|
122
|
+
if (!Array.isArray(input.lines)) {
|
|
123
|
+
throw invalidPreview('lines', 'List the lines the fulfillment would ship.');
|
|
124
|
+
}
|
|
125
|
+
for (const [index, line] of input.lines.entries()) {
|
|
126
|
+
const at = `lines[${String(index)}]`;
|
|
127
|
+
const id = isObject(line) ? line.orderLineId : undefined;
|
|
128
|
+
if (typeof id !== 'string' || id.trim() === '') {
|
|
129
|
+
throw invalidPreview(`${at}.orderLineId`, 'Each line names its order line.');
|
|
130
|
+
}
|
|
131
|
+
if (!Number.isInteger(line.quantity)) {
|
|
132
|
+
throw invalidPreview(`${at}.quantity`, 'A quantity is a whole number.');
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
export function createFulfillmentCreateMethods(transport) {
|
|
137
|
+
return {
|
|
138
|
+
async create(input, options) {
|
|
139
|
+
assertCreateInput(input);
|
|
140
|
+
const key = options?.idempotencyKey ?? mintIdempotencyKey();
|
|
141
|
+
try {
|
|
142
|
+
const data = await transport.graphql({
|
|
143
|
+
api: 'admin',
|
|
144
|
+
query: CREATE_WAREHOUSE_FULFILLMENTS_MUTATION,
|
|
145
|
+
variables: {
|
|
146
|
+
input: {
|
|
147
|
+
stockLocationId: input.stockLocationId,
|
|
148
|
+
groups: input.groups.map((group) => ({
|
|
149
|
+
lines: group.lines.map(({ orderLineId, quantity }) => ({
|
|
150
|
+
orderLineId,
|
|
151
|
+
quantity,
|
|
152
|
+
})),
|
|
153
|
+
handlerCode: group.handlerCode,
|
|
154
|
+
...(group.handlerArgs
|
|
155
|
+
? { handlerArgs: group.handlerArgs.map(({ name, value }) => ({ name, value })) }
|
|
156
|
+
: {}),
|
|
157
|
+
...(group.fulfillmentProfileId
|
|
158
|
+
? { fulfillmentProfileId: group.fulfillmentProfileId }
|
|
159
|
+
: {}),
|
|
160
|
+
})),
|
|
161
|
+
...(input.startPicking === undefined ? {} : { startPicking: input.startPicking }),
|
|
162
|
+
...(input.overridePreferredLocation === undefined
|
|
163
|
+
? {}
|
|
164
|
+
: { overridePreferredLocation: input.overridePreferredLocation }),
|
|
165
|
+
},
|
|
166
|
+
idempotencyKey: key,
|
|
167
|
+
},
|
|
168
|
+
}, { ...options, idempotencyKey: key });
|
|
169
|
+
const result = data.createWarehouseFulfillments;
|
|
170
|
+
// The whole call refused: classified like every other warehouse refusal (W10-37 F-4).
|
|
171
|
+
if (isWarehouseErrorMember(result))
|
|
172
|
+
throw warehouseRefusalError(result);
|
|
173
|
+
const outcome = result;
|
|
174
|
+
return {
|
|
175
|
+
created: outcome.created,
|
|
176
|
+
failed: outcome.failed,
|
|
177
|
+
results: outcome.results.map((item) => ({
|
|
178
|
+
index: item.index,
|
|
179
|
+
fulfillment: item.fulfillment ? toFulfillment(item.fulfillment) : null,
|
|
180
|
+
error: toRefusal(item.error),
|
|
181
|
+
claimError: toRefusal(item.claimError),
|
|
182
|
+
})),
|
|
183
|
+
idempotencyKey: key,
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
catch (error) {
|
|
187
|
+
throw withAttemptKey(error, key);
|
|
188
|
+
}
|
|
189
|
+
},
|
|
190
|
+
async profileChargePreview(input, options) {
|
|
191
|
+
assertPreviewInput(input);
|
|
192
|
+
const data = await transport.graphql({
|
|
193
|
+
api: 'admin',
|
|
194
|
+
query: FULFILLMENT_PROFILE_CHARGE_PREVIEW_QUERY,
|
|
195
|
+
variables: {
|
|
196
|
+
input: {
|
|
197
|
+
fulfillmentProfileId: input.fulfillmentProfileId,
|
|
198
|
+
lines: input.lines.map(({ orderLineId, quantity }) => ({ orderLineId, quantity })),
|
|
199
|
+
},
|
|
200
|
+
},
|
|
201
|
+
}, options);
|
|
202
|
+
const preview = data.fulfillmentProfileChargePreview;
|
|
203
|
+
return {
|
|
204
|
+
profileName: preview.profileName,
|
|
205
|
+
currencyCode: preview.currencyCode,
|
|
206
|
+
minOrder: preview.minOrder,
|
|
207
|
+
selectedNet: preview.selectedNet,
|
|
208
|
+
shortfall: preview.shortfall,
|
|
209
|
+
deliveryCharge: preview.deliveryCharge ?? null,
|
|
210
|
+
deliveryChargeIncludesTax: preview.deliveryChargeIncludesTax ?? null,
|
|
211
|
+
settled: preview.settled,
|
|
212
|
+
handedOver: preview.handedOver,
|
|
213
|
+
};
|
|
214
|
+
},
|
|
215
|
+
};
|
|
216
|
+
}
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
-
import { type Transport } from '@sixtyninecommerce/core';
|
|
1
|
+
import { type PlatformError, type Transport } from '@sixtyninecommerce/core';
|
|
2
2
|
import type { OrderOverpaymentChoice, OverpaymentOption } from '../orders/surcharges.js';
|
|
3
3
|
import type { Call } from '../types.js';
|
|
4
|
+
import { type FulfillmentCreateMethods } from './create.js';
|
|
5
|
+
import { type FulfillmentPaymentPolicyModule } from './payment-policy.js';
|
|
6
|
+
import { type WarehouseDemandRouting, type WarehouseFulfillmentsModule } from './warehouse.js';
|
|
7
|
+
export type { WarehouseDemandRouting };
|
|
4
8
|
/**
|
|
5
9
|
* A fulfillment's parcels as the order records them: one MyParcel shipment per
|
|
6
10
|
* parcel, and the barcodes the carrier has issued so far.
|
|
@@ -40,8 +44,6 @@ export interface FulfillmentParcelTracking {
|
|
|
40
44
|
parcelCount: number;
|
|
41
45
|
}
|
|
42
46
|
export type FulfillmentLabelFormat = 'A4' | 'A6';
|
|
43
|
-
/** How a warehouse's "To ship" queue routes a line (`WarehouseDemandRouting`). */
|
|
44
|
-
export type WarehouseDemandRouting = 'preferred' | 'allocated' | 'unrouted' | 'no_stock';
|
|
45
47
|
/**
|
|
46
48
|
* Which "To ship" entry of an order to read. The entry, and so whether it
|
|
47
49
|
* holds the whole order, depends on the warehouse and on the routing filters:
|
|
@@ -180,6 +182,15 @@ export interface FulfillmentCancelPreview {
|
|
|
180
182
|
export interface FulfillmentCancelChoice {
|
|
181
183
|
orderId: string;
|
|
182
184
|
choice: OrderOverpaymentChoice;
|
|
185
|
+
/**
|
|
186
|
+
* With `ACCOUNT_CREDIT` in a store whose book is store credit (`cancelPreview`'s
|
|
187
|
+
* `accountCredit.book` `STORE_CREDIT`): whether THIS order's customer expressly agreed to store
|
|
188
|
+
* credit instead of a refund to their payment (EU consumer law, CRD art. 13(1)), as staff
|
|
189
|
+
* recorded it. The settlement's move records it on its ledger entries
|
|
190
|
+
* (`StoredValueEntry.customerAgreed`); never a condition, nothing is refused for it. Sent only
|
|
191
|
+
* when given; an engine before the field (incentives sprint 8 PR 6a) refuses a call that gives it.
|
|
192
|
+
*/
|
|
193
|
+
customerAgreed?: boolean;
|
|
183
194
|
}
|
|
184
195
|
/** What `cancel` sends besides the fulfillment. */
|
|
185
196
|
export interface CancelFulfillmentInput {
|
|
@@ -196,6 +207,11 @@ export interface FulfillmentCancelSettlement {
|
|
|
196
207
|
amount: number;
|
|
197
208
|
currencyCode: string;
|
|
198
209
|
choice: OrderOverpaymentChoice;
|
|
210
|
+
/**
|
|
211
|
+
* For `ACCOUNT_CREDIT`: the store's customer-credit book the credit lands in (`AR` or
|
|
212
|
+
* `STORE_CREDIT`); null for `REFUND` and from an engine before it.
|
|
213
|
+
*/
|
|
214
|
+
book?: string | null;
|
|
199
215
|
}
|
|
200
216
|
/** A cancelled fulfillment and what its cancel queued. */
|
|
201
217
|
export interface CancelledFulfillment {
|
|
@@ -258,12 +274,44 @@ export interface OrderFulfillmentCoverage {
|
|
|
258
274
|
}
|
|
259
275
|
/** The longest override reason the engine stores. */
|
|
260
276
|
export declare const FULFILLMENT_COVERAGE_REASON_MAX_LENGTH = 500;
|
|
277
|
+
/** A fulfillment as `transition` leaves it. */
|
|
278
|
+
export interface FulfillmentStateChange {
|
|
279
|
+
id: string;
|
|
280
|
+
/** The state it is in now (`Shipped`, `Delivered`, …). */
|
|
281
|
+
state: string;
|
|
282
|
+
/** The states it may move to next, as the store's fulfillment process allows. */
|
|
283
|
+
nextStates: string[];
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* The facts a refused `transition` carries on `PlatformError.extensions`, beside its code:
|
|
287
|
+
* the move that was asked for and the refusing step's own words.
|
|
288
|
+
*/
|
|
289
|
+
export interface FulfillmentTransitionRefusalFacts {
|
|
290
|
+
/** Core's code for every refused move: `FULFILLMENT_STATE_TRANSITION_ERROR`. */
|
|
291
|
+
errorCode: string;
|
|
292
|
+
fromState: string;
|
|
293
|
+
toState: string;
|
|
294
|
+
/** The refusing step's text, `[CODE]` prefix included when it had one. */
|
|
295
|
+
transitionError: string;
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* What re-sending a fulfillment's label to the store's 3PL came to (`resendLabelHandoff`):
|
|
299
|
+
* - `QUEUED`: the email with the label is queued for the 3PL recipient;
|
|
300
|
+
* - `NOT_READY`: the fulfillment has no ready MyParcel label yet, so nothing was sent;
|
|
301
|
+
* - `DISABLED`: the store has the label hand-off notification switched off;
|
|
302
|
+
* - `NO_RECIPIENT`: it is on, but names no recipient;
|
|
303
|
+
* - `UNAVAILABLE`: the platform's email delivery is not installed.
|
|
304
|
+
*/
|
|
305
|
+
export type LabelHandoffOutcome = 'QUEUED' | 'DISABLED' | 'NO_RECIPIENT' | 'NOT_READY' | 'UNAVAILABLE';
|
|
261
306
|
/**
|
|
262
307
|
* Fulfillment parcels (multi-parcel shipments). Each method is its own request
|
|
263
308
|
* on purpose: a caller deployed ahead of an engine without these fields sees
|
|
264
309
|
* only that call refused, never the order or fulfillment read beside it.
|
|
310
|
+
*
|
|
311
|
+
* `create` and `profileChargePreview` (the shared create flow) are declared in
|
|
312
|
+
* `fulfillments/create.ts`.
|
|
265
313
|
*/
|
|
266
|
-
export interface FulfillmentsModule {
|
|
314
|
+
export interface FulfillmentsModule extends FulfillmentCreateMethods {
|
|
267
315
|
/** Every fulfillment of an order, with its parcels. Needs `ReadOrder`. */
|
|
268
316
|
parcelsOfOrder(orderId: string, options?: Call): Promise<OrderFulfillmentParcels[]>;
|
|
269
317
|
/**
|
|
@@ -281,7 +329,11 @@ export interface FulfillmentsModule {
|
|
|
281
329
|
/**
|
|
282
330
|
* Every parcel's MyParcel label merged by MyParcel into one PDF, fetched live
|
|
283
331
|
* and never cached. Needs `ReadOrder`. Allowed up to 55s: the engine retries
|
|
284
|
-
* a slow MyParcel within a budget the default timeout does not cover.
|
|
332
|
+
* a slow MyParcel within a budget the default timeout does not cover. A
|
|
333
|
+
* credential restricted to stock locations (an API token or app installation
|
|
334
|
+
* with `locationIds`) prints it only for a fulfillment that ships from one of
|
|
335
|
+
* them; any other, another store's and a missing one included, is
|
|
336
|
+
* `LOCATION_OUT_OF_SCOPE` (422).
|
|
285
337
|
*/
|
|
286
338
|
myparcelLabel(fulfillmentId: string, format: FulfillmentLabelFormat, options?: Call): Promise<FulfillmentLabel>;
|
|
287
339
|
/**
|
|
@@ -303,8 +355,11 @@ export interface FulfillmentsModule {
|
|
|
303
355
|
* `NotFoundError` (`MYPARCEL_ORDER_NOT_FOUND_ERROR`); a cancelled one, or
|
|
304
356
|
* one holding no shipment, a `BusinessRuleError`
|
|
305
357
|
* (`MYPARCEL_VALIDATION_ERROR`), as is MyParcel switched off for the store
|
|
306
|
-
* (`MYPARCEL_NOT_CONFIGURED_ERROR`).
|
|
307
|
-
*
|
|
358
|
+
* (`MYPARCEL_NOT_CONFIGURED_ERROR`). A credential restricted to stock
|
|
359
|
+
* locations (an API token or app installation with `locationIds`) is refused
|
|
360
|
+
* `LOCATION_OUT_OF_SCOPE` (422) first for a fulfillment that does not ship
|
|
361
|
+
* from one of them, another store's and a missing one included. Only queues
|
|
362
|
+
* work, so the default timeout applies.
|
|
308
363
|
*/
|
|
309
364
|
labelMyparcelParcels(fulfillmentId: string, input?: LabelMyparcelParcelsInput, options?: Call): Promise<MyparcelParcelsLabelRequest>;
|
|
310
365
|
/**
|
|
@@ -336,7 +391,10 @@ export interface FulfillmentsModule {
|
|
|
336
391
|
* What cancelling the fulfillment would owe each order's customer back (a delivery charge
|
|
337
392
|
* they already paid), and which ways of settling it are open. Read now, without a lock; the
|
|
338
393
|
* cancel judges it again. Needs `UpdateOrder`. Another store's fulfillment is a
|
|
339
|
-
* `NotFoundError` (`ENTITY_NOT_FOUND`).
|
|
394
|
+
* `NotFoundError` (`ENTITY_NOT_FOUND`). A credential restricted to stock locations (an API
|
|
395
|
+
* token or app installation with `locationIds`) reads it only for a fulfillment that ships
|
|
396
|
+
* from one of them; any other, another store's and a missing one included, is
|
|
397
|
+
* `LOCATION_OUT_OF_SCOPE` (422).
|
|
340
398
|
*/
|
|
341
399
|
cancelPreview(fulfillmentId: string, options?: Call): Promise<FulfillmentCancelPreview>;
|
|
342
400
|
/**
|
|
@@ -355,7 +413,10 @@ export interface FulfillmentsModule {
|
|
|
355
413
|
* `AR_ACCOUNT_IN_ERP`, `ORDER_OVERPAYMENT_REFUND_UNRECONCILED`, …);
|
|
356
414
|
* `FULFILLMENT_CANCEL_REFUSED` (→ `BusinessRuleError`) when the fulfillment's process refuses
|
|
357
415
|
* the cancel (already cancelled, a carrier that cannot let go). Another store's fulfillment is
|
|
358
|
-
* a `NotFoundError`.
|
|
416
|
+
* a `NotFoundError`. A credential restricted to stock locations (an API token or app
|
|
417
|
+
* installation with `locationIds`) cancels only a fulfillment that ships from one of them; any
|
|
418
|
+
* other (one with no recorded warehouse, another store's and a missing one included) is
|
|
419
|
+
* `LOCATION_OUT_OF_SCOPE` (422), before the key is claimed.
|
|
359
420
|
*
|
|
360
421
|
* `options.idempotencyKey`: a repeat under it answers the first call's result, never a second
|
|
361
422
|
* cancel; the same key with a different choice is `IDEMPOTENCY_CONFLICT`.
|
|
@@ -389,14 +450,91 @@ export interface FulfillmentsModule {
|
|
|
389
450
|
allowUncovered(orderId: string, reason: string, options?: Call & {
|
|
390
451
|
idempotencyKey?: string;
|
|
391
452
|
}): Promise<FulfillmentCoverageOverride>;
|
|
453
|
+
/**
|
|
454
|
+
* Move a fulfillment to one of its `nextStates` (the order page's "Mark as Shipped" and "Mark as
|
|
455
|
+
* Delivered"). Needs `UpdateOrder`. The move runs the store's own fulfillment process, so the
|
|
456
|
+
* order's state follows and whatever the store does on a shipped or delivered fulfillment (its
|
|
457
|
+
* events, its notifications: the customer gets the shipped e-mail) happens; the process has no
|
|
458
|
+
* way back to an earlier state. Shipping an order's last open lines moves the ORDER to
|
|
459
|
+
* `Shipped`, which on a store that pushes orders to its ERP when they ship (Exact Online's
|
|
460
|
+
* "fulfilled" auto-push) sends the order there, where it cannot be taken back.
|
|
461
|
+
*
|
|
462
|
+
* A move into `Cancelled` is a cancel: it ends the fulfillment for good and has its carrier let
|
|
463
|
+
* go of the shipment, and the delivery charge it added comes off what each of its orders bills.
|
|
464
|
+
* It is refused, before the carrier is told, while the customer has PAID such a charge
|
|
465
|
+
* (`FULFILLMENT_CANCEL_OVERPAYMENT_CHOICE_REQUIRED`): {@link FulfillmentsModule.cancel} takes the
|
|
466
|
+
* choice of how that money goes back. An unpaid charge simply leaves the bill.
|
|
467
|
+
*
|
|
468
|
+
* Tagged `money`, its strongest effect: a cancel changes what a placed order bills.
|
|
469
|
+
*
|
|
470
|
+
* Refused, with nothing moved:
|
|
471
|
+
* - a step of the store's process that refuses the move answers ITS OWN code, which the engine
|
|
472
|
+
* prefixes to its text as `[CODE]`, with the text after it as the message, classed as the
|
|
473
|
+
* warehouse API classes the same code: `ORDER_NOT_COVERED` (the store requires full payment
|
|
474
|
+
* and an order is not paid in full: `coverage` reads what it owes, `allowUncovered` records
|
|
475
|
+
* an override), `ORDER_ON_HOLD` (release the order's fulfilment hold first),
|
|
476
|
+
* `BOOKING_REQUIRED`, `PARCELS_REQUIRED`, `CONSOLIDATION_ADDRESS_DIVERGED`, …;
|
|
477
|
+
* - any other refusal of the process, an edge it does not have included, is
|
|
478
|
+
* `FULFILLMENT_STATE_TRANSITION_ERROR` (`BusinessRuleError`, 422) with the refusing step's
|
|
479
|
+
* text as the message;
|
|
480
|
+
* - both carry {@link FulfillmentTransitionRefusalFacts} on `extensions`;
|
|
481
|
+
* - another store's or a missing fulfillment is `ENTITY_NOT_FOUND` (`NotFoundError`); a
|
|
482
|
+
* credential restricted to stock locations (an API token or app installation with
|
|
483
|
+
* `locationIds`) moves only a fulfillment that ships from one of them
|
|
484
|
+
* (`LOCATION_OUT_OF_SCOPE`, 422);
|
|
485
|
+
* - a blank id or state is refused before any request (`FULFILLMENT_TRANSITION_INVALID`,
|
|
486
|
+
* `ValidationError`).
|
|
487
|
+
*
|
|
488
|
+
* Takes no idempotency key: repeating a move that went through asks for an edge the process no
|
|
489
|
+
* longer has, and is refused as above, never moved twice.
|
|
490
|
+
*
|
|
491
|
+
* @effect money
|
|
492
|
+
* @permission UpdateOrder
|
|
493
|
+
*/
|
|
494
|
+
transition(fulfillmentId: string, state: string, options?: Call): Promise<FulfillmentStateChange>;
|
|
495
|
+
/**
|
|
496
|
+
* E-mail the fulfillment's ready MyParcel label again to the store's 3PL recipient (the
|
|
497
|
+
* `fulfillment_label_handoff` notification), whatever the store's automatic hand-off setting.
|
|
498
|
+
* Answers what came of it ({@link LabelHandoffOutcome}): only `QUEUED` sent anything; the
|
|
499
|
+
* others say why nothing was sent. Every outcome leaves an audit row. Needs `UpdateOrder`.
|
|
500
|
+
*
|
|
501
|
+
* Takes no idempotency key: a repeat sends the e-mail again.
|
|
502
|
+
*
|
|
503
|
+
* Refused: another store's or a missing fulfillment is `ENTITY_NOT_FOUND` (`NotFoundError`); a
|
|
504
|
+
* store without the MyParcel plugin `PLUGIN_ACCESS_DENIED` (`PermissionDeniedError`, 403) for
|
|
505
|
+
* an ordinary caller; a credential restricted to other stock locations `LOCATION_OUT_OF_SCOPE`
|
|
506
|
+
* (422). A blank id is refused before any request (`MYPARCEL_LABEL_INPUT_INVALID`,
|
|
507
|
+
* `ValidationError`).
|
|
508
|
+
*
|
|
509
|
+
* @effect irreversible
|
|
510
|
+
* @permission UpdateOrder
|
|
511
|
+
*/
|
|
512
|
+
resendLabelHandoff(fulfillmentId: string, options?: Call): Promise<LabelHandoffOutcome>;
|
|
513
|
+
/**
|
|
514
|
+
* The store's fulfilment payment policy (`fulfillmentPaymentPolicy`): whether a fulfilment of
|
|
515
|
+
* an order not paid in full is refused `ORDER_NOT_COVERED`, and which payment methods are
|
|
516
|
+
* exempt. Read as the engine applies it; written whole (`UpdateChannel`).
|
|
517
|
+
*/
|
|
518
|
+
paymentPolicy: FulfillmentPaymentPolicyModule;
|
|
519
|
+
/**
|
|
520
|
+
* The pick/pack/ship workspace: the warehouse API (price-free, location-scoped), the pick list
|
|
521
|
+
* and consolidation. See `fulfillments/warehouse.ts`.
|
|
522
|
+
*/
|
|
523
|
+
warehouse: WarehouseFulfillmentsModule;
|
|
392
524
|
}
|
|
393
525
|
/**
|
|
394
526
|
* Its own document, like every call here: on an engine without the query this call alone fails
|
|
395
527
|
* validation.
|
|
396
528
|
*/
|
|
397
|
-
export declare const FULFILLMENT_CANCEL_PREVIEW_QUERY = "\n query FulfillmentCancelPreview($fulfillmentId: ID!) {\n fulfillmentCancelPreview(fulfillmentId: $fulfillmentId) {\n fulfillmentId\n overpayments {\n orderId\n orderCode\n amount\n currencyCode\n refund { \n available\n code\n message\n }\n accountCredit { \n available\n code\n message\n }\n }\n }\n }\n";
|
|
529
|
+
export declare const FULFILLMENT_CANCEL_PREVIEW_QUERY = "\n query FulfillmentCancelPreview($fulfillmentId: ID!) {\n fulfillmentCancelPreview(fulfillmentId: $fulfillmentId) {\n fulfillmentId\n overpayments {\n orderId\n orderCode\n amount\n currencyCode\n refund { \n available\n code\n message\n book\n }\n accountCredit { \n available\n code\n message\n book\n }\n }\n }\n }\n";
|
|
398
530
|
/** `$overpayment` and `$idempotencyKey` are optional and left out of the variables when not given. */
|
|
399
|
-
export declare const CANCEL_FULFILLMENT_MUTATION = "\n mutation CancelFulfillment(\n $fulfillmentId: ID!\n $overpayment: [FulfillmentCancelOverpaymentInput!]\n $idempotencyKey: String\n ) {\n cancelFulfillment(\n fulfillmentId: $fulfillmentId\n overpayment: $overpayment\n idempotencyKey: $idempotencyKey\n ) {\n fulfillment {\n id\n state\n }\n settlements {\n orderId\n orderCode\n amount\n currencyCode\n choice\n }\n }\n }\n";
|
|
531
|
+
export declare const CANCEL_FULFILLMENT_MUTATION = "\n mutation CancelFulfillment(\n $fulfillmentId: ID!\n $overpayment: [FulfillmentCancelOverpaymentInput!]\n $idempotencyKey: String\n ) {\n cancelFulfillment(\n fulfillmentId: $fulfillmentId\n overpayment: $overpayment\n idempotencyKey: $idempotencyKey\n ) {\n fulfillment {\n id\n state\n }\n settlements {\n orderId\n orderCode\n amount\n currencyCode\n choice\n book\n }\n }\n }\n";
|
|
532
|
+
/**
|
|
533
|
+
* The refusal member is selected for its facts: `message` is core's per-code template ("Cannot
|
|
534
|
+
* transition Fulfillment from X to Y"), and the refusing step's reason is `transitionError` alone.
|
|
535
|
+
*/
|
|
536
|
+
export declare const TRANSITION_FULFILLMENT_MUTATION = "\n mutation TransitionFulfillment($id: ID!, $state: String!) {\n transitionFulfillmentToState(id: $id, state: $state) {\n __typename\n ... on Fulfillment {\n id\n state\n nextStates\n }\n ... on FulfillmentStateTransitionError {\n errorCode\n message\n fromState\n toState\n transitionError\n }\n }\n }\n";
|
|
537
|
+
export declare const RESEND_FULFILLMENT_LABEL_HANDOFF_MUTATION = "\n mutation ResendFulfillmentLabelHandoff($fulfillmentId: ID!) {\n resendFulfillmentLabelHandoff(fulfillmentId: $fulfillmentId)\n }\n";
|
|
400
538
|
/** Its own document: on an engine without the query this call alone fails validation. */
|
|
401
539
|
export declare const ORDER_FULFILLMENT_COVERAGE_QUERY = "\n query OrderFulfillmentCoverage($orderId: ID!) {\n orderFulfillmentCoverage(orderId: $orderId) {\n orderId\n orderCode\n currencyCode\n policyActive\n covered\n outstanding\n exempt\n exemptReason\n allowed\n override { \n id\n orderId\n reason\n actorKind\n actorId\n outstandingAtGrant\n currencyCode\n createdAt\n active\n }\n }\n }\n";
|
|
402
540
|
/** `$idempotencyKey` is optional and left out of the variables when not given. */
|
|
@@ -434,4 +572,18 @@ export declare const MYPARCEL_LABEL_TIMEOUT_MS = 55000;
|
|
|
434
572
|
export declare function toUnretractedShipments(raw: readonly MyparcelUnretractedShipment[] | null | undefined): MyparcelUnretractedShipment[];
|
|
435
573
|
/** The bytes of a base64 label document (`atob`: no Node `Buffer`, it ships to browsers). */
|
|
436
574
|
export declare function decodeBase64(base64: string): Uint8Array;
|
|
575
|
+
interface RawTransitionRefusal {
|
|
576
|
+
errorCode: string;
|
|
577
|
+
message: string;
|
|
578
|
+
fromState?: string | null;
|
|
579
|
+
toState?: string | null;
|
|
580
|
+
transitionError?: string | null;
|
|
581
|
+
}
|
|
582
|
+
/**
|
|
583
|
+
* A refused move as the coded error it is. Core carries a step's refusal only as text, so the
|
|
584
|
+
* step's own code is read off its `[CODE]` prefix and classed through the GraphQL dialect, as the
|
|
585
|
+
* warehouse API's refusals of the same codes are (`warehouseRefusalError`): one code, one class,
|
|
586
|
+
* whichever door answered it.
|
|
587
|
+
*/
|
|
588
|
+
export declare function fulfillmentTransitionRefusal(result: RawTransitionRefusal): PlatformError;
|
|
437
589
|
export declare function createFulfillmentsModule(transport: Transport): FulfillmentsModule;
|