@sixtyninecommerce/admin 0.9.0 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4598 -128
- package/dist/catalog/assets.d.ts +120 -8
- package/dist/catalog/assets.js +98 -12
- package/dist/catalog/collections.d.ts +279 -14
- package/dist/catalog/collections.js +246 -15
- package/dist/catalog/index.d.ts +9 -2
- package/dist/catalog/index.js +4 -0
- package/dist/catalog/products.d.ts +318 -17
- package/dist/catalog/products.js +182 -14
- package/dist/catalog/properties.d.ts +102 -14
- package/dist/catalog/properties.js +13 -0
- package/dist/catalog/recommendations.d.ts +261 -0
- package/dist/catalog/recommendations.js +145 -0
- package/dist/catalog/reviews.d.ts +368 -0
- package/dist/catalog/reviews.js +318 -0
- package/dist/catalog/types.d.ts +17 -1
- package/dist/catalog/types.js +10 -0
- package/dist/catalog/variant-find.d.ts +136 -0
- package/dist/catalog/variant-find.js +239 -0
- package/dist/catalog/variants.d.ts +282 -25
- package/dist/catalog/variants.js +173 -25
- package/dist/catalog/visibility.d.ts +20 -5
- package/dist/catalog/visibility.js +19 -1
- package/dist/client.d.ts +116 -9
- package/dist/client.js +41 -7
- package/dist/content/assets.d.ts +286 -0
- package/dist/content/assets.js +181 -0
- package/dist/content/items.d.ts +269 -0
- package/dist/content/items.js +170 -0
- package/dist/content/types.d.ts +282 -0
- package/dist/content/types.js +100 -0
- package/dist/customers/age-verification.d.ts +66 -0
- package/dist/customers/age-verification.js +79 -0
- package/dist/customers/credit.d.ts +263 -0
- package/dist/customers/credit.js +244 -0
- package/dist/customers/delivery-preferences.d.ts +120 -0
- package/dist/customers/delivery-preferences.js +97 -0
- package/dist/customers/groups.d.ts +207 -0
- package/dist/customers/groups.js +438 -0
- package/dist/customers/index.d.ts +447 -37
- package/dist/customers/index.js +313 -40
- package/dist/customers/invitation-status.d.ts +57 -0
- package/dist/customers/invitation-status.js +21 -0
- package/dist/customers/notes.d.ts +67 -0
- package/dist/customers/notes.js +51 -0
- package/dist/customers/notification-recipients.d.ts +97 -0
- package/dist/customers/notification-recipients.js +84 -0
- package/dist/customers/saved-lists.d.ts +42 -0
- package/dist/customers/saved-lists.js +61 -0
- package/dist/customers/vat.d.ts +83 -0
- package/dist/customers/vat.js +46 -0
- package/dist/customers/wire.d.ts +20 -0
- package/dist/customers/wire.js +35 -0
- package/dist/documents/ar.d.ts +307 -0
- package/dist/documents/ar.js +254 -0
- package/dist/documents/index.d.ts +731 -21
- package/dist/documents/index.js +436 -24
- package/dist/documents/pdf.d.ts +2 -0
- package/dist/documents/pdf.js +11 -0
- package/dist/fulfillments/create.d.ts +167 -0
- package/dist/fulfillments/create.js +216 -0
- package/dist/fulfillments/index.d.ts +121 -10
- package/dist/fulfillments/index.js +120 -2
- package/dist/fulfillments/payment-policy.d.ts +64 -0
- package/dist/fulfillments/payment-policy.js +140 -0
- package/dist/fulfillments/warehouse.d.ts +724 -0
- package/dist/fulfillments/warehouse.js +914 -0
- package/dist/geo/index.d.ts +119 -0
- package/dist/geo/index.js +107 -0
- package/dist/index.d.ts +129 -30
- package/dist/index.js +47 -9
- package/dist/integrations/afas-actions.d.ts +234 -0
- package/dist/integrations/afas-actions.js +310 -0
- package/dist/integrations/afas-types.d.ts +483 -0
- package/dist/integrations/afas-types.js +5 -0
- package/dist/integrations/afas.d.ts +234 -0
- package/dist/integrations/afas.js +290 -0
- package/dist/integrations/connections.d.ts +103 -0
- package/dist/integrations/connections.js +55 -0
- package/dist/integrations/esp.d.ts +313 -0
- package/dist/integrations/esp.js +169 -0
- package/dist/integrations/exact-online-types.d.ts +423 -0
- package/dist/integrations/exact-online-types.js +6 -0
- package/dist/integrations/exact-online.d.ts +248 -0
- package/dist/integrations/exact-online.js +376 -0
- package/dist/integrations/index.d.ts +40 -0
- package/dist/integrations/index.js +24 -0
- package/dist/integrations/pipeline-keys.d.ts +13 -0
- package/dist/integrations/pipeline-keys.js +22 -0
- package/dist/integrations/pipelines.d.ts +114 -0
- package/dist/integrations/pipelines.js +46 -0
- package/dist/integrations/types.d.ts +322 -0
- package/dist/integrations/types.js +8 -0
- package/dist/jobs/bulk-action-run.d.ts +11 -2
- package/dist/jobs/bulk-action-run.js +4 -5
- package/dist/locations/index.d.ts +66 -0
- package/dist/locations/index.js +31 -0
- package/dist/meta/index.d.ts +162 -0
- package/dist/orders/bulk.d.ts +75 -0
- package/dist/orders/bulk.js +150 -0
- package/dist/orders/cancel-with-money.d.ts +227 -0
- package/dist/orders/cancel-with-money.js +153 -0
- package/dist/orders/commit-edit.d.ts +7 -1
- package/dist/orders/commit-edit.js +5 -1
- package/dist/orders/deposit-policy.d.ts +103 -0
- package/dist/orders/deposit-policy.js +202 -0
- package/dist/orders/drafts.d.ts +800 -0
- package/dist/orders/drafts.js +771 -0
- package/dist/orders/fields.d.ts +245 -0
- package/dist/orders/fields.js +188 -0
- package/dist/orders/get.d.ts +29 -19
- package/dist/orders/get.js +17 -8
- package/dist/orders/index.d.ts +125 -5
- package/dist/orders/index.js +35 -2
- package/dist/orders/lifecycle.d.ts +128 -0
- package/dist/orders/lifecycle.js +158 -0
- package/dist/orders/line-price-preview.d.ts +7 -2
- package/dist/orders/list.d.ts +222 -0
- package/dist/orders/list.js +377 -0
- package/dist/orders/manual-discounts.d.ts +11 -2
- package/dist/orders/manual-discounts.js +2 -0
- package/dist/orders/manual-pricing.d.ts +5 -0
- package/dist/orders/order-entry.d.ts +20 -7
- package/dist/orders/plan-edit.d.ts +1 -1
- package/dist/orders/plan-edit.js +4 -1
- package/dist/orders/settings.d.ts +201 -0
- package/dist/orders/settings.js +325 -0
- package/dist/orders/status.d.ts +159 -13
- package/dist/orders/status.js +21 -0
- package/dist/orders/surcharges.d.ts +8 -1
- package/dist/orders/surcharges.js +3 -2
- package/dist/payments/account-credit.d.ts +30 -0
- package/dist/payments/account-credit.js +19 -0
- package/dist/payments/ar.d.ts +292 -0
- package/dist/payments/ar.js +223 -0
- package/dist/payments/connected-account.d.ts +47 -0
- package/dist/payments/connected-account.js +61 -0
- package/dist/payments/credit-noted-fields.d.ts +12 -0
- package/dist/payments/credit-noted-fields.js +37 -0
- package/dist/payments/index.d.ts +263 -10
- package/dist/payments/index.js +133 -1
- package/dist/payments/methods.d.ts +332 -0
- package/dist/payments/methods.js +363 -0
- package/dist/payments/mollie-methods.d.ts +159 -0
- package/dist/payments/mollie-methods.js +141 -0
- package/dist/payments/payment-links.d.ts +180 -0
- package/dist/payments/payment-links.js +97 -0
- package/dist/payments/provider-keys.d.ts +150 -0
- package/dist/payments/provider-keys.js +118 -0
- package/dist/payments/providers.d.ts +86 -11
- package/dist/payments/providers.js +29 -0
- package/dist/payments/requests.d.ts +144 -0
- package/dist/payments/requests.js +92 -0
- package/dist/payments/store-credit-fields.d.ts +15 -0
- package/dist/payments/store-credit-fields.js +51 -0
- package/dist/pickups/index.d.ts +104 -0
- package/dist/pickups/index.js +105 -0
- package/dist/platform/channels.d.ts +132 -0
- package/dist/platform/channels.js +128 -0
- package/dist/platform/geo.d.ts +123 -0
- package/dist/platform/geo.js +144 -0
- package/dist/platform/tax.d.ts +154 -0
- package/dist/platform/tax.js +139 -0
- package/dist/pos/anomalies.d.ts +158 -0
- package/dist/pos/anomalies.js +64 -0
- package/dist/pos/assisted-selling.d.ts +79 -0
- package/dist/pos/assisted-selling.js +38 -0
- package/dist/pos/exchanges.d.ts +103 -0
- package/dist/pos/exchanges.js +22 -0
- package/dist/pos/gift-cards.d.ts +135 -0
- package/dist/pos/gift-cards.js +47 -0
- package/dist/pos/index.d.ts +2125 -32
- package/dist/pos/index.js +742 -4
- package/dist/pos/no-receipt.d.ts +94 -0
- package/dist/pos/no-receipt.js +25 -0
- package/dist/pos/offline-sales.d.ts +187 -0
- package/dist/pos/offline-sales.js +116 -0
- package/dist/pos/pay-by-link.d.ts +143 -0
- package/dist/pos/pay-by-link.js +57 -0
- package/dist/pos/quick-keys.d.ts +103 -0
- package/dist/pos/quick-keys.js +45 -0
- package/dist/pos/reports.d.ts +360 -0
- package/dist/pos/reports.js +62 -0
- package/dist/pos/returns.d.ts +217 -0
- package/dist/pos/returns.js +53 -0
- package/dist/pricing/bulk-coupons.d.ts +139 -0
- package/dist/pricing/bulk-coupons.js +112 -0
- package/dist/pricing/index.d.ts +177 -4
- package/dist/pricing/index.js +176 -1
- package/dist/pricing/price-lists.d.ts +604 -0
- package/dist/pricing/price-lists.js +600 -0
- package/dist/pricing/vouchers.d.ts +103 -0
- package/dist/pricing/vouchers.js +69 -0
- package/dist/purchasing/alerts.d.ts +89 -0
- package/dist/purchasing/alerts.js +62 -0
- package/dist/purchasing/cost.d.ts +110 -0
- package/dist/purchasing/cost.js +86 -0
- package/dist/purchasing/index.d.ts +36 -0
- package/dist/purchasing/index.js +16 -0
- package/dist/purchasing/purchase-orders.d.ts +548 -0
- package/dist/purchasing/purchase-orders.js +491 -0
- package/dist/purchasing/replenishment.d.ts +281 -0
- package/dist/purchasing/replenishment.js +240 -0
- package/dist/purchasing/settings.d.ts +152 -0
- package/dist/purchasing/settings.js +181 -0
- package/dist/purchasing/suppliers.d.ts +476 -0
- package/dist/purchasing/suppliers.js +438 -0
- package/dist/quotes/index.d.ts +501 -0
- package/dist/quotes/index.js +439 -0
- package/dist/reports/index.d.ts +71 -8
- package/dist/reports/index.js +74 -11
- package/dist/returns/index.d.ts +818 -0
- package/dist/returns/index.js +844 -0
- package/dist/search/index.d.ts +174 -0
- package/dist/search/index.js +125 -0
- package/dist/shipping/definitions.d.ts +29 -0
- package/dist/shipping/definitions.js +47 -0
- package/dist/shipping/fulfillment-profiles.d.ts +174 -0
- package/dist/shipping/fulfillment-profiles.js +104 -0
- package/dist/shipping/hendriks.d.ts +97 -0
- package/dist/shipping/hendriks.js +50 -0
- package/dist/shipping/index.d.ts +48 -0
- package/dist/shipping/index.js +25 -0
- package/dist/shipping/methods.d.ts +198 -0
- package/dist/shipping/methods.js +240 -0
- package/dist/shipping/myparcel.d.ts +254 -0
- package/dist/shipping/myparcel.js +178 -0
- package/dist/shipping/parcel-count-suggestion.d.ts +2 -0
- package/dist/shipping/parcel-rule.d.ts +6 -5
- package/dist/shipping/parcel-rule.js +21 -23
- package/dist/shipping/rate-tables.d.ts +179 -0
- package/dist/shipping/rate-tables.js +184 -0
- package/dist/stock/index.d.ts +10 -3
- package/dist/stock/index.js +3 -0
- package/dist/stock/locations.d.ts +144 -0
- package/dist/stock/locations.js +168 -0
- package/dist/stock/transfers.d.ts +216 -43
- package/dist/stock/transfers.js +140 -13
- package/dist/stored-value/index.d.ts +214 -4
- package/dist/stored-value/index.js +152 -0
- package/dist/subscriptions/index.d.ts +682 -0
- package/dist/subscriptions/index.js +815 -0
- package/dist/tax/index.d.ts +76 -1
- package/dist/tax/index.js +50 -0
- package/dist/tenant/email-style.d.ts +102 -0
- package/dist/tenant/email-style.js +72 -0
- package/dist/tenant/email-templates.d.ts +66 -0
- package/dist/tenant/email-templates.js +54 -0
- package/dist/tenant/notifications.d.ts +23 -17
- package/dist/tenant/settings-sources.d.ts +1 -1
- package/dist/tenant/time-zone.d.ts +17 -0
- package/dist/tenant/time-zone.js +11 -0
- package/dist/types.d.ts +51 -4
- package/dist/users/index.d.ts +3 -0
- package/dist/users/index.js +2 -0
- package/dist/users/warehouses.d.ts +50 -0
- package/dist/users/warehouses.js +51 -0
- package/package.json +2 -2
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { type Page, type Transport } from '@sixtyninecommerce/core';
|
|
2
|
+
import type { Call } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* One order as a list shows it (`admin.orders.list`, `admin.customers.orders`): the totals, the
|
|
5
|
+
* status dimensions, who it is for, and the three company sources a display name reads
|
|
6
|
+
* (`billingAddress.company`, `shippingAddress.company`, the customer's address book).
|
|
7
|
+
*
|
|
8
|
+
* Money is an integer in minor units of the order's `currencyCode`.
|
|
9
|
+
*/
|
|
10
|
+
export interface OrderSummary {
|
|
11
|
+
id: string;
|
|
12
|
+
code: string;
|
|
13
|
+
state: string;
|
|
14
|
+
total: number;
|
|
15
|
+
totalWithTax: number;
|
|
16
|
+
currencyCode: string;
|
|
17
|
+
/** ISO-8601; null for an order not placed yet (a cart, a draft). */
|
|
18
|
+
orderPlacedAt: string | null;
|
|
19
|
+
customer: {
|
|
20
|
+
id: string;
|
|
21
|
+
firstName: string;
|
|
22
|
+
lastName: string;
|
|
23
|
+
emailAddress: string;
|
|
24
|
+
addresses: Array<{
|
|
25
|
+
company: string | null;
|
|
26
|
+
defaultBillingAddress: boolean | null;
|
|
27
|
+
defaultShippingAddress: boolean | null;
|
|
28
|
+
}> | null;
|
|
29
|
+
} | null;
|
|
30
|
+
billingAddress: {
|
|
31
|
+
company: string | null;
|
|
32
|
+
} | null;
|
|
33
|
+
shippingAddress: {
|
|
34
|
+
company: string | null;
|
|
35
|
+
} | null;
|
|
36
|
+
lines: Array<{
|
|
37
|
+
quantity: number;
|
|
38
|
+
}>;
|
|
39
|
+
payments: Array<{
|
|
40
|
+
id: string;
|
|
41
|
+
state: string;
|
|
42
|
+
}> | null;
|
|
43
|
+
customFields: {
|
|
44
|
+
externalOrderId: string | null;
|
|
45
|
+
externalPlatform: string | null;
|
|
46
|
+
isGift: boolean | null;
|
|
47
|
+
/** The status dimensions; null until the engine has set them on an older order. */
|
|
48
|
+
paymentStatus: string | null;
|
|
49
|
+
fulfillmentStatus: string | null;
|
|
50
|
+
returnStatus: string | null;
|
|
51
|
+
lifecycleStatus: string | null;
|
|
52
|
+
statusOverrides: {
|
|
53
|
+
fulfillmentHoldReason: string | null;
|
|
54
|
+
} | null;
|
|
55
|
+
} | null;
|
|
56
|
+
/**
|
|
57
|
+
* Set when the caller's customer-data level blanked part of the row (an app installation below
|
|
58
|
+
* `customerData: full`): read an empty name or company as "not granted", never as "none".
|
|
59
|
+
*/
|
|
60
|
+
redacted?: true;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Which orders a list holds. Every key narrows it; several keys are combined with AND. An empty
|
|
64
|
+
* list (`state: []`) matches nothing.
|
|
65
|
+
*/
|
|
66
|
+
export interface OrderListFilter {
|
|
67
|
+
ids?: readonly string[];
|
|
68
|
+
/** Any of these engine states (`PaymentSettled`, `Draft`, …). */
|
|
69
|
+
state?: readonly string[];
|
|
70
|
+
/**
|
|
71
|
+
* The order code. `startsWith` and `contains` ignore case; `contains` treats `%` and `_` as
|
|
72
|
+
* wildcards.
|
|
73
|
+
*/
|
|
74
|
+
code?: {
|
|
75
|
+
eq?: string;
|
|
76
|
+
contains?: string;
|
|
77
|
+
startsWith?: string;
|
|
78
|
+
};
|
|
79
|
+
/**
|
|
80
|
+
* When the order was placed. `isNull: true` keeps the orders never placed (carts, drafts),
|
|
81
|
+
* `false` the placed ones. `before`/`after` are ISO-8601 instants WITH an offset or `Z`, both
|
|
82
|
+
* exclusive; an order never placed matches neither.
|
|
83
|
+
*/
|
|
84
|
+
orderPlacedAt?: {
|
|
85
|
+
isNull?: boolean;
|
|
86
|
+
before?: string;
|
|
87
|
+
after?: string;
|
|
88
|
+
};
|
|
89
|
+
/** True for a cart its shopper still has open; a draft, placed or cancelled order is not. */
|
|
90
|
+
active?: boolean;
|
|
91
|
+
currencyCode?: string;
|
|
92
|
+
/**
|
|
93
|
+
* The platform an imported order came from (`woocommerce`, …); `null` keeps only the orders
|
|
94
|
+
* that were not imported.
|
|
95
|
+
*/
|
|
96
|
+
externalPlatform?: string | null;
|
|
97
|
+
/** Any of these payment dimensions (`paid`, `partially_paid`, …). */
|
|
98
|
+
paymentStatus?: readonly string[];
|
|
99
|
+
/** Any of these lifecycles (`open`, `completed`, …). */
|
|
100
|
+
lifecycleStatus?: readonly string[];
|
|
101
|
+
/** Part of the customer's last name, ignoring case. */
|
|
102
|
+
customerLastName?: string;
|
|
103
|
+
}
|
|
104
|
+
/** The fields an order list sorts on. */
|
|
105
|
+
export type OrderListSortField = 'orderPlacedAt' | 'createdAt' | 'updatedAt' | 'code' | 'state' | 'total' | 'totalWithTax' | 'customerLastName';
|
|
106
|
+
export declare const ORDER_LIST_SORT_FIELDS: readonly OrderListSortField[];
|
|
107
|
+
export interface OrderListSort {
|
|
108
|
+
field: OrderListSortField;
|
|
109
|
+
direction: 'ASC' | 'DESC';
|
|
110
|
+
}
|
|
111
|
+
export interface OrderListOptions extends Call {
|
|
112
|
+
filter?: OrderListFilter;
|
|
113
|
+
sort?: OrderListSort;
|
|
114
|
+
/** Rows to skip, 0 when omitted. */
|
|
115
|
+
skip?: number;
|
|
116
|
+
/** Rows per page, 1 to {@link MAX_ORDER_LIST_TAKE}; 25 when omitted. */
|
|
117
|
+
take?: number;
|
|
118
|
+
}
|
|
119
|
+
/** The engine's `adminListQueryLimit`: a larger page is refused. */
|
|
120
|
+
export declare const MAX_ORDER_LIST_TAKE = 1000;
|
|
121
|
+
export declare const ORDER_SUMMARY_FIELDS = "\n id\n code\n state\n total\n totalWithTax\n currencyCode\n orderPlacedAt\n customer {\n id\n firstName\n lastName\n emailAddress\n addresses {\n company\n defaultBillingAddress\n defaultShippingAddress\n }\n }\n billingAddress {\n company\n }\n shippingAddress {\n company\n }\n lines {\n quantity\n }\n payments {\n id\n state\n }\n customFields {\n externalOrderId\n externalPlatform\n isGift\n paymentStatus\n fulfillmentStatus\n returnStatus\n lifecycleStatus\n statusOverrides {\n fulfillmentHoldReason\n }\n }\n";
|
|
122
|
+
export declare const ORDERS_LIST_QUERY = "\n query OrdersList($options: OrderListOptions) {\n orders(options: $options) {\n items {\n \n id\n code\n state\n total\n totalWithTax\n currencyCode\n orderPlacedAt\n customer {\n id\n firstName\n lastName\n emailAddress\n addresses {\n company\n defaultBillingAddress\n defaultShippingAddress\n }\n }\n billingAddress {\n company\n }\n shippingAddress {\n company\n }\n lines {\n quantity\n }\n payments {\n id\n state\n }\n customFields {\n externalOrderId\n externalPlatform\n isGift\n paymentStatus\n fulfillmentStatus\n returnStatus\n lifecycleStatus\n statusOverrides {\n fulfillmentHoldReason\n }\n }\n\n }\n totalItems\n }\n }\n";
|
|
123
|
+
export declare const ORDERS_COUNT_QUERY = "\n query OrdersCount($options: OrderListOptions) {\n orders(options: $options) {\n totalItems\n }\n }\n";
|
|
124
|
+
export declare const CUSTOMER_ORDERS_QUERY = "\n query CustomerOrders($id: ID!, $options: OrderListOptions) {\n customer(id: $id) {\n id\n orders(options: $options) {\n items {\n \n id\n code\n state\n total\n totalWithTax\n currencyCode\n orderPlacedAt\n customer {\n id\n firstName\n lastName\n emailAddress\n addresses {\n company\n defaultBillingAddress\n defaultShippingAddress\n }\n }\n billingAddress {\n company\n }\n shippingAddress {\n company\n }\n lines {\n quantity\n }\n payments {\n id\n state\n }\n customFields {\n externalOrderId\n externalPlatform\n isGift\n paymentStatus\n fulfillmentStatus\n returnStatus\n lifecycleStatus\n statusOverrides {\n fulfillmentHoldReason\n }\n }\n\n }\n totalItems\n }\n }\n }\n";
|
|
125
|
+
/** The Admin API's `OrderFilterParameter` for a typed filter; unknown keys are refused. */
|
|
126
|
+
export declare function toOrderFilterParameter(filter: OrderListFilter | undefined): Record<string, unknown>;
|
|
127
|
+
export interface OrderListModule {
|
|
128
|
+
/**
|
|
129
|
+
* One page of the store's orders, with `total` the exact count of every order the filter
|
|
130
|
+
* matches. Needs `ReadOrder`.
|
|
131
|
+
*
|
|
132
|
+
* - **Carts are orders too.** A cart a shopper never checked out, and a draft staff never placed,
|
|
133
|
+
* are listed unless the filter leaves them out (`orderPlacedAt: { isNull: false }`).
|
|
134
|
+
* - **Sorting by `orderPlacedAt` descending puts the never-placed rows FIRST** (the database
|
|
135
|
+
* sorts an empty date above every date). To show the newest placed order first, list the
|
|
136
|
+
* placed orders, then continue with `orderPlacedAt: { isNull: true }` sorted by `createdAt`.
|
|
137
|
+
* - `page.next()` asks for the following page with the same filter and sort; `skip` starts
|
|
138
|
+
* somewhere else.
|
|
139
|
+
*
|
|
140
|
+
* Refused before anything is asked: `INVALID_ORDER_LIST_OPTIONS` (`ValidationError`, 400) for a
|
|
141
|
+
* filter key or operator it does not list, a date without an offset, a sort field it does not
|
|
142
|
+
* list, or `take`/`skip` out of range.
|
|
143
|
+
*
|
|
144
|
+
* @effect read
|
|
145
|
+
*/
|
|
146
|
+
list(options?: OrderListOptions): Promise<Page<OrderSummary>>;
|
|
147
|
+
/**
|
|
148
|
+
* How many of the store's orders the filter matches, without reading any. Carts count unless
|
|
149
|
+
* the filter leaves them out. Needs `ReadOrder`. Refused like {@link list}.
|
|
150
|
+
*
|
|
151
|
+
* @effect read
|
|
152
|
+
*/
|
|
153
|
+
count(filter?: OrderListFilter, options?: Call): Promise<number>;
|
|
154
|
+
}
|
|
155
|
+
export declare function createOrderListModule(transport: Transport): OrderListModule;
|
|
156
|
+
/**
|
|
157
|
+
* One customer's orders, as `customers.orders` reads them: the same rows, filter, sort and paging
|
|
158
|
+
* as `orders.list`, or `null` when the store holds no customer with that id.
|
|
159
|
+
*/
|
|
160
|
+
export declare function listCustomerOrders(transport: Transport, customerId: string, options: OrderListOptions | undefined): Promise<Page<OrderSummary> | null>;
|
|
161
|
+
/** The most orders `customers.recentOrders` answers. */
|
|
162
|
+
export declare const MAX_RECENT_ORDERS = 20;
|
|
163
|
+
/**
|
|
164
|
+
* One line of a customer's earlier order: what was bought, and how many. The members are named
|
|
165
|
+
* as on every other order line of this SDK (`orders.get`, `orders.drafts`).
|
|
166
|
+
*/
|
|
167
|
+
export interface RecentOrderLine {
|
|
168
|
+
id: string;
|
|
169
|
+
/** 0 for a line that was cancelled on the order. */
|
|
170
|
+
quantity: number;
|
|
171
|
+
/**
|
|
172
|
+
* Whether the line is priced gross. `customFields.unitPriceOverride` is stated in this basis,
|
|
173
|
+
* which follows the customer's tax zone, not the store's setting: a store that prices gross
|
|
174
|
+
* still holds net lines for a customer in a tax-exclusive country.
|
|
175
|
+
*/
|
|
176
|
+
listPriceIncludesTax: boolean;
|
|
177
|
+
/**
|
|
178
|
+
* The variant as it is NOW (its name and SKU may have changed since the order). A line an
|
|
179
|
+
* external system priced sits on the platform's hidden carrier variant: read it through
|
|
180
|
+
* `catalog.variants.find({ ids })`, which leaves such a variant out, before offering it.
|
|
181
|
+
*/
|
|
182
|
+
productVariant: {
|
|
183
|
+
id: string;
|
|
184
|
+
name: string;
|
|
185
|
+
sku: string;
|
|
186
|
+
product: {
|
|
187
|
+
id: string;
|
|
188
|
+
name: string;
|
|
189
|
+
};
|
|
190
|
+
};
|
|
191
|
+
customFields: {
|
|
192
|
+
/**
|
|
193
|
+
* The unit price the line states in place of the catalogue's, in minor units of the
|
|
194
|
+
* order's currency and in the line's basis (`listPriceIncludesTax`); null for a line the
|
|
195
|
+
* catalogue priced.
|
|
196
|
+
*/
|
|
197
|
+
unitPriceOverride: number | null;
|
|
198
|
+
/** True when that price arrived with the line (an import, a quote, a till price). */
|
|
199
|
+
unitPriceImported: boolean | null;
|
|
200
|
+
} | null;
|
|
201
|
+
}
|
|
202
|
+
/** A placed order of a customer, with its lines. */
|
|
203
|
+
export interface RecentOrder {
|
|
204
|
+
id: string;
|
|
205
|
+
code: string;
|
|
206
|
+
/** ISO-8601. */
|
|
207
|
+
orderPlacedAt: string;
|
|
208
|
+
/** Minor units of `currencyCode`. */
|
|
209
|
+
totalWithTax: number;
|
|
210
|
+
currencyCode: string;
|
|
211
|
+
lines: RecentOrderLine[];
|
|
212
|
+
}
|
|
213
|
+
export interface RecentOrdersOptions extends Call {
|
|
214
|
+
/** How many orders, 1 to {@link MAX_RECENT_ORDERS}; 5 when omitted. */
|
|
215
|
+
take?: number;
|
|
216
|
+
}
|
|
217
|
+
export declare const CUSTOMER_RECENT_ORDERS_QUERY = "\n query CustomerRecentOrders($id: ID!, $options: OrderListOptions) {\n customer(id: $id) {\n id\n orders(options: $options) {\n items {\n id\n code\n orderPlacedAt\n totalWithTax\n currencyCode\n lines {\n id\n quantity\n listPriceIncludesTax\n productVariant {\n id\n name\n sku\n product {\n id\n name\n }\n }\n customFields {\n unitPriceOverride\n unitPriceImported\n }\n }\n }\n totalItems\n }\n }\n }\n";
|
|
218
|
+
/**
|
|
219
|
+
* A customer's last placed orders, newest first, each with its lines, as `customers.recentOrders`
|
|
220
|
+
* reads them; `null` when the store holds no customer with that id.
|
|
221
|
+
*/
|
|
222
|
+
export declare function listCustomerRecentOrders(transport: Transport, customerId: string, options: RecentOrdersOptions | undefined): Promise<RecentOrder[] | null>;
|
|
@@ -0,0 +1,377 @@
|
|
|
1
|
+
import { pageFromVendureList, readOffsetCursor, UpstreamError, ValidationError, } from '@sixtyninecommerce/core';
|
|
2
|
+
import { redactionWatcher } from '../customer-data-redaction.js';
|
|
3
|
+
export const ORDER_LIST_SORT_FIELDS = [
|
|
4
|
+
'orderPlacedAt',
|
|
5
|
+
'createdAt',
|
|
6
|
+
'updatedAt',
|
|
7
|
+
'code',
|
|
8
|
+
'state',
|
|
9
|
+
'total',
|
|
10
|
+
'totalWithTax',
|
|
11
|
+
'customerLastName',
|
|
12
|
+
];
|
|
13
|
+
/** The engine's `adminListQueryLimit`: a larger page is refused. */
|
|
14
|
+
export const MAX_ORDER_LIST_TAKE = 1000;
|
|
15
|
+
const DEFAULT_TAKE = 25;
|
|
16
|
+
export const ORDER_SUMMARY_FIELDS = /* GraphQL */ `
|
|
17
|
+
id
|
|
18
|
+
code
|
|
19
|
+
state
|
|
20
|
+
total
|
|
21
|
+
totalWithTax
|
|
22
|
+
currencyCode
|
|
23
|
+
orderPlacedAt
|
|
24
|
+
customer {
|
|
25
|
+
id
|
|
26
|
+
firstName
|
|
27
|
+
lastName
|
|
28
|
+
emailAddress
|
|
29
|
+
addresses {
|
|
30
|
+
company
|
|
31
|
+
defaultBillingAddress
|
|
32
|
+
defaultShippingAddress
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
billingAddress {
|
|
36
|
+
company
|
|
37
|
+
}
|
|
38
|
+
shippingAddress {
|
|
39
|
+
company
|
|
40
|
+
}
|
|
41
|
+
lines {
|
|
42
|
+
quantity
|
|
43
|
+
}
|
|
44
|
+
payments {
|
|
45
|
+
id
|
|
46
|
+
state
|
|
47
|
+
}
|
|
48
|
+
customFields {
|
|
49
|
+
externalOrderId
|
|
50
|
+
externalPlatform
|
|
51
|
+
isGift
|
|
52
|
+
paymentStatus
|
|
53
|
+
fulfillmentStatus
|
|
54
|
+
returnStatus
|
|
55
|
+
lifecycleStatus
|
|
56
|
+
statusOverrides {
|
|
57
|
+
fulfillmentHoldReason
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
`;
|
|
61
|
+
export const ORDERS_LIST_QUERY = /* GraphQL */ `
|
|
62
|
+
query OrdersList($options: OrderListOptions) {
|
|
63
|
+
orders(options: $options) {
|
|
64
|
+
items {
|
|
65
|
+
${ORDER_SUMMARY_FIELDS}
|
|
66
|
+
}
|
|
67
|
+
totalItems
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
`;
|
|
71
|
+
export const ORDERS_COUNT_QUERY = /* GraphQL */ `
|
|
72
|
+
query OrdersCount($options: OrderListOptions) {
|
|
73
|
+
orders(options: $options) {
|
|
74
|
+
totalItems
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
`;
|
|
78
|
+
export const CUSTOMER_ORDERS_QUERY = /* GraphQL */ `
|
|
79
|
+
query CustomerOrders($id: ID!, $options: OrderListOptions) {
|
|
80
|
+
customer(id: $id) {
|
|
81
|
+
id
|
|
82
|
+
orders(options: $options) {
|
|
83
|
+
items {
|
|
84
|
+
${ORDER_SUMMARY_FIELDS}
|
|
85
|
+
}
|
|
86
|
+
totalItems
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
`;
|
|
91
|
+
function invalid(message) {
|
|
92
|
+
return new ValidationError({
|
|
93
|
+
code: 'INVALID_ORDER_LIST_OPTIONS',
|
|
94
|
+
message,
|
|
95
|
+
status: 400,
|
|
96
|
+
service: 'vendure',
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
function stringList(value, path) {
|
|
100
|
+
if (!Array.isArray(value) || value.some((item) => typeof item !== 'string')) {
|
|
101
|
+
throw invalid(`${path} must be a list of strings.`);
|
|
102
|
+
}
|
|
103
|
+
return [...value];
|
|
104
|
+
}
|
|
105
|
+
function text(value, path) {
|
|
106
|
+
if (typeof value !== 'string')
|
|
107
|
+
throw invalid(`${path} must be a string.`);
|
|
108
|
+
return value;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* An instant the engine compares without guessing a zone: a string with no offset would be read
|
|
112
|
+
* in the database server's zone, so a range would shift by hours with the server.
|
|
113
|
+
*/
|
|
114
|
+
const INSTANT = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(?::\d{2}(?:\.\d+)?)?(?:Z|[+-]\d{2}:\d{2})$/;
|
|
115
|
+
function instant(value, path) {
|
|
116
|
+
if (typeof value !== 'string' || !INSTANT.test(value) || Number.isNaN(Date.parse(value))) {
|
|
117
|
+
throw invalid(`${path} must be an ISO-8601 instant with an offset or Z.`);
|
|
118
|
+
}
|
|
119
|
+
return value;
|
|
120
|
+
}
|
|
121
|
+
function escapeRegex(value) {
|
|
122
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
123
|
+
}
|
|
124
|
+
/** The Admin API's `OrderFilterParameter` for a typed filter; unknown keys are refused. */
|
|
125
|
+
export function toOrderFilterParameter(filter) {
|
|
126
|
+
if (filter === undefined)
|
|
127
|
+
return {};
|
|
128
|
+
if (typeof filter !== 'object' || filter === null || Array.isArray(filter)) {
|
|
129
|
+
throw invalid('filter must be an object.');
|
|
130
|
+
}
|
|
131
|
+
const out = {};
|
|
132
|
+
for (const [key, value] of Object.entries(filter)) {
|
|
133
|
+
if (value === undefined)
|
|
134
|
+
continue;
|
|
135
|
+
switch (key) {
|
|
136
|
+
case 'ids':
|
|
137
|
+
out.id = { in: stringList(value, 'filter.ids') };
|
|
138
|
+
break;
|
|
139
|
+
case 'state':
|
|
140
|
+
case 'paymentStatus':
|
|
141
|
+
case 'lifecycleStatus':
|
|
142
|
+
out[key] = { in: stringList(value, `filter.${key}`) };
|
|
143
|
+
break;
|
|
144
|
+
case 'code': {
|
|
145
|
+
const code = value;
|
|
146
|
+
if (typeof code !== 'object' || code === null)
|
|
147
|
+
throw invalid('filter.code must be an object.');
|
|
148
|
+
const operators = {};
|
|
149
|
+
for (const [operator, operand] of Object.entries(code)) {
|
|
150
|
+
if (operand === undefined)
|
|
151
|
+
continue;
|
|
152
|
+
const path = `filter.code.${operator}`;
|
|
153
|
+
if (operator === 'eq' || operator === 'contains')
|
|
154
|
+
operators[operator] = text(operand, path);
|
|
155
|
+
else if (operator === 'startsWith')
|
|
156
|
+
operators.regex = `^${escapeRegex(text(operand, path))}`;
|
|
157
|
+
else
|
|
158
|
+
throw invalid(`${path} is not a code filter; use eq, contains or startsWith.`);
|
|
159
|
+
}
|
|
160
|
+
out.code = operators;
|
|
161
|
+
break;
|
|
162
|
+
}
|
|
163
|
+
case 'orderPlacedAt': {
|
|
164
|
+
const placed = value;
|
|
165
|
+
if (typeof placed !== 'object' || placed === null) {
|
|
166
|
+
throw invalid('filter.orderPlacedAt must be an object.');
|
|
167
|
+
}
|
|
168
|
+
const operators = {};
|
|
169
|
+
for (const [operator, operand] of Object.entries(placed)) {
|
|
170
|
+
if (operand === undefined)
|
|
171
|
+
continue;
|
|
172
|
+
const path = `filter.orderPlacedAt.${operator}`;
|
|
173
|
+
if (operator === 'isNull') {
|
|
174
|
+
if (typeof operand !== 'boolean')
|
|
175
|
+
throw invalid(`${path} must be a boolean.`);
|
|
176
|
+
operators.isNull = operand;
|
|
177
|
+
}
|
|
178
|
+
else if (operator === 'before' || operator === 'after') {
|
|
179
|
+
operators[operator] = instant(operand, path);
|
|
180
|
+
}
|
|
181
|
+
else {
|
|
182
|
+
throw invalid(`${path} is not a date filter; use isNull, before or after.`);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
out.orderPlacedAt = operators;
|
|
186
|
+
break;
|
|
187
|
+
}
|
|
188
|
+
case 'active':
|
|
189
|
+
if (typeof value !== 'boolean')
|
|
190
|
+
throw invalid('filter.active must be a boolean.');
|
|
191
|
+
out.active = { eq: value };
|
|
192
|
+
break;
|
|
193
|
+
case 'currencyCode':
|
|
194
|
+
out.currencyCode = { eq: text(value, 'filter.currencyCode') };
|
|
195
|
+
break;
|
|
196
|
+
case 'externalPlatform':
|
|
197
|
+
out.externalPlatform =
|
|
198
|
+
value === null ? { isNull: true } : { eq: text(value, 'filter.externalPlatform') };
|
|
199
|
+
break;
|
|
200
|
+
case 'customerLastName':
|
|
201
|
+
out.customerLastName = { contains: text(value, 'filter.customerLastName') };
|
|
202
|
+
break;
|
|
203
|
+
default:
|
|
204
|
+
throw invalid(`filter.${key} is not an order list filter.`);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
return out;
|
|
208
|
+
}
|
|
209
|
+
function toOrderSort(sort) {
|
|
210
|
+
if (sort === undefined)
|
|
211
|
+
return undefined;
|
|
212
|
+
if (typeof sort !== 'object' ||
|
|
213
|
+
sort === null ||
|
|
214
|
+
!ORDER_LIST_SORT_FIELDS.includes(sort.field) ||
|
|
215
|
+
(sort.direction !== 'ASC' && sort.direction !== 'DESC')) {
|
|
216
|
+
throw invalid(`sort must be { field: ${ORDER_LIST_SORT_FIELDS.join(' | ')}, direction: ASC | DESC }.`);
|
|
217
|
+
}
|
|
218
|
+
return { [sort.field]: sort.direction };
|
|
219
|
+
}
|
|
220
|
+
function pageBounds(options) {
|
|
221
|
+
const take = options?.take ?? DEFAULT_TAKE;
|
|
222
|
+
const skip = options?.skip ?? 0;
|
|
223
|
+
if (!Number.isInteger(take) || take < 1 || take > MAX_ORDER_LIST_TAKE) {
|
|
224
|
+
throw invalid(`take must be a whole number from 1 to ${String(MAX_ORDER_LIST_TAKE)}.`);
|
|
225
|
+
}
|
|
226
|
+
if (!Number.isInteger(skip) || skip < 0)
|
|
227
|
+
throw invalid('skip must be a whole number of 0 or more.');
|
|
228
|
+
return { skip, take };
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Pages through one order list. `read` answers the list (or `null` when its owner is gone); each
|
|
232
|
+
* following page re-sends the same filter, sort and per-call options, so a page cannot walk
|
|
233
|
+
* another store's orders.
|
|
234
|
+
*/
|
|
235
|
+
async function listOrders(read, options) {
|
|
236
|
+
const { skip, take } = pageBounds(options);
|
|
237
|
+
const filter = toOrderFilterParameter(options?.filter);
|
|
238
|
+
const sort = toOrderSort(options?.sort);
|
|
239
|
+
const fetchPage = async (pageSkip) => {
|
|
240
|
+
const redaction = redactionWatcher();
|
|
241
|
+
const list = await read({
|
|
242
|
+
options: {
|
|
243
|
+
skip: pageSkip,
|
|
244
|
+
take,
|
|
245
|
+
...(Object.keys(filter).length > 0 ? { filter, filterOperator: 'AND' } : {}),
|
|
246
|
+
...(sort ? { sort } : {}),
|
|
247
|
+
},
|
|
248
|
+
}, redaction.onExtensions);
|
|
249
|
+
if (list === null)
|
|
250
|
+
return null;
|
|
251
|
+
return pageFromVendureList({ items: list.items.map((item) => redaction.mark(item)), totalItems: list.totalItems }, pageSkip, take, async (cursor) => {
|
|
252
|
+
const next = await fetchPage(readOffsetCursor(cursor));
|
|
253
|
+
if (next === null) {
|
|
254
|
+
throw new UpstreamError({
|
|
255
|
+
code: 'UNEXPECTED_RESPONSE',
|
|
256
|
+
message: 'The customer was gone by the next page of their orders.',
|
|
257
|
+
status: 502,
|
|
258
|
+
service: 'vendure',
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
return next;
|
|
262
|
+
});
|
|
263
|
+
};
|
|
264
|
+
return fetchPage(skip);
|
|
265
|
+
}
|
|
266
|
+
export function createOrderListModule(transport) {
|
|
267
|
+
return {
|
|
268
|
+
async list(options) {
|
|
269
|
+
const page = await listOrders(async (variables, onExtensions) => {
|
|
270
|
+
const data = await transport.graphql({ api: 'admin', query: ORDERS_LIST_QUERY, variables, onExtensions }, options);
|
|
271
|
+
return data.orders;
|
|
272
|
+
}, options);
|
|
273
|
+
// `read` above never answers null: the store's own list always exists.
|
|
274
|
+
return page;
|
|
275
|
+
},
|
|
276
|
+
async count(filter, options) {
|
|
277
|
+
const parameter = toOrderFilterParameter(filter);
|
|
278
|
+
const data = await transport.graphql({
|
|
279
|
+
api: 'admin',
|
|
280
|
+
query: ORDERS_COUNT_QUERY,
|
|
281
|
+
variables: {
|
|
282
|
+
options: {
|
|
283
|
+
// Never 0: Vendure passes it through and TypeORM then sends no LIMIT, so a
|
|
284
|
+
// "count" would load every matching order. One row costs nothing.
|
|
285
|
+
take: 1,
|
|
286
|
+
...(Object.keys(parameter).length > 0
|
|
287
|
+
? { filter: parameter, filterOperator: 'AND' }
|
|
288
|
+
: {}),
|
|
289
|
+
},
|
|
290
|
+
},
|
|
291
|
+
}, options);
|
|
292
|
+
return data.orders.totalItems;
|
|
293
|
+
},
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
/**
|
|
297
|
+
* One customer's orders, as `customers.orders` reads them: the same rows, filter, sort and paging
|
|
298
|
+
* as `orders.list`, or `null` when the store holds no customer with that id.
|
|
299
|
+
*/
|
|
300
|
+
export async function listCustomerOrders(transport, customerId, options) {
|
|
301
|
+
return listOrders(async (variables, onExtensions) => {
|
|
302
|
+
const data = await transport.graphql({
|
|
303
|
+
api: 'admin',
|
|
304
|
+
query: CUSTOMER_ORDERS_QUERY,
|
|
305
|
+
variables: { id: customerId, ...variables },
|
|
306
|
+
onExtensions,
|
|
307
|
+
}, options);
|
|
308
|
+
return data.customer?.orders ?? null;
|
|
309
|
+
}, options);
|
|
310
|
+
}
|
|
311
|
+
/** The most orders `customers.recentOrders` answers. */
|
|
312
|
+
export const MAX_RECENT_ORDERS = 20;
|
|
313
|
+
const DEFAULT_RECENT_ORDERS = 5;
|
|
314
|
+
export const CUSTOMER_RECENT_ORDERS_QUERY = /* GraphQL */ `
|
|
315
|
+
query CustomerRecentOrders($id: ID!, $options: OrderListOptions) {
|
|
316
|
+
customer(id: $id) {
|
|
317
|
+
id
|
|
318
|
+
orders(options: $options) {
|
|
319
|
+
items {
|
|
320
|
+
id
|
|
321
|
+
code
|
|
322
|
+
orderPlacedAt
|
|
323
|
+
totalWithTax
|
|
324
|
+
currencyCode
|
|
325
|
+
lines {
|
|
326
|
+
id
|
|
327
|
+
quantity
|
|
328
|
+
listPriceIncludesTax
|
|
329
|
+
productVariant {
|
|
330
|
+
id
|
|
331
|
+
name
|
|
332
|
+
sku
|
|
333
|
+
product {
|
|
334
|
+
id
|
|
335
|
+
name
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
customFields {
|
|
339
|
+
unitPriceOverride
|
|
340
|
+
unitPriceImported
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
totalItems
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
`;
|
|
349
|
+
/**
|
|
350
|
+
* A customer's last placed orders, newest first, each with its lines, as `customers.recentOrders`
|
|
351
|
+
* reads them; `null` when the store holds no customer with that id.
|
|
352
|
+
*/
|
|
353
|
+
export async function listCustomerRecentOrders(transport, customerId, options) {
|
|
354
|
+
const { take = DEFAULT_RECENT_ORDERS, ...call } = options ?? {};
|
|
355
|
+
if (!Number.isInteger(take) || take < 1 || take > MAX_RECENT_ORDERS) {
|
|
356
|
+
throw invalid(`take must be a whole number from 1 to ${String(MAX_RECENT_ORDERS)}.`);
|
|
357
|
+
}
|
|
358
|
+
const data = await transport.graphql({
|
|
359
|
+
api: 'admin',
|
|
360
|
+
query: CUSTOMER_RECENT_ORDERS_QUERY,
|
|
361
|
+
variables: {
|
|
362
|
+
id: customerId,
|
|
363
|
+
options: {
|
|
364
|
+
take,
|
|
365
|
+
// Placed orders only: sorted on its own, `orderPlacedAt` descending lists the carts
|
|
366
|
+
// and drafts (no date) first.
|
|
367
|
+
filter: { orderPlacedAt: { isNull: false } },
|
|
368
|
+
// ONE key, on purpose. The engine applies the keys of a sort in the order its schema
|
|
369
|
+
// declares them, not the order they are sent in, and `id` is declared before
|
|
370
|
+
// `orderPlacedAt`: an id "tie-breaker" here sorted the orders by id (found live).
|
|
371
|
+
sort: { orderPlacedAt: 'DESC' },
|
|
372
|
+
},
|
|
373
|
+
},
|
|
374
|
+
}, call);
|
|
375
|
+
// The document selects exactly the members of `RecentOrder`: the answer is the wire's.
|
|
376
|
+
return data.customer ? data.customer.orders.items : null;
|
|
377
|
+
}
|
|
@@ -37,10 +37,19 @@ export interface DiscountPolicy {
|
|
|
37
37
|
* active reasons for that line. A till discount (`pos.sale.applyDiscount`) is not held to it.
|
|
38
38
|
*/
|
|
39
39
|
reasonRequired: boolean;
|
|
40
|
+
/**
|
|
41
|
+
* The store's ceiling on manual discounts in basis points (1000 = 10 %), or `null` for none: how
|
|
42
|
+
* far below the price the customer would get anyway (its contract included) staff without the
|
|
43
|
+
* `OverrideDiscountLimit` permission may take a line (`DISCOUNT_OVER_LIMIT`). Reducing a
|
|
44
|
+
* discount is never refused. The POS till is not held to it.
|
|
45
|
+
*/
|
|
46
|
+
maxDiscountBps: number | null;
|
|
40
47
|
}
|
|
41
48
|
export interface DiscountPolicyInput {
|
|
42
49
|
/** Omitted keeps the stored value. */
|
|
43
50
|
reasonRequired?: boolean;
|
|
51
|
+
/** 0..10000 basis points; omitted keeps the stored value, `null` removes the ceiling. */
|
|
52
|
+
maxDiscountBps?: number | null;
|
|
44
53
|
}
|
|
45
54
|
/**
|
|
46
55
|
* One price movement a manual-discount door made on an order. Append-only. Each row is a price
|
|
@@ -126,7 +135,7 @@ export interface ManualDiscountsModule {
|
|
|
126
135
|
}
|
|
127
136
|
export declare const DISCOUNT_REASONS_QUERY = "\n query DiscountReasons($includeInactive: Boolean) {\n discountReasons(includeInactive: $includeInactive) {\n \n id\n code\n label\n active\n createdAt\n updatedAt\n\n }\n }\n";
|
|
128
137
|
export declare const UPSERT_DISCOUNT_REASON_MUTATION = "\n mutation UpsertDiscountReason($input: UpsertDiscountReasonInput!) {\n upsertDiscountReason(input: $input) {\n \n id\n code\n label\n active\n createdAt\n updatedAt\n\n }\n }\n";
|
|
129
|
-
export declare const DISCOUNT_POLICY_QUERY = "\n query DiscountPolicy {\n discountPolicy {\n reasonRequired\n }\n }\n";
|
|
130
|
-
export declare const UPDATE_DISCOUNT_POLICY_MUTATION = "\n mutation UpdateDiscountPolicy($input: UpdateDiscountPolicyInput!) {\n updateDiscountPolicy(input: $input) {\n reasonRequired\n }\n }\n";
|
|
138
|
+
export declare const DISCOUNT_POLICY_QUERY = "\n query DiscountPolicy {\n discountPolicy {\n reasonRequired\n maxDiscountBps\n }\n }\n";
|
|
139
|
+
export declare const UPDATE_DISCOUNT_POLICY_MUTATION = "\n mutation UpdateDiscountPolicy($input: UpdateDiscountPolicyInput!) {\n updateDiscountPolicy(input: $input) {\n reasonRequired\n maxDiscountBps\n }\n }\n";
|
|
131
140
|
export declare const ORDER_MANUAL_DISCOUNTS_QUERY = "\n query OrderManualDiscounts($orderId: ID!) {\n orderManualDiscounts(orderId: $orderId) {\n \n id\n createdAt\n orderId\n orderLineId\n door\n amount\n amountWithTax\n currencyCode\n reason {\n id\n code\n label\n active\n }\n actorUserId\n onBehalfOfRef\n deviceRef\n callId\n\n }\n }\n";
|
|
132
141
|
export declare function createManualDiscountsModule(transport: Transport): ManualDiscountsModule;
|
|
@@ -44,6 +44,7 @@ export const DISCOUNT_POLICY_QUERY = /* GraphQL */ `
|
|
|
44
44
|
query DiscountPolicy {
|
|
45
45
|
discountPolicy {
|
|
46
46
|
reasonRequired
|
|
47
|
+
maxDiscountBps
|
|
47
48
|
}
|
|
48
49
|
}
|
|
49
50
|
`;
|
|
@@ -51,6 +52,7 @@ export const UPDATE_DISCOUNT_POLICY_MUTATION = /* GraphQL */ `
|
|
|
51
52
|
mutation UpdateDiscountPolicy($input: UpdateDiscountPolicyInput!) {
|
|
52
53
|
updateDiscountPolicy(input: $input) {
|
|
53
54
|
reasonRequired
|
|
55
|
+
maxDiscountBps
|
|
54
56
|
}
|
|
55
57
|
}
|
|
56
58
|
`;
|
|
@@ -161,6 +161,11 @@ export interface OrderManualPricingModule {
|
|
|
161
161
|
* neither `unitPriceOverride` nor `priceOverrideReason` (it asks for nothing); a negative price;
|
|
162
162
|
* `unitPriceOverride: null` on a line an external system priced (`orders.createOrRecover`
|
|
163
163
|
* external lines), which has no catalogue price to fall back to: state the price instead.
|
|
164
|
+
*
|
|
165
|
+
* `ORDER_LINE_VARIANT_UNPRICED` (`BusinessRuleError`, 422; absent from an engine released before
|
|
166
|
+
* 2026-10-10): `unitPriceOverride: null` on a line that states a manual price while its variant
|
|
167
|
+
* has no price in the store, which would leave the line nothing to charge. Nothing is written:
|
|
168
|
+
* state the price instead, or set a price for the variant in the store first.
|
|
164
169
|
*/
|
|
165
170
|
setLinePrices(orderId: string, input: SetLinePricesInput, options?: Call): Promise<OrderDiscounts>;
|
|
166
171
|
/**
|