@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,487 @@
|
|
|
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
|
+
/** {@link ORDER_SUMMARY_FIELDS} as an engine before `Order.billableTotalWithTax` accepts it. */
|
|
17
|
+
const ORDER_SUMMARY_FIELDS_BEFORE_BILLABLE = /* GraphQL */ `
|
|
18
|
+
id
|
|
19
|
+
code
|
|
20
|
+
state
|
|
21
|
+
total
|
|
22
|
+
totalWithTax
|
|
23
|
+
currencyCode
|
|
24
|
+
orderPlacedAt
|
|
25
|
+
customer {
|
|
26
|
+
id
|
|
27
|
+
firstName
|
|
28
|
+
lastName
|
|
29
|
+
emailAddress
|
|
30
|
+
addresses {
|
|
31
|
+
company
|
|
32
|
+
defaultBillingAddress
|
|
33
|
+
defaultShippingAddress
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
billingAddress {
|
|
37
|
+
company
|
|
38
|
+
}
|
|
39
|
+
shippingAddress {
|
|
40
|
+
company
|
|
41
|
+
}
|
|
42
|
+
lines {
|
|
43
|
+
quantity
|
|
44
|
+
}
|
|
45
|
+
payments {
|
|
46
|
+
id
|
|
47
|
+
state
|
|
48
|
+
}
|
|
49
|
+
customFields {
|
|
50
|
+
externalOrderId
|
|
51
|
+
externalPlatform
|
|
52
|
+
isGift
|
|
53
|
+
paymentStatus
|
|
54
|
+
fulfillmentStatus
|
|
55
|
+
returnStatus
|
|
56
|
+
lifecycleStatus
|
|
57
|
+
statusOverrides {
|
|
58
|
+
fulfillmentHoldReason
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
`;
|
|
62
|
+
export const ORDER_SUMMARY_FIELDS = /* GraphQL */ `
|
|
63
|
+
${ORDER_SUMMARY_FIELDS_BEFORE_BILLABLE}
|
|
64
|
+
billableTotals {
|
|
65
|
+
total
|
|
66
|
+
totalExcludingTax
|
|
67
|
+
}
|
|
68
|
+
`;
|
|
69
|
+
// Each document is spelled out with a named constant inside, never built by a function: the
|
|
70
|
+
// GraphQL cost spec (`graphql-cost-fits-repo.spec.ts`) resolves `${NAME}` statically.
|
|
71
|
+
export const ORDERS_LIST_QUERY = /* GraphQL */ `
|
|
72
|
+
query OrdersList($options: OrderListOptions) {
|
|
73
|
+
orders(options: $options) {
|
|
74
|
+
items {
|
|
75
|
+
${ORDER_SUMMARY_FIELDS}
|
|
76
|
+
}
|
|
77
|
+
totalItems
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
`;
|
|
81
|
+
const ORDERS_LIST_QUERY_BEFORE_BILLABLE = /* GraphQL */ `
|
|
82
|
+
query OrdersList($options: OrderListOptions) {
|
|
83
|
+
orders(options: $options) {
|
|
84
|
+
items {
|
|
85
|
+
${ORDER_SUMMARY_FIELDS_BEFORE_BILLABLE}
|
|
86
|
+
}
|
|
87
|
+
totalItems
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
`;
|
|
91
|
+
export const ORDERS_COUNT_QUERY = /* GraphQL */ `
|
|
92
|
+
query OrdersCount($options: OrderListOptions) {
|
|
93
|
+
orders(options: $options) {
|
|
94
|
+
totalItems
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
`;
|
|
98
|
+
export const CUSTOMER_ORDERS_QUERY = /* GraphQL */ `
|
|
99
|
+
query CustomerOrders($id: ID!, $options: OrderListOptions) {
|
|
100
|
+
customer(id: $id) {
|
|
101
|
+
id
|
|
102
|
+
orders(options: $options) {
|
|
103
|
+
items {
|
|
104
|
+
${ORDER_SUMMARY_FIELDS}
|
|
105
|
+
}
|
|
106
|
+
totalItems
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
`;
|
|
111
|
+
const CUSTOMER_ORDERS_QUERY_BEFORE_BILLABLE = /* GraphQL */ `
|
|
112
|
+
query CustomerOrders($id: ID!, $options: OrderListOptions) {
|
|
113
|
+
customer(id: $id) {
|
|
114
|
+
id
|
|
115
|
+
orders(options: $options) {
|
|
116
|
+
items {
|
|
117
|
+
${ORDER_SUMMARY_FIELDS_BEFORE_BILLABLE}
|
|
118
|
+
}
|
|
119
|
+
totalItems
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
`;
|
|
124
|
+
/**
|
|
125
|
+
* Whether a failure is "this engine does not know that field yet": the document refused before
|
|
126
|
+
* it ran, never an execution-time refusal or a transient failure (the purchasing module's rule).
|
|
127
|
+
*/
|
|
128
|
+
function isUnknownFieldRejection(error) {
|
|
129
|
+
if (!(error instanceof ValidationError) || error.service !== 'vendure')
|
|
130
|
+
return false;
|
|
131
|
+
return (error.code === 'BAD_REQUEST' ||
|
|
132
|
+
error.code === 'GRAPHQL_VALIDATION_FAILED' ||
|
|
133
|
+
/Cannot query field/i.test(error.message));
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Sends the current document; only an engine that refuses it as naming an unknown field (one
|
|
137
|
+
* before `Order.billableTotals`, services deploy separately) is sent the one before it.
|
|
138
|
+
*/
|
|
139
|
+
async function withBillableFallback(send) {
|
|
140
|
+
try {
|
|
141
|
+
return await send(false);
|
|
142
|
+
}
|
|
143
|
+
catch (error) {
|
|
144
|
+
if (!isUnknownFieldRejection(error))
|
|
145
|
+
throw error;
|
|
146
|
+
return send(true);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
function invalid(message) {
|
|
150
|
+
return new ValidationError({
|
|
151
|
+
code: 'INVALID_ORDER_LIST_OPTIONS',
|
|
152
|
+
message,
|
|
153
|
+
status: 400,
|
|
154
|
+
service: 'vendure',
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
function stringList(value, path) {
|
|
158
|
+
if (!Array.isArray(value) || value.some((item) => typeof item !== 'string')) {
|
|
159
|
+
throw invalid(`${path} must be a list of strings.`);
|
|
160
|
+
}
|
|
161
|
+
return [...value];
|
|
162
|
+
}
|
|
163
|
+
function text(value, path) {
|
|
164
|
+
if (typeof value !== 'string')
|
|
165
|
+
throw invalid(`${path} must be a string.`);
|
|
166
|
+
return value;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* An instant the engine compares without guessing a zone: a string with no offset would be read
|
|
170
|
+
* in the database server's zone, so a range would shift by hours with the server.
|
|
171
|
+
*/
|
|
172
|
+
const INSTANT = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(?::\d{2}(?:\.\d+)?)?(?:Z|[+-]\d{2}:\d{2})$/;
|
|
173
|
+
function instant(value, path) {
|
|
174
|
+
if (typeof value !== 'string' || !INSTANT.test(value) || Number.isNaN(Date.parse(value))) {
|
|
175
|
+
throw invalid(`${path} must be an ISO-8601 instant with an offset or Z.`);
|
|
176
|
+
}
|
|
177
|
+
return value;
|
|
178
|
+
}
|
|
179
|
+
function escapeRegex(value) {
|
|
180
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
181
|
+
}
|
|
182
|
+
/** The Admin API's `OrderFilterParameter` for a typed filter; unknown keys are refused. */
|
|
183
|
+
export function toOrderFilterParameter(filter) {
|
|
184
|
+
if (filter === undefined)
|
|
185
|
+
return {};
|
|
186
|
+
if (typeof filter !== 'object' || filter === null || Array.isArray(filter)) {
|
|
187
|
+
throw invalid('filter must be an object.');
|
|
188
|
+
}
|
|
189
|
+
const out = {};
|
|
190
|
+
for (const [key, value] of Object.entries(filter)) {
|
|
191
|
+
if (value === undefined)
|
|
192
|
+
continue;
|
|
193
|
+
switch (key) {
|
|
194
|
+
case 'ids':
|
|
195
|
+
out.id = { in: stringList(value, 'filter.ids') };
|
|
196
|
+
break;
|
|
197
|
+
case 'state':
|
|
198
|
+
case 'paymentStatus':
|
|
199
|
+
case 'lifecycleStatus':
|
|
200
|
+
out[key] = { in: stringList(value, `filter.${key}`) };
|
|
201
|
+
break;
|
|
202
|
+
case 'code': {
|
|
203
|
+
const code = value;
|
|
204
|
+
if (typeof code !== 'object' || code === null)
|
|
205
|
+
throw invalid('filter.code must be an object.');
|
|
206
|
+
const operators = {};
|
|
207
|
+
for (const [operator, operand] of Object.entries(code)) {
|
|
208
|
+
if (operand === undefined)
|
|
209
|
+
continue;
|
|
210
|
+
const path = `filter.code.${operator}`;
|
|
211
|
+
if (operator === 'eq' || operator === 'contains')
|
|
212
|
+
operators[operator] = text(operand, path);
|
|
213
|
+
else if (operator === 'startsWith')
|
|
214
|
+
operators.regex = `^${escapeRegex(text(operand, path))}`;
|
|
215
|
+
else
|
|
216
|
+
throw invalid(`${path} is not a code filter; use eq, contains or startsWith.`);
|
|
217
|
+
}
|
|
218
|
+
out.code = operators;
|
|
219
|
+
break;
|
|
220
|
+
}
|
|
221
|
+
case 'orderPlacedAt': {
|
|
222
|
+
const placed = value;
|
|
223
|
+
if (typeof placed !== 'object' || placed === null) {
|
|
224
|
+
throw invalid('filter.orderPlacedAt must be an object.');
|
|
225
|
+
}
|
|
226
|
+
const operators = {};
|
|
227
|
+
for (const [operator, operand] of Object.entries(placed)) {
|
|
228
|
+
if (operand === undefined)
|
|
229
|
+
continue;
|
|
230
|
+
const path = `filter.orderPlacedAt.${operator}`;
|
|
231
|
+
if (operator === 'isNull') {
|
|
232
|
+
if (typeof operand !== 'boolean')
|
|
233
|
+
throw invalid(`${path} must be a boolean.`);
|
|
234
|
+
operators.isNull = operand;
|
|
235
|
+
}
|
|
236
|
+
else if (operator === 'before' || operator === 'after') {
|
|
237
|
+
operators[operator] = instant(operand, path);
|
|
238
|
+
}
|
|
239
|
+
else {
|
|
240
|
+
throw invalid(`${path} is not a date filter; use isNull, before or after.`);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
out.orderPlacedAt = operators;
|
|
244
|
+
break;
|
|
245
|
+
}
|
|
246
|
+
case 'active':
|
|
247
|
+
if (typeof value !== 'boolean')
|
|
248
|
+
throw invalid('filter.active must be a boolean.');
|
|
249
|
+
out.active = { eq: value };
|
|
250
|
+
break;
|
|
251
|
+
case 'currencyCode':
|
|
252
|
+
out.currencyCode = { eq: text(value, 'filter.currencyCode') };
|
|
253
|
+
break;
|
|
254
|
+
case 'externalPlatform':
|
|
255
|
+
out.externalPlatform =
|
|
256
|
+
value === null ? { isNull: true } : { eq: text(value, 'filter.externalPlatform') };
|
|
257
|
+
break;
|
|
258
|
+
case 'customerLastName':
|
|
259
|
+
out.customerLastName = { contains: text(value, 'filter.customerLastName') };
|
|
260
|
+
break;
|
|
261
|
+
default:
|
|
262
|
+
throw invalid(`filter.${key} is not an order list filter.`);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
return out;
|
|
266
|
+
}
|
|
267
|
+
function toOrderSort(sort) {
|
|
268
|
+
if (sort === undefined)
|
|
269
|
+
return undefined;
|
|
270
|
+
if (typeof sort !== 'object' ||
|
|
271
|
+
sort === null ||
|
|
272
|
+
!ORDER_LIST_SORT_FIELDS.includes(sort.field) ||
|
|
273
|
+
(sort.direction !== 'ASC' && sort.direction !== 'DESC')) {
|
|
274
|
+
throw invalid(`sort must be { field: ${ORDER_LIST_SORT_FIELDS.join(' | ')}, direction: ASC | DESC }.`);
|
|
275
|
+
}
|
|
276
|
+
return { [sort.field]: sort.direction };
|
|
277
|
+
}
|
|
278
|
+
function pageBounds(options) {
|
|
279
|
+
const take = options?.take ?? DEFAULT_TAKE;
|
|
280
|
+
const skip = options?.skip ?? 0;
|
|
281
|
+
if (!Number.isInteger(take) || take < 1 || take > MAX_ORDER_LIST_TAKE) {
|
|
282
|
+
throw invalid(`take must be a whole number from 1 to ${String(MAX_ORDER_LIST_TAKE)}.`);
|
|
283
|
+
}
|
|
284
|
+
if (!Number.isInteger(skip) || skip < 0)
|
|
285
|
+
throw invalid('skip must be a whole number of 0 or more.');
|
|
286
|
+
return { skip, take };
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* Pages through one order list. `read` answers the list (or `null` when its owner is gone); each
|
|
290
|
+
* following page re-sends the same filter, sort and per-call options, so a page cannot walk
|
|
291
|
+
* another store's orders.
|
|
292
|
+
*/
|
|
293
|
+
async function listOrders(read, options) {
|
|
294
|
+
const { skip, take } = pageBounds(options);
|
|
295
|
+
const filter = toOrderFilterParameter(options?.filter);
|
|
296
|
+
const sort = toOrderSort(options?.sort);
|
|
297
|
+
const fetchPage = async (pageSkip) => {
|
|
298
|
+
const redaction = redactionWatcher();
|
|
299
|
+
const variables = {
|
|
300
|
+
options: {
|
|
301
|
+
skip: pageSkip,
|
|
302
|
+
take,
|
|
303
|
+
...(Object.keys(filter).length > 0 ? { filter, filterOperator: 'AND' } : {}),
|
|
304
|
+
...(sort ? { sort } : {}),
|
|
305
|
+
},
|
|
306
|
+
};
|
|
307
|
+
const list = await withBillableFallback((beforeBillable) => read(variables, redaction.onExtensions, beforeBillable));
|
|
308
|
+
if (list === null)
|
|
309
|
+
return null;
|
|
310
|
+
const items = list.items.map((item) => ({
|
|
311
|
+
...item,
|
|
312
|
+
billableTotals: item.billableTotals ?? null,
|
|
313
|
+
}));
|
|
314
|
+
return pageFromVendureList({ items: items.map((item) => redaction.mark(item)), totalItems: list.totalItems }, pageSkip, take, async (cursor) => {
|
|
315
|
+
const next = await fetchPage(readOffsetCursor(cursor));
|
|
316
|
+
if (next === null) {
|
|
317
|
+
throw new UpstreamError({
|
|
318
|
+
code: 'UNEXPECTED_RESPONSE',
|
|
319
|
+
message: 'The customer was gone by the next page of their orders.',
|
|
320
|
+
status: 502,
|
|
321
|
+
service: 'vendure',
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
return next;
|
|
325
|
+
});
|
|
326
|
+
};
|
|
327
|
+
return fetchPage(skip);
|
|
328
|
+
}
|
|
329
|
+
export function createOrderListModule(transport) {
|
|
330
|
+
return {
|
|
331
|
+
async list(options) {
|
|
332
|
+
const page = await listOrders(async (variables, onExtensions, beforeBillable) => {
|
|
333
|
+
const query = beforeBillable ? ORDERS_LIST_QUERY_BEFORE_BILLABLE : ORDERS_LIST_QUERY;
|
|
334
|
+
const data = await transport.graphql({ api: 'admin', query, variables, onExtensions }, options);
|
|
335
|
+
return data.orders;
|
|
336
|
+
}, options);
|
|
337
|
+
// `read` above never answers null: the store's own list always exists.
|
|
338
|
+
return page;
|
|
339
|
+
},
|
|
340
|
+
async count(filter, options) {
|
|
341
|
+
const parameter = toOrderFilterParameter(filter);
|
|
342
|
+
const data = await transport.graphql({
|
|
343
|
+
api: 'admin',
|
|
344
|
+
query: ORDERS_COUNT_QUERY,
|
|
345
|
+
variables: {
|
|
346
|
+
options: {
|
|
347
|
+
// Never 0: Vendure passes it through and TypeORM then sends no LIMIT, so a
|
|
348
|
+
// "count" would load every matching order. One row costs nothing.
|
|
349
|
+
take: 1,
|
|
350
|
+
...(Object.keys(parameter).length > 0
|
|
351
|
+
? { filter: parameter, filterOperator: 'AND' }
|
|
352
|
+
: {}),
|
|
353
|
+
},
|
|
354
|
+
},
|
|
355
|
+
}, options);
|
|
356
|
+
return data.orders.totalItems;
|
|
357
|
+
},
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* One customer's orders, as `customers.orders` reads them: the same rows, filter, sort and paging
|
|
362
|
+
* as `orders.list`, or `null` when the store holds no customer with that id.
|
|
363
|
+
*/
|
|
364
|
+
export async function listCustomerOrders(transport, customerId, options) {
|
|
365
|
+
return listOrders(async (variables, onExtensions, beforeBillable) => {
|
|
366
|
+
const data = await transport.graphql({
|
|
367
|
+
api: 'admin',
|
|
368
|
+
query: beforeBillable ? CUSTOMER_ORDERS_QUERY_BEFORE_BILLABLE : CUSTOMER_ORDERS_QUERY,
|
|
369
|
+
variables: { id: customerId, ...variables },
|
|
370
|
+
onExtensions,
|
|
371
|
+
}, options);
|
|
372
|
+
return data.customer?.orders ?? null;
|
|
373
|
+
}, options);
|
|
374
|
+
}
|
|
375
|
+
/** The most orders `customers.recentOrders` answers. */
|
|
376
|
+
export const MAX_RECENT_ORDERS = 20;
|
|
377
|
+
const DEFAULT_RECENT_ORDERS = 5;
|
|
378
|
+
export const CUSTOMER_RECENT_ORDERS_QUERY = /* GraphQL */ `
|
|
379
|
+
query CustomerRecentOrders($id: ID!, $options: OrderListOptions) {
|
|
380
|
+
customer(id: $id) {
|
|
381
|
+
id
|
|
382
|
+
orders(options: $options) {
|
|
383
|
+
items {
|
|
384
|
+
id
|
|
385
|
+
code
|
|
386
|
+
orderPlacedAt
|
|
387
|
+
totalWithTax
|
|
388
|
+
billableTotals {
|
|
389
|
+
total
|
|
390
|
+
totalExcludingTax
|
|
391
|
+
}
|
|
392
|
+
currencyCode
|
|
393
|
+
lines {
|
|
394
|
+
id
|
|
395
|
+
quantity
|
|
396
|
+
listPriceIncludesTax
|
|
397
|
+
productVariant {
|
|
398
|
+
id
|
|
399
|
+
name
|
|
400
|
+
sku
|
|
401
|
+
product {
|
|
402
|
+
id
|
|
403
|
+
name
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
customFields {
|
|
407
|
+
unitPriceOverride
|
|
408
|
+
unitPriceImported
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
totalItems
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
`;
|
|
417
|
+
const CUSTOMER_RECENT_ORDERS_QUERY_BEFORE_BILLABLE = /* GraphQL */ `
|
|
418
|
+
query CustomerRecentOrders($id: ID!, $options: OrderListOptions) {
|
|
419
|
+
customer(id: $id) {
|
|
420
|
+
id
|
|
421
|
+
orders(options: $options) {
|
|
422
|
+
items {
|
|
423
|
+
id
|
|
424
|
+
code
|
|
425
|
+
orderPlacedAt
|
|
426
|
+
totalWithTax
|
|
427
|
+
currencyCode
|
|
428
|
+
lines {
|
|
429
|
+
id
|
|
430
|
+
quantity
|
|
431
|
+
listPriceIncludesTax
|
|
432
|
+
productVariant {
|
|
433
|
+
id
|
|
434
|
+
name
|
|
435
|
+
sku
|
|
436
|
+
product {
|
|
437
|
+
id
|
|
438
|
+
name
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
customFields {
|
|
442
|
+
unitPriceOverride
|
|
443
|
+
unitPriceImported
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
totalItems
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
`;
|
|
452
|
+
/**
|
|
453
|
+
* A customer's last placed orders, newest first, each with its lines, as `customers.recentOrders`
|
|
454
|
+
* reads them; `null` when the store holds no customer with that id.
|
|
455
|
+
*/
|
|
456
|
+
export async function listCustomerRecentOrders(transport, customerId, options) {
|
|
457
|
+
const { take = DEFAULT_RECENT_ORDERS, ...call } = options ?? {};
|
|
458
|
+
if (!Number.isInteger(take) || take < 1 || take > MAX_RECENT_ORDERS) {
|
|
459
|
+
throw invalid(`take must be a whole number from 1 to ${String(MAX_RECENT_ORDERS)}.`);
|
|
460
|
+
}
|
|
461
|
+
const data = await withBillableFallback((beforeBillable) => transport.graphql({
|
|
462
|
+
api: 'admin',
|
|
463
|
+
query: beforeBillable
|
|
464
|
+
? CUSTOMER_RECENT_ORDERS_QUERY_BEFORE_BILLABLE
|
|
465
|
+
: CUSTOMER_RECENT_ORDERS_QUERY,
|
|
466
|
+
variables: {
|
|
467
|
+
id: customerId,
|
|
468
|
+
options: {
|
|
469
|
+
take,
|
|
470
|
+
// Placed orders only: sorted on its own, `orderPlacedAt` descending lists the carts
|
|
471
|
+
// and drafts (no date) first.
|
|
472
|
+
filter: { orderPlacedAt: { isNull: false } },
|
|
473
|
+
// ONE key, on purpose. The engine applies the keys of a sort in the order its schema
|
|
474
|
+
// declares them, not the order they are sent in, and `id` is declared before
|
|
475
|
+
// `orderPlacedAt`: an id "tie-breaker" here sorted the orders by id (found live).
|
|
476
|
+
sort: { orderPlacedAt: 'DESC' },
|
|
477
|
+
},
|
|
478
|
+
},
|
|
479
|
+
}, call));
|
|
480
|
+
// The document selects the members of `RecentOrder`; an older engine leaves out the billable one.
|
|
481
|
+
return data.customer
|
|
482
|
+
? data.customer.orders.items.map((order) => ({
|
|
483
|
+
...order,
|
|
484
|
+
billableTotals: order.billableTotals ?? null,
|
|
485
|
+
}))
|
|
486
|
+
: null;
|
|
487
|
+
}
|
|
@@ -41,7 +41,10 @@ export interface DiscountPolicy {
|
|
|
41
41
|
* The store's ceiling on manual discounts in basis points (1000 = 10 %), or `null` for none: how
|
|
42
42
|
* far below the price the customer would get anyway (its contract included) staff without the
|
|
43
43
|
* `OverrideDiscountLimit` permission may take a line (`DISCOUNT_OVER_LIMIT`). Reducing a
|
|
44
|
-
* discount is never refused. The POS till is
|
|
44
|
+
* discount is never refused. The POS till is held to it too (a till discount and a lowered
|
|
45
|
+
* till price, cart-wide and per line): there only a session holding `OverrideDiscountLimit`, or
|
|
46
|
+
* a staff member holding the explicit `discount_over_limit` grant (a grant no role holds by
|
|
47
|
+
* default), goes past it.
|
|
45
48
|
*/
|
|
46
49
|
maxDiscountBps: number | null;
|
|
47
50
|
}
|
|
@@ -63,14 +66,16 @@ export interface OrderManualDiscount {
|
|
|
63
66
|
/** The line the movement was on; `null` for a till discount on the whole cart. */
|
|
64
67
|
orderLineId: string | null;
|
|
65
68
|
/**
|
|
66
|
-
* `price_list`, `line_override` or `till` (`pos.sale.applyDiscount`, one row per call
|
|
67
|
-
*
|
|
69
|
+
* `price_list`, `line_override` or `till` (`pos.sale.applyDiscount`, one row per call, and a row
|
|
70
|
+
* per change the till made to that money since: a removal, a cap or a re-split). Accept a value
|
|
71
|
+
* you do not know.
|
|
68
72
|
*/
|
|
69
73
|
door: string;
|
|
70
74
|
/**
|
|
71
75
|
* The change of the line's total, net: (unit price after − before) × quantity, minor units of
|
|
72
76
|
* `currencyCode`, as the order holds it. Negative when the price fell (a manual discount). For
|
|
73
|
-
* `till`: the money the call's negative surcharges added
|
|
77
|
+
* `till`: the money the call's negative surcharges added; a later row of that discount carries
|
|
78
|
+
* the till's change, signed, so an order's `till` rows sum to its till discount in force.
|
|
74
79
|
*/
|
|
75
80
|
amount: number;
|
|
76
81
|
/** The same movement gross. */
|
|
@@ -85,7 +90,10 @@ export interface OrderManualDiscount {
|
|
|
85
90
|
} | null;
|
|
86
91
|
/** The Vendure user of the session that moved it. */
|
|
87
92
|
actorUserId: string | null;
|
|
88
|
-
/**
|
|
93
|
+
/**
|
|
94
|
+
* The vouched-for `x-on-behalf-of` ref; for a till vouched for nothing, `pos-staff:<id>`. A `till`
|
|
95
|
+
* row that changes a discount carries the ref of the row that gave it.
|
|
96
|
+
*/
|
|
89
97
|
onBehalfOfRef: string | null;
|
|
90
98
|
/** The vouched-for `x-device-ref` ref; for a paired till vouched for nothing, `pos-device:<id>`. */
|
|
91
99
|
deviceRef: string | null;
|
|
@@ -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
|
/**
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `admin.orders.moneyView(orderId, { basis })`: an order's money as rows that add up exactly to
|
|
3
|
+
* its own totals, in one basis (pricing-display-consistency, USER O12). Every surface that shows
|
|
4
|
+
* an order's money prints these rows, so an order page, an email and an invoice cannot disagree
|
|
5
|
+
* by a cent. The engine builds them (`Order.moneyView`); this module only reads them.
|
|
6
|
+
*/
|
|
7
|
+
import { type Transport } from '@sixtyninecommerce/core';
|
|
8
|
+
import type { Call } from '../types.js';
|
|
9
|
+
/**
|
|
10
|
+
* Which prices a view shows. `GROSS` = incl. VAT, `NET` = excl. VAT. `STORE` follows how the
|
|
11
|
+
* store sets its prices; `CUSTOMER` how the shop shows prices to the order's customer. The view
|
|
12
|
+
* answers the one it used, `GROSS` or `NET`.
|
|
13
|
+
*/
|
|
14
|
+
export declare const ORDER_MONEY_BASES: readonly ["STORE", "CUSTOMER", "GROSS", "NET"];
|
|
15
|
+
export type OrderMoneyBasis = (typeof ORDER_MONEY_BASES)[number];
|
|
16
|
+
/** One order line. Money is an integer in minor units of the view's `currencyCode`. */
|
|
17
|
+
export interface OrderMoneyLine {
|
|
18
|
+
orderLineId: string;
|
|
19
|
+
quantity: number;
|
|
20
|
+
taxRate: number;
|
|
21
|
+
/**
|
|
22
|
+
* The unit price, only when the line was priced in this basis (`unitAmount × quantity =
|
|
23
|
+
* amount`); null in the other basis, where only the line total multiplies out.
|
|
24
|
+
*/
|
|
25
|
+
unitAmount: number | null;
|
|
26
|
+
/** The line total before promotions. */
|
|
27
|
+
amount: number;
|
|
28
|
+
}
|
|
29
|
+
/** A promotion, a surcharge or a shipping line. A discount is negative. */
|
|
30
|
+
export interface OrderMoneyRow {
|
|
31
|
+
/** The promotion's adjustment source, the surcharge id or the shipping line id. */
|
|
32
|
+
key: string;
|
|
33
|
+
description: string;
|
|
34
|
+
amount: number;
|
|
35
|
+
/** The row's VAT rate; null for a promotion, which can span several. */
|
|
36
|
+
taxRate: number | null;
|
|
37
|
+
}
|
|
38
|
+
/** The VAT at one rate: goods, shipping and surcharges together, a staff rounding's VAT in. */
|
|
39
|
+
export interface OrderMoneyTaxRow {
|
|
40
|
+
taxRate: number;
|
|
41
|
+
/** Excl. VAT. */
|
|
42
|
+
base: number;
|
|
43
|
+
amount: number;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Why a view gives no still-to-pay figure: `KEPT_IN_ERP`, the order was placed on a B2B account
|
|
47
|
+
* kept in an external accounting system, so print a note ("paid via your account in the
|
|
48
|
+
* accounting system") instead of an amount. A new value may be added.
|
|
49
|
+
*/
|
|
50
|
+
export type OrderMoneyStillToPayNote = 'KEPT_IN_ERP';
|
|
51
|
+
/**
|
|
52
|
+
* What has been paid and what is still to pay, gross; a zero row is not printed. An engine that
|
|
53
|
+
* answers `stillToPayNote` (null included) reads the B2B account ledger: money paid or credited on
|
|
54
|
+
* an account invoice is in `paid` and `credited`. Without it (an older engine) it is not, so an
|
|
55
|
+
* order a live account invoice bills reads its whole remainder as `stillToPay`: do not print that
|
|
56
|
+
* figure for it.
|
|
57
|
+
*/
|
|
58
|
+
export interface OrderMoneyBalance {
|
|
59
|
+
/** Money received or held by a payment provider, less refunds; never a payment still to arrive. */
|
|
60
|
+
paid: number;
|
|
61
|
+
giftCard: number;
|
|
62
|
+
storeCredit: number;
|
|
63
|
+
/** What credit notes took off the bill. */
|
|
64
|
+
credited: number;
|
|
65
|
+
/** What the order bills less the four above, never below zero. A bank-transfer or net-terms promise still counts as to pay. Zero when `stillToPayNote` is set. */
|
|
66
|
+
stillToPay: number;
|
|
67
|
+
/** Set when no still-to-pay figure can be given (print its note); null otherwise; absent on an older engine. */
|
|
68
|
+
stillToPayNote?: OrderMoneyStillToPayNote | null;
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* The rows and their identities: `Σ lines + Σ goodsAdjustments + Σ surcharges = subtotal`;
|
|
72
|
+
* `Σ shipping + Σ shippingAdjustments = shippingTotal`; on `GROSS` `subtotal + shippingTotal +
|
|
73
|
+
* (rounding ?? 0) = total`; on `NET` `subtotal + shippingTotal + taxTotal + (rounding ?? 0) =
|
|
74
|
+
* total`; `Σ taxes = taxTotal`; `totalExcludingTax + taxTotal = total`.
|
|
75
|
+
*/
|
|
76
|
+
export interface OrderMoneyView {
|
|
77
|
+
basis: 'GROSS' | 'NET';
|
|
78
|
+
currencyCode: string;
|
|
79
|
+
lines: OrderMoneyLine[];
|
|
80
|
+
/** One row per promotion on the goods (price-list order rules and coupons included). */
|
|
81
|
+
goodsAdjustments: OrderMoneyRow[];
|
|
82
|
+
/** Fees (positive) and staff discounts (negative). */
|
|
83
|
+
surcharges: OrderMoneyRow[];
|
|
84
|
+
subtotal: number;
|
|
85
|
+
/** Each shipping line before its promotions. */
|
|
86
|
+
shipping: OrderMoneyRow[];
|
|
87
|
+
/** One row per promotion on shipping. */
|
|
88
|
+
shippingAdjustments: OrderMoneyRow[];
|
|
89
|
+
shippingTotal: number;
|
|
90
|
+
/** Everything excl. VAT, a staff rounding's net part in: the invoice's "Total excl. VAT". */
|
|
91
|
+
totalExcludingTax: number;
|
|
92
|
+
/** One row per VAT rate. */
|
|
93
|
+
taxes: OrderMoneyTaxRow[];
|
|
94
|
+
/** True on `GROSS`: the VAT rows are inside the total, not added to it. */
|
|
95
|
+
taxIncluded: boolean;
|
|
96
|
+
taxTotal: number;
|
|
97
|
+
/** A staff rounding, printed just above the total (gross on `GROSS`, excl. VAT on `NET`). */
|
|
98
|
+
rounding: number | null;
|
|
99
|
+
/** What the order bills, incl. VAT, after a staff rounding. */
|
|
100
|
+
total: number;
|
|
101
|
+
/** The total before a staff rounding. */
|
|
102
|
+
totalBeforeRounding: number;
|
|
103
|
+
balance: OrderMoneyBalance;
|
|
104
|
+
/** False only when the order's stored totals disagree with its own rows. */
|
|
105
|
+
reconciles: boolean;
|
|
106
|
+
}
|
|
107
|
+
/** Every field of an `OrderMoneyView`, at every depth: the selection each document reads it with. */
|
|
108
|
+
export declare const ORDER_MONEY_VIEW_FIELDS = "\n basis\n currencyCode\n lines { orderLineId quantity taxRate unitAmount amount }\n goodsAdjustments { key description amount taxRate }\n surcharges { key description amount taxRate }\n subtotal\n shipping { key description amount taxRate }\n shippingAdjustments { key description amount taxRate }\n shippingTotal\n totalExcludingTax\n taxes { taxRate base amount }\n taxIncluded\n taxTotal\n rounding\n total\n totalBeforeRounding\n balance { paid giftCard storeCredit credited stillToPay stillToPayNote }\n reconciles\n";
|
|
109
|
+
export declare const ORDER_MONEY_VIEW_QUERY = "\n query OrderMoneyView($id: ID!, $basis: OrderMoneyBasis!) {\n order(id: $id) {\n id\n moneyView(basis: $basis) {\n basis\n currencyCode\n lines { orderLineId quantity taxRate unitAmount amount }\n goodsAdjustments { key description amount taxRate }\n surcharges { key description amount taxRate }\n subtotal\n shipping { key description amount taxRate }\n shippingAdjustments { key description amount taxRate }\n shippingTotal\n totalExcludingTax\n taxes { taxRate base amount }\n taxIncluded\n taxTotal\n rounding\n total\n totalBeforeRounding\n balance { paid giftCard storeCredit credited stillToPay stillToPayNote }\n reconciles\n }\n }\n }\n";
|
|
110
|
+
/** `INVALID_ORDER_MONEY_BASIS` for a basis not in `ORDER_MONEY_BASES`, before anything is sent. */
|
|
111
|
+
export declare function assertOrderMoneyBasis(basis: string): asserts basis is OrderMoneyBasis;
|
|
112
|
+
export interface OrderMoneyViewModule {
|
|
113
|
+
/**
|
|
114
|
+
* The order's money as rows that add up exactly to its stored totals, in `options.basis`
|
|
115
|
+
* (default `STORE`). Print these rows as they come, never re-derived: an amount re-computed
|
|
116
|
+
* from them, or from the order's other figures, can miss the order's own total by a cent.
|
|
117
|
+
* Needs `ReadOrder`.
|
|
118
|
+
*
|
|
119
|
+
* - A unit price (`lines[].unitAmount`) is only answered in the basis the line was priced in;
|
|
120
|
+
* show the line total alone in the other.
|
|
121
|
+
* - The VAT rows are one per rate. On a `GROSS` view they are included in the total
|
|
122
|
+
* (`taxIncluded`): label them so, never as an addition.
|
|
123
|
+
* - `balance.stillToPay` is money not received yet: a bank-transfer or net-terms payment that
|
|
124
|
+
* is promised still counts. With `balance.stillToPayNote` answered it reads the B2B account
|
|
125
|
+
* ledger; `KEPT_IN_ERP` means print its note, not a figure. Not answered (an older engine,
|
|
126
|
+
* resent without it): for an order a live account invoice bills, show the other rows only.
|
|
127
|
+
* - It reads the order as STORED: it cannot preview an edit (`planEdit`'s `preview.moneyView` does).
|
|
128
|
+
*
|
|
129
|
+
* Refused: `INVALID_ORDER_MONEY_BASIS` (`ValidationError`, 400, before sending) for a basis
|
|
130
|
+
* not in `ORDER_MONEY_BASES`; `ORDER_NOT_FOUND` (`NotFoundError`, 404) for an order this store
|
|
131
|
+
* does not hold. An engine before `Order.moneyView` refuses the document as
|
|
132
|
+
* `ValidationError` `GRAPHQL_VALIDATION_FAILED` (400): fall back to the order's own figures.
|
|
133
|
+
*
|
|
134
|
+
* @effect read
|
|
135
|
+
*/
|
|
136
|
+
moneyView(orderId: string, options?: Call & {
|
|
137
|
+
basis?: OrderMoneyBasis;
|
|
138
|
+
}): Promise<OrderMoneyView>;
|
|
139
|
+
}
|
|
140
|
+
/** `document` without `stillToPayNote`: what an engine before it accepts. */
|
|
141
|
+
export declare function withoutStillToPayNote(document: string): string;
|
|
142
|
+
/**
|
|
143
|
+
* The transport, sending a document that names `balance.stillToPayNote` (pricing-display-consistency
|
|
144
|
+
* B1c) once more without it when the engine refused it as unknown. Safe for a mutation too: a
|
|
145
|
+
* refused document never ran. The newest money-view field, so it falls away first: wrap it inside
|
|
146
|
+
* any other `*Aware` transport.
|
|
147
|
+
*/
|
|
148
|
+
export declare function stillToPayNoteAware(transport: Pick<Transport, 'graphql'>): Pick<Transport, 'graphql'>;
|
|
149
|
+
export declare function createOrderMoneyViewModule(transport: Transport): OrderMoneyViewModule;
|