@sixtyninecommerce/admin 0.10.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (247) hide show
  1. package/README.md +4347 -171
  2. package/dist/catalog/assets.d.ts +120 -8
  3. package/dist/catalog/assets.js +98 -12
  4. package/dist/catalog/collections.d.ts +279 -14
  5. package/dist/catalog/collections.js +246 -15
  6. package/dist/catalog/index.d.ts +9 -2
  7. package/dist/catalog/index.js +4 -0
  8. package/dist/catalog/products.d.ts +159 -19
  9. package/dist/catalog/products.js +88 -13
  10. package/dist/catalog/properties.d.ts +102 -14
  11. package/dist/catalog/properties.js +13 -0
  12. package/dist/catalog/recommendations.d.ts +261 -0
  13. package/dist/catalog/recommendations.js +145 -0
  14. package/dist/catalog/reviews.d.ts +368 -0
  15. package/dist/catalog/reviews.js +318 -0
  16. package/dist/catalog/types.d.ts +17 -1
  17. package/dist/catalog/types.js +10 -0
  18. package/dist/catalog/variant-find.d.ts +136 -0
  19. package/dist/catalog/variant-find.js +239 -0
  20. package/dist/catalog/variants.d.ts +233 -26
  21. package/dist/catalog/variants.js +125 -7
  22. package/dist/catalog/visibility.d.ts +20 -5
  23. package/dist/catalog/visibility.js +19 -1
  24. package/dist/client.d.ts +95 -9
  25. package/dist/client.js +35 -7
  26. package/dist/content/assets.d.ts +286 -0
  27. package/dist/content/assets.js +181 -0
  28. package/dist/content/items.d.ts +269 -0
  29. package/dist/content/items.js +170 -0
  30. package/dist/content/types.d.ts +282 -0
  31. package/dist/content/types.js +100 -0
  32. package/dist/customers/age-verification.d.ts +66 -0
  33. package/dist/customers/age-verification.js +79 -0
  34. package/dist/customers/credit.d.ts +263 -0
  35. package/dist/customers/credit.js +244 -0
  36. package/dist/customers/delivery-preferences.d.ts +120 -0
  37. package/dist/customers/delivery-preferences.js +97 -0
  38. package/dist/customers/groups.d.ts +207 -0
  39. package/dist/customers/groups.js +438 -0
  40. package/dist/customers/index.d.ts +447 -37
  41. package/dist/customers/index.js +313 -40
  42. package/dist/customers/invitation-status.d.ts +57 -0
  43. package/dist/customers/invitation-status.js +21 -0
  44. package/dist/customers/notes.d.ts +67 -0
  45. package/dist/customers/notes.js +51 -0
  46. package/dist/customers/notification-recipients.d.ts +97 -0
  47. package/dist/customers/notification-recipients.js +84 -0
  48. package/dist/customers/saved-lists.d.ts +42 -0
  49. package/dist/customers/saved-lists.js +61 -0
  50. package/dist/customers/vat.d.ts +83 -0
  51. package/dist/customers/vat.js +46 -0
  52. package/dist/customers/wire.d.ts +20 -0
  53. package/dist/customers/wire.js +35 -0
  54. package/dist/documents/ar.d.ts +307 -0
  55. package/dist/documents/ar.js +254 -0
  56. package/dist/documents/index.d.ts +731 -21
  57. package/dist/documents/index.js +436 -24
  58. package/dist/documents/pdf.d.ts +2 -0
  59. package/dist/documents/pdf.js +11 -0
  60. package/dist/fulfillments/create.d.ts +167 -0
  61. package/dist/fulfillments/create.js +216 -0
  62. package/dist/fulfillments/index.d.ts +44 -10
  63. package/dist/fulfillments/index.js +11 -2
  64. package/dist/fulfillments/payment-policy.d.ts +64 -0
  65. package/dist/fulfillments/payment-policy.js +140 -0
  66. package/dist/fulfillments/warehouse.d.ts +724 -0
  67. package/dist/fulfillments/warehouse.js +914 -0
  68. package/dist/geo/index.d.ts +119 -0
  69. package/dist/geo/index.js +107 -0
  70. package/dist/index.d.ts +123 -35
  71. package/dist/index.js +45 -12
  72. package/dist/integrations/afas-actions.d.ts +234 -0
  73. package/dist/integrations/afas-actions.js +310 -0
  74. package/dist/integrations/afas-types.d.ts +483 -0
  75. package/dist/integrations/afas-types.js +5 -0
  76. package/dist/integrations/afas.d.ts +234 -0
  77. package/dist/integrations/afas.js +290 -0
  78. package/dist/integrations/connections.d.ts +103 -0
  79. package/dist/integrations/connections.js +55 -0
  80. package/dist/integrations/esp.d.ts +313 -0
  81. package/dist/integrations/esp.js +169 -0
  82. package/dist/integrations/exact-online-types.d.ts +423 -0
  83. package/dist/integrations/exact-online-types.js +6 -0
  84. package/dist/integrations/exact-online.d.ts +248 -0
  85. package/dist/integrations/exact-online.js +376 -0
  86. package/dist/integrations/index.d.ts +29 -3
  87. package/dist/integrations/index.js +18 -3
  88. package/dist/integrations/pipeline-keys.d.ts +13 -0
  89. package/dist/integrations/pipeline-keys.js +22 -0
  90. package/dist/integrations/pipelines.d.ts +15 -14
  91. package/dist/integrations/pipelines.js +6 -22
  92. package/dist/integrations/types.d.ts +146 -0
  93. package/dist/locations/index.d.ts +66 -0
  94. package/dist/locations/index.js +31 -0
  95. package/dist/meta/index.d.ts +162 -0
  96. package/dist/orders/cancel-with-money.d.ts +227 -0
  97. package/dist/orders/cancel-with-money.js +153 -0
  98. package/dist/orders/commit-edit.d.ts +7 -1
  99. package/dist/orders/commit-edit.js +5 -1
  100. package/dist/orders/drafts.d.ts +800 -0
  101. package/dist/orders/drafts.js +771 -0
  102. package/dist/orders/fields.d.ts +245 -0
  103. package/dist/orders/fields.js +188 -0
  104. package/dist/orders/get.d.ts +29 -19
  105. package/dist/orders/get.js +17 -8
  106. package/dist/orders/index.d.ts +49 -9
  107. package/dist/orders/index.js +22 -2
  108. package/dist/orders/lifecycle.d.ts +128 -0
  109. package/dist/orders/lifecycle.js +158 -0
  110. package/dist/orders/line-price-preview.d.ts +7 -2
  111. package/dist/orders/list.d.ts +222 -0
  112. package/dist/orders/list.js +377 -0
  113. package/dist/orders/manual-pricing.d.ts +5 -0
  114. package/dist/orders/order-entry.d.ts +20 -7
  115. package/dist/orders/plan-edit.d.ts +1 -1
  116. package/dist/orders/plan-edit.js +4 -1
  117. package/dist/orders/settings.d.ts +201 -0
  118. package/dist/orders/settings.js +325 -0
  119. package/dist/orders/status.d.ts +159 -13
  120. package/dist/orders/status.js +21 -0
  121. package/dist/orders/surcharges.d.ts +8 -1
  122. package/dist/orders/surcharges.js +3 -2
  123. package/dist/payments/account-credit.d.ts +30 -0
  124. package/dist/payments/account-credit.js +19 -0
  125. package/dist/payments/ar.d.ts +292 -0
  126. package/dist/payments/ar.js +223 -0
  127. package/dist/payments/connected-account.d.ts +47 -0
  128. package/dist/payments/connected-account.js +61 -0
  129. package/dist/payments/credit-noted-fields.d.ts +12 -0
  130. package/dist/payments/credit-noted-fields.js +37 -0
  131. package/dist/payments/index.d.ts +257 -11
  132. package/dist/payments/index.js +131 -1
  133. package/dist/payments/methods.d.ts +303 -8
  134. package/dist/payments/methods.js +337 -7
  135. package/dist/payments/mollie-methods.d.ts +159 -0
  136. package/dist/payments/mollie-methods.js +141 -0
  137. package/dist/payments/payment-links.d.ts +180 -0
  138. package/dist/payments/payment-links.js +97 -0
  139. package/dist/payments/provider-keys.d.ts +150 -0
  140. package/dist/payments/provider-keys.js +118 -0
  141. package/dist/payments/providers.d.ts +86 -11
  142. package/dist/payments/providers.js +29 -0
  143. package/dist/payments/requests.d.ts +144 -0
  144. package/dist/payments/requests.js +92 -0
  145. package/dist/payments/store-credit-fields.d.ts +15 -0
  146. package/dist/payments/store-credit-fields.js +51 -0
  147. package/dist/pickups/index.d.ts +104 -0
  148. package/dist/pickups/index.js +105 -0
  149. package/dist/platform/channels.d.ts +132 -0
  150. package/dist/platform/channels.js +128 -0
  151. package/dist/platform/geo.d.ts +123 -0
  152. package/dist/platform/geo.js +144 -0
  153. package/dist/platform/tax.d.ts +154 -0
  154. package/dist/platform/tax.js +139 -0
  155. package/dist/pos/anomalies.d.ts +158 -0
  156. package/dist/pos/anomalies.js +64 -0
  157. package/dist/pos/assisted-selling.d.ts +79 -0
  158. package/dist/pos/assisted-selling.js +38 -0
  159. package/dist/pos/exchanges.d.ts +103 -0
  160. package/dist/pos/exchanges.js +22 -0
  161. package/dist/pos/gift-cards.d.ts +135 -0
  162. package/dist/pos/gift-cards.js +47 -0
  163. package/dist/pos/index.d.ts +2125 -32
  164. package/dist/pos/index.js +742 -4
  165. package/dist/pos/no-receipt.d.ts +94 -0
  166. package/dist/pos/no-receipt.js +25 -0
  167. package/dist/pos/offline-sales.d.ts +187 -0
  168. package/dist/pos/offline-sales.js +116 -0
  169. package/dist/pos/pay-by-link.d.ts +143 -0
  170. package/dist/pos/pay-by-link.js +57 -0
  171. package/dist/pos/quick-keys.d.ts +103 -0
  172. package/dist/pos/quick-keys.js +45 -0
  173. package/dist/pos/reports.d.ts +360 -0
  174. package/dist/pos/reports.js +62 -0
  175. package/dist/pos/returns.d.ts +217 -0
  176. package/dist/pos/returns.js +53 -0
  177. package/dist/pricing/bulk-coupons.d.ts +139 -0
  178. package/dist/pricing/bulk-coupons.js +112 -0
  179. package/dist/pricing/index.d.ts +174 -4
  180. package/dist/pricing/index.js +174 -1
  181. package/dist/pricing/price-lists.d.ts +604 -0
  182. package/dist/pricing/price-lists.js +600 -0
  183. package/dist/purchasing/alerts.d.ts +89 -0
  184. package/dist/purchasing/alerts.js +62 -0
  185. package/dist/purchasing/cost.d.ts +110 -0
  186. package/dist/purchasing/cost.js +86 -0
  187. package/dist/purchasing/index.d.ts +36 -0
  188. package/dist/purchasing/index.js +16 -0
  189. package/dist/purchasing/purchase-orders.d.ts +548 -0
  190. package/dist/purchasing/purchase-orders.js +491 -0
  191. package/dist/purchasing/replenishment.d.ts +281 -0
  192. package/dist/purchasing/replenishment.js +240 -0
  193. package/dist/purchasing/settings.d.ts +152 -0
  194. package/dist/purchasing/settings.js +181 -0
  195. package/dist/purchasing/suppliers.d.ts +476 -0
  196. package/dist/purchasing/suppliers.js +438 -0
  197. package/dist/quotes/index.d.ts +501 -0
  198. package/dist/quotes/index.js +439 -0
  199. package/dist/reports/index.d.ts +71 -8
  200. package/dist/reports/index.js +74 -11
  201. package/dist/returns/index.d.ts +614 -21
  202. package/dist/returns/index.js +695 -11
  203. package/dist/search/index.d.ts +76 -1
  204. package/dist/search/index.js +63 -0
  205. package/dist/shipping/definitions.d.ts +29 -0
  206. package/dist/shipping/definitions.js +47 -0
  207. package/dist/shipping/fulfillment-profiles.d.ts +174 -0
  208. package/dist/shipping/fulfillment-profiles.js +104 -0
  209. package/dist/shipping/hendriks.d.ts +97 -0
  210. package/dist/shipping/hendriks.js +50 -0
  211. package/dist/shipping/index.d.ts +48 -0
  212. package/dist/shipping/index.js +25 -0
  213. package/dist/shipping/methods.d.ts +198 -0
  214. package/dist/shipping/methods.js +240 -0
  215. package/dist/shipping/myparcel.d.ts +254 -0
  216. package/dist/shipping/myparcel.js +178 -0
  217. package/dist/shipping/parcel-count-suggestion.d.ts +2 -0
  218. package/dist/shipping/parcel-rule.d.ts +6 -5
  219. package/dist/shipping/parcel-rule.js +21 -23
  220. package/dist/shipping/rate-tables.d.ts +179 -0
  221. package/dist/shipping/rate-tables.js +184 -0
  222. package/dist/stock/index.d.ts +10 -3
  223. package/dist/stock/index.js +3 -0
  224. package/dist/stock/locations.d.ts +144 -0
  225. package/dist/stock/locations.js +168 -0
  226. package/dist/stock/transfers.d.ts +216 -43
  227. package/dist/stock/transfers.js +140 -13
  228. package/dist/stored-value/index.d.ts +214 -4
  229. package/dist/stored-value/index.js +152 -0
  230. package/dist/subscriptions/index.d.ts +682 -0
  231. package/dist/subscriptions/index.js +815 -0
  232. package/dist/tax/index.d.ts +76 -1
  233. package/dist/tax/index.js +50 -0
  234. package/dist/tenant/email-style.d.ts +102 -0
  235. package/dist/tenant/email-style.js +72 -0
  236. package/dist/tenant/email-templates.d.ts +66 -0
  237. package/dist/tenant/email-templates.js +54 -0
  238. package/dist/tenant/notifications.d.ts +23 -17
  239. package/dist/tenant/settings-sources.d.ts +1 -1
  240. package/dist/tenant/time-zone.d.ts +17 -0
  241. package/dist/tenant/time-zone.js +11 -0
  242. package/dist/types.d.ts +50 -3
  243. package/dist/users/index.d.ts +3 -0
  244. package/dist/users/index.js +2 -0
  245. package/dist/users/warehouses.d.ts +50 -0
  246. package/dist/users/warehouses.js +51 -0
  247. package/package.json +2 -2
@@ -0,0 +1,154 @@
1
+ import { type Transport } from '@sixtyninecommerce/core';
2
+ import type { AdminClientConfig } from '../client.js';
3
+ import { type TaxCategory, type TaxRate } from '../tax/index.js';
4
+ import type { Call } from '../types.js';
5
+ /** A new platform-wide tax category, as {@link PlatformTaxCategoriesModule.create} takes it. */
6
+ export interface CreateTaxCategoryInput {
7
+ name: string;
8
+ /**
9
+ * Make it the platform's default category. Only one category is the default: setting it here
10
+ * takes the mark off the one that had it. Not the default when left out.
11
+ */
12
+ isDefault?: boolean;
13
+ }
14
+ /** A change to a tax category. A field left out keeps what the category has. */
15
+ export interface UpdateTaxCategoryInput {
16
+ name?: string;
17
+ /** `true` moves the default mark here (off the category that had it). */
18
+ isDefault?: boolean;
19
+ }
20
+ /** A new platform-wide tax rate, as {@link PlatformTaxRatesModule.create} takes it. */
21
+ export interface CreateTaxRateInput {
22
+ name: string;
23
+ /**
24
+ * A percentage: `21` is 21 %. Not money. The engine keeps two decimals (`5.5`, `20.75`), so
25
+ * a third one is rounded when it is stored; the answer carries the stored value.
26
+ */
27
+ value: number;
28
+ /** A disabled rate is never applied. Required: a rate is applied from the moment it exists. */
29
+ enabled: boolean;
30
+ /** The tax category it prices (`tax.categories.list`). */
31
+ categoryId: string;
32
+ /** The zone it prices that category in (`geo.zones.list`). */
33
+ zoneId: string;
34
+ /** Only for customers of this group. Left out, the rate applies to every customer. */
35
+ customerGroupId?: string;
36
+ }
37
+ /**
38
+ * A change to a tax rate. A field left out keeps what the rate has.
39
+ *
40
+ * There is no way to take the customer group OFF a rate: the engine ignores a null group and
41
+ * keeps the one stored, so `customerGroupId: null` is refused here rather than silently
42
+ * dropped. To widen a group-limited rate to every customer, create a rate without a group and
43
+ * delete the old one.
44
+ */
45
+ export interface UpdateTaxRateInput {
46
+ name?: string;
47
+ /** See {@link CreateTaxRateInput.value}. */
48
+ value?: number;
49
+ enabled?: boolean;
50
+ categoryId?: string;
51
+ zoneId?: string;
52
+ /** Move the rate to another customer group. */
53
+ customerGroupId?: string;
54
+ }
55
+ /**
56
+ * `admin.platform.tax.categories` — the SuperAdmin writes of the platform-wide tax categories
57
+ * every store shares (spec §9.2 `platform`, ruling G128). Reads are `tax.categories.list()`.
58
+ *
59
+ * Every method needs a human SuperAdmin session: an API token or an app credential is refused
60
+ * with `PLATFORM_REQUIRES_SESSION` (`PermissionDeniedError`, 403) BEFORE anything is sent, and a
61
+ * store administrator is refused by the engine with `PLATFORM_SETTINGS_NOT_ALLOWED`
62
+ * (`PermissionDeniedError`, 403) before anything is read or written. No tenant is needed on the
63
+ * client.
64
+ */
65
+ export interface PlatformTaxCategoriesModule {
66
+ /**
67
+ * Create a tax category, and answer it as `tax.categories.list()` reads it.
68
+ *
69
+ * `INVALID_TAX_CATEGORY_INPUT` (`ValidationError`, 400): a missing or blank name, or an
70
+ * `isDefault` that is not a boolean, refused here before anything is sent.
71
+ *
72
+ * @effect write
73
+ */
74
+ create(input: CreateTaxCategoryInput, options?: Call): Promise<TaxCategory>;
75
+ /**
76
+ * Rename a tax category or move the default mark to it, and answer it as read. Every store
77
+ * mapping a tax class onto it, and every rate pricing it, keeps pointing at it.
78
+ *
79
+ * `ENTITY_NOT_FOUND` (`NotFoundError`, 404): no category has that id.
80
+ *
81
+ * @effect write
82
+ */
83
+ update(id: string, patch: UpdateTaxCategoryInput, options?: Call): Promise<TaxCategory>;
84
+ /**
85
+ * Delete a tax category nothing uses any more.
86
+ *
87
+ * - `TAX_CATEGORY_IN_USE` (`ConflictError`, 409): something still prices or carries it. The
88
+ * message names what: the tax rates pricing it, each store's tax class mapped to it (by key
89
+ * and store code), how many product variants carry it, and whether deleted variants or
90
+ * orders were taxed with it. Rates, classes and live variants can be moved to another
91
+ * category; deleted variants and orders keep it for good, so such a category can never be
92
+ * deleted. Nothing is deleted.
93
+ * - `TAX_CATEGORY_NOT_DELETED` (`ConflictError`, 409): the engine refused it for a reason it
94
+ * answered as a result rather than an error, with that reason.
95
+ * - `ENTITY_NOT_FOUND` (`NotFoundError`, 404): no category has that id.
96
+ *
97
+ * @effect destructive
98
+ */
99
+ delete(id: string, options?: Call): Promise<void>;
100
+ }
101
+ /**
102
+ * `admin.platform.tax.rates` — the SuperAdmin writes of the platform-wide tax rates: what a tax
103
+ * category costs in a zone. One rate serves every store, so a change reaches every store selling
104
+ * into that zone. Reads are `tax.rates.list()`.
105
+ *
106
+ * Every method needs a human SuperAdmin session (`PLATFORM_REQUIRES_SESSION` before anything is
107
+ * sent; `PLATFORM_SETTINGS_NOT_ALLOWED` from the engine for a store administrator, both
108
+ * `PermissionDeniedError`, 403). No tenant is needed on the client.
109
+ */
110
+ export interface PlatformTaxRatesModule {
111
+ /**
112
+ * Create a tax rate, and answer it as `tax.rates.list()` reads it.
113
+ *
114
+ * - `INVALID_TAX_RATE_INPUT` (`ValidationError`, 400): a missing name, category, zone or
115
+ * `enabled`, or a value that is not a finite number, refused here before anything is sent.
116
+ * - `ENTITY_NOT_FOUND` (`NotFoundError`, 404): the category, zone or customer group does not
117
+ * exist.
118
+ *
119
+ * Tagged `money`: a rate decides the tax every store selling into its zone charges from the
120
+ * moment it exists.
121
+ *
122
+ * @effect money
123
+ */
124
+ create(input: CreateTaxRateInput, options?: Call): Promise<TaxRate>;
125
+ /**
126
+ * Change a tax rate, and answer it as read. Refused as {@link create} is, plus
127
+ * `INVALID_TAX_RATE_INPUT` for `customerGroupId: null` (see {@link UpdateTaxRateInput}) and
128
+ * `ENTITY_NOT_FOUND` for an unknown rate.
129
+ *
130
+ * @effect money
131
+ */
132
+ update(id: string, patch: UpdateTaxRateInput, options?: Call): Promise<TaxRate>;
133
+ /**
134
+ * Delete a tax rate, for every store.
135
+ *
136
+ * - `TAX_RATE_NOT_DELETED` (`ConflictError`, 409): the engine refused it, with its reason.
137
+ * - `ENTITY_NOT_FOUND` (`NotFoundError`, 404): no rate has that id.
138
+ *
139
+ * @effect destructive
140
+ */
141
+ delete(id: string, options?: Call): Promise<void>;
142
+ }
143
+ /** `admin.platform.tax`: SuperAdmin writes of the platform-wide tax tables (G128). */
144
+ export interface PlatformTaxModule {
145
+ categories: PlatformTaxCategoriesModule;
146
+ rates: PlatformTaxRatesModule;
147
+ }
148
+ export declare const CREATE_TAX_CATEGORY_MUTATION = "\n mutation PlatformCreateTaxCategory($input: CreateTaxCategoryInput!) {\n createTaxCategory(input: $input) { \n id\n name\n isDefault\n createdAt\n updatedAt\n }\n }\n";
149
+ export declare const UPDATE_TAX_CATEGORY_MUTATION = "\n mutation PlatformUpdateTaxCategory($input: UpdateTaxCategoryInput!) {\n updateTaxCategory(input: $input) { \n id\n name\n isDefault\n createdAt\n updatedAt\n }\n }\n";
150
+ export declare const DELETE_TAX_CATEGORY_MUTATION = "\n mutation PlatformDeleteTaxCategory($id: ID!) {\n deleteTaxCategory(id: $id) { \n result\n message\n }\n }\n";
151
+ export declare const CREATE_TAX_RATE_MUTATION = "\n mutation PlatformCreateTaxRate($input: CreateTaxRateInput!) {\n createTaxRate(input: $input) { \n id\n name\n value\n enabled\n category { id name }\n zone { id name }\n customerGroup { id name }\n createdAt\n updatedAt\n }\n }\n";
152
+ export declare const UPDATE_TAX_RATE_MUTATION = "\n mutation PlatformUpdateTaxRate($input: UpdateTaxRateInput!) {\n updateTaxRate(input: $input) { \n id\n name\n value\n enabled\n category { id name }\n zone { id name }\n customerGroup { id name }\n createdAt\n updatedAt\n }\n }\n";
153
+ export declare const DELETE_TAX_RATE_MUTATION = "\n mutation PlatformDeleteTaxRate($id: ID!) {\n deleteTaxRate(id: $id) { \n result\n message\n }\n }\n";
154
+ export declare function createPlatformTaxModule(transport: Transport, config: AdminClientConfig): PlatformTaxModule;
@@ -0,0 +1,139 @@
1
+ import { ValidationError } from '@sixtyninecommerce/core';
2
+ import { assertDeleted, DELETION_FIELDS, fieldOf, } from '../catalog/types.js';
3
+ import { TAX_CATEGORY_FIELDS, TAX_RATE_FIELDS, } from '../tax/index.js';
4
+ import { requireHumanSession } from './guard.js';
5
+ export const CREATE_TAX_CATEGORY_MUTATION = /* GraphQL */ `
6
+ mutation PlatformCreateTaxCategory($input: CreateTaxCategoryInput!) {
7
+ createTaxCategory(input: $input) { ${TAX_CATEGORY_FIELDS} }
8
+ }
9
+ `;
10
+ export const UPDATE_TAX_CATEGORY_MUTATION = /* GraphQL */ `
11
+ mutation PlatformUpdateTaxCategory($input: UpdateTaxCategoryInput!) {
12
+ updateTaxCategory(input: $input) { ${TAX_CATEGORY_FIELDS} }
13
+ }
14
+ `;
15
+ export const DELETE_TAX_CATEGORY_MUTATION = /* GraphQL */ `
16
+ mutation PlatformDeleteTaxCategory($id: ID!) {
17
+ deleteTaxCategory(id: $id) { ${DELETION_FIELDS} }
18
+ }
19
+ `;
20
+ export const CREATE_TAX_RATE_MUTATION = /* GraphQL */ `
21
+ mutation PlatformCreateTaxRate($input: CreateTaxRateInput!) {
22
+ createTaxRate(input: $input) { ${TAX_RATE_FIELDS} }
23
+ }
24
+ `;
25
+ export const UPDATE_TAX_RATE_MUTATION = /* GraphQL */ `
26
+ mutation PlatformUpdateTaxRate($input: UpdateTaxRateInput!) {
27
+ updateTaxRate(input: $input) { ${TAX_RATE_FIELDS} }
28
+ }
29
+ `;
30
+ export const DELETE_TAX_RATE_MUTATION = /* GraphQL */ `
31
+ mutation PlatformDeleteTaxRate($id: ID!) {
32
+ deleteTaxRate(id: $id) { ${DELETION_FIELDS} }
33
+ }
34
+ `;
35
+ const isObject = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
36
+ const refusal = (code) => (message) => new ValidationError({ code, message, status: 400, service: 'vendure' });
37
+ const categoryRefusal = refusal('INVALID_TAX_CATEGORY_INPUT');
38
+ const rateRefusal = refusal('INVALID_TAX_RATE_INPUT');
39
+ function requireId(id, what, refuse) {
40
+ if (typeof id !== 'string' || id.trim() === '')
41
+ throw refuse(`${what} must be an id.`);
42
+ return id;
43
+ }
44
+ function categoryInput(input, creating) {
45
+ if (!isObject(input))
46
+ throw categoryRefusal('A tax category input must be an object.');
47
+ const out = {};
48
+ if (input.name !== undefined || creating) {
49
+ if (typeof input.name !== 'string' || input.name.trim() === '') {
50
+ throw categoryRefusal('A tax category needs a name.');
51
+ }
52
+ out.name = input.name;
53
+ }
54
+ if (input.isDefault !== undefined) {
55
+ if (typeof input.isDefault !== 'boolean')
56
+ throw categoryRefusal('isDefault must be a boolean.');
57
+ out.isDefault = input.isDefault;
58
+ }
59
+ return out;
60
+ }
61
+ function rateInput(input, creating) {
62
+ if (!isObject(input))
63
+ throw rateRefusal('A tax rate input must be an object.');
64
+ const out = {};
65
+ if (input.name !== undefined || creating) {
66
+ if (typeof input.name !== 'string' || input.name.trim() === '') {
67
+ throw rateRefusal('A tax rate needs a name.');
68
+ }
69
+ out.name = input.name;
70
+ }
71
+ if (input.value !== undefined || creating) {
72
+ if (typeof input.value !== 'number' || !Number.isFinite(input.value)) {
73
+ throw rateRefusal('value must be a finite number: the percentage, 21 for 21 %.');
74
+ }
75
+ out.value = input.value;
76
+ }
77
+ if (input.enabled !== undefined || creating) {
78
+ if (typeof input.enabled !== 'boolean')
79
+ throw rateRefusal('enabled must be a boolean.');
80
+ out.enabled = input.enabled;
81
+ }
82
+ if (input.categoryId !== undefined || creating) {
83
+ out.categoryId = requireId(input.categoryId, 'categoryId', rateRefusal);
84
+ }
85
+ if (input.zoneId !== undefined || creating) {
86
+ out.zoneId = requireId(input.zoneId, 'zoneId', rateRefusal);
87
+ }
88
+ if (input.customerGroupId === null && !creating) {
89
+ // The engine reads a null group as "keep the stored one": a request that seems to widen a
90
+ // group-limited rate to every customer would answer success and change nothing.
91
+ throw rateRefusal('A tax rate cannot lose its customer group: create a rate without one and delete this one.');
92
+ }
93
+ if (input.customerGroupId !== undefined && input.customerGroupId !== null) {
94
+ out.customerGroupId = requireId(input.customerGroupId, 'customerGroupId', rateRefusal);
95
+ }
96
+ return out;
97
+ }
98
+ export function createPlatformTaxModule(transport, config) {
99
+ // Platform-wide rows: no store is involved, so no tenant is needed. Scoped to a store instead,
100
+ // the transport would first resolve it through the CMS channel mirror and fail on one missing
101
+ // there.
102
+ const unscoped = (call) => ({ ...call, allowUnscoped: true });
103
+ return {
104
+ categories: {
105
+ async create(input, options) {
106
+ requireHumanSession(config);
107
+ return fieldOf(transport, CREATE_TAX_CATEGORY_MUTATION, 'createTaxCategory', { input: categoryInput(input, true) }, unscoped(options));
108
+ },
109
+ async update(id, patch, options) {
110
+ requireHumanSession(config);
111
+ const categoryId = requireId(id, 'id', categoryRefusal);
112
+ return fieldOf(transport, UPDATE_TAX_CATEGORY_MUTATION, 'updateTaxCategory', { input: { ...categoryInput(patch, false), id: categoryId } }, unscoped(options));
113
+ },
114
+ async delete(id, options) {
115
+ requireHumanSession(config);
116
+ assertDeleted('TAX_CATEGORY_NOT_DELETED', [
117
+ await fieldOf(transport, DELETE_TAX_CATEGORY_MUTATION, 'deleteTaxCategory', { id: requireId(id, 'id', categoryRefusal) }, unscoped(options)),
118
+ ]);
119
+ },
120
+ },
121
+ rates: {
122
+ async create(input, options) {
123
+ requireHumanSession(config);
124
+ return fieldOf(transport, CREATE_TAX_RATE_MUTATION, 'createTaxRate', { input: rateInput(input, true) }, unscoped(options));
125
+ },
126
+ async update(id, patch, options) {
127
+ requireHumanSession(config);
128
+ const rateId = requireId(id, 'id', rateRefusal);
129
+ return fieldOf(transport, UPDATE_TAX_RATE_MUTATION, 'updateTaxRate', { input: { ...rateInput(patch, false), id: rateId } }, unscoped(options));
130
+ },
131
+ async delete(id, options) {
132
+ requireHumanSession(config);
133
+ assertDeleted('TAX_RATE_NOT_DELETED', [
134
+ await fieldOf(transport, DELETE_TAX_RATE_MUTATION, 'deleteTaxRate', { id: requireId(id, 'id', rateRefusal) }, unscoped(options)),
135
+ ]);
136
+ },
137
+ },
138
+ };
139
+ }
@@ -0,0 +1,158 @@
1
+ import { type Page, type Transport } from '@sixtyninecommerce/core';
2
+ import type { Call, ListOptions } from '../types.js';
3
+ /**
4
+ * A store's anomaly flags (engine row 43): rules run over each location's ENDED business day flag
5
+ * unusual refunds, voids, returns without a receipt, outlying or unlogged discounts, cash
6
+ * variances, uncounted closes, money landed after a Z, a closed drawer whose cash changed, sales
7
+ * credited to another cashier and many no-sale opens. A flag never acts against anyone: a person
8
+ * reviews it and acknowledges it with a note.
9
+ *
10
+ * OFF until the store turns it on (`setRules({ enabled: true })`): flags name staff, and in the
11
+ * Netherlands and Germany a system that monitors staff needs the works council's consent first.
12
+ * Every read and write needs `UpdateSettings` or `ManagePosDevices` (`setRules`: `UpdateSettings`);
13
+ * a location-restricted caller sees its locations' flags only. Each method is its own document: an
14
+ * engine before 43 refuses it at validation, nothing else.
15
+ */
16
+ export interface PosAnomalyThresholds {
17
+ minCount: number | null;
18
+ minSales: number | null;
19
+ multiplier: number | null;
20
+ floorPercent: number | null;
21
+ fallbackPercent: number | null;
22
+ percentile: number | null;
23
+ /** Minor units of the drawer currency; null = that test off. */
24
+ amount: number | null;
25
+ }
26
+ export interface PosAnomalyRule {
27
+ code: string;
28
+ enabled: boolean;
29
+ /** False: the store lacks the rule's source (it is skipped). */
30
+ available: boolean;
31
+ /** `info`, `warning` or `high`; more may come. */
32
+ severity: string;
33
+ /** `staff`, `drawer` or `store_day`; more may come. */
34
+ subject: string;
35
+ /** The thresholds this rule takes. */
36
+ parameters: string[];
37
+ thresholds: PosAnomalyThresholds;
38
+ defaults: PosAnomalyThresholds;
39
+ }
40
+ export interface PosAnomalyRules {
41
+ enabled: boolean;
42
+ rulesVersion: number;
43
+ rules: PosAnomalyRule[];
44
+ }
45
+ export interface PosAnomalyRuleInput extends Partial<PosAnomalyThresholds> {
46
+ code: string;
47
+ enabled: boolean;
48
+ }
49
+ export interface PosAnomalyRulesInput {
50
+ enabled: boolean;
51
+ /** Rules not listed keep their stored settings; a listed one is replaced whole. */
52
+ rules?: PosAnomalyRuleInput[];
53
+ }
54
+ /** A figure: `count`, `percent`, `basis_points` or `minor` (more may come). */
55
+ export interface PosAnomalyFigure {
56
+ key: string;
57
+ value: number;
58
+ unit: string;
59
+ }
60
+ export interface PosAnomalyFlag {
61
+ id: string;
62
+ stockLocationId: string;
63
+ locationName: string | null;
64
+ businessDay: string;
65
+ rule: string;
66
+ severity: string;
67
+ subjectKind: string;
68
+ staffId: string | null;
69
+ staffName: string | null;
70
+ sessionId: string | null;
71
+ registerId: string | null;
72
+ registerName: string | null;
73
+ zNumber: number | null;
74
+ /** `open` or `acknowledged`; more may come. */
75
+ status: string;
76
+ measure: PosAnomalyFigure[];
77
+ thresholds: PosAnomalyFigure[];
78
+ evidence: {
79
+ orders: Array<{
80
+ orderId: string;
81
+ code: string;
82
+ receiptNumber: string | null;
83
+ amount: number | null;
84
+ }>;
85
+ sessionIds: string[];
86
+ truncated: boolean;
87
+ };
88
+ detectedAt: string;
89
+ lastEvaluatedAt: string;
90
+ acknowledgedAt: string | null;
91
+ acknowledgedByName: string | null;
92
+ note: string | null;
93
+ }
94
+ export interface PosAnomalyFlagListOptions extends ListOptions {
95
+ /** `open` (default), `acknowledged` or `all`. */
96
+ status?: string;
97
+ fromDay?: string;
98
+ toDay?: string;
99
+ stockLocationId?: string;
100
+ rule?: string;
101
+ severity?: string;
102
+ staffId?: string;
103
+ }
104
+ export interface PosAnomalyOverview {
105
+ enabled: boolean;
106
+ open: number;
107
+ openHigh: number;
108
+ openWarning: number;
109
+ openInfo: number;
110
+ oldestOpenDay: string | null;
111
+ }
112
+ export interface PosAnomalyScanResult {
113
+ stockLocationId: string;
114
+ businessDay: string;
115
+ newFlagCount: number;
116
+ openFlagCount: number;
117
+ skippedRules: string[];
118
+ }
119
+ export interface PosAnomaliesModule {
120
+ rules(options?: Call): Promise<PosAnomalyRules>;
121
+ /**
122
+ * Refused `POS_ANOMALY_RULES_INVALID`: `details[0].field` is a JSON Pointer into the input
123
+ * (`/rules/<index>/<threshold>`, `/enabled`), `details[0].code` the reason.
124
+ */
125
+ setRules(input: PosAnomalyRulesInput, options?: Call): Promise<PosAnomalyRules>;
126
+ /** Newest business day first, then severity; `limit` 1-100 (25), `after` an offset cursor. */
127
+ list(options?: PosAnomalyFlagListOptions): Promise<Page<PosAnomalyFlag>>;
128
+ /** One flag, or null (another store's, or another location's for a restricted caller). */
129
+ get(id: string, options?: Call): Promise<PosAnomalyFlag | null>;
130
+ overview(options?: Call): Promise<PosAnomalyOverview>;
131
+ /** Refused `POS_ANOMALY_FLAG_NOT_FOUND`, `POS_ANOMALY_FLAG_NOT_OPEN`, `POS_ANOMALY_NOTE_INVALID`. */
132
+ acknowledge(input: {
133
+ flagId: string;
134
+ note: string;
135
+ }, options?: Call): Promise<PosAnomalyFlag>;
136
+ /**
137
+ * Evaluate one ENDED business day of a location now (a rerun adds nothing). Refused
138
+ * `POS_ANOMALY_FLAGS_OFF`, `POS_ANOMALY_DAY_NOT_ENDED`, `POS_LIST_RANGE_INVALID`,
139
+ * `POS_ANOMALY_SCAN_BUSY`, `POS_LOCATION_NOT_FOUND`, `LOCATION_NOT_ALLOWED`.
140
+ */
141
+ scanDay(input: {
142
+ stockLocationId: string;
143
+ businessDay: string;
144
+ }, options?: Call): Promise<PosAnomalyScanResult>;
145
+ }
146
+ export declare const POS_ANOMALY_FLAG_FIELDS = "id stockLocationId locationName businessDay rule severity subjectKind staffId staffName sessionId registerId registerName zNumber status measure { key value unit } thresholds { key value unit } evidence { orders { orderId code receiptNumber amount } sessionIds truncated } detectedAt lastEvaluatedAt acknowledgedAt acknowledgedByName note";
147
+ export declare const POS_ANOMALY_RULES_QUERY = "query PosAnomalyRules { posAnomalyRules { enabled rulesVersion rules { code enabled available severity subject parameters thresholds { minCount minSales multiplier floorPercent fallbackPercent percentile amount } defaults { minCount minSales multiplier floorPercent fallbackPercent percentile amount } } } }";
148
+ export declare const SET_POS_ANOMALY_RULES_MUTATION = "mutation SetPosAnomalyRules($input: PosAnomalyRulesInput!) { setPosAnomalyRules(input: $input) { enabled rulesVersion rules { code enabled available severity subject parameters thresholds { minCount minSales multiplier floorPercent fallbackPercent percentile amount } defaults { minCount minSales multiplier floorPercent fallbackPercent percentile amount } } } }";
149
+ export declare const POS_ANOMALY_FLAGS_QUERY = "query PosAnomalyFlags($input: PosAnomalyFlagListInput) { posAnomalyFlags(input: $input) { items { id stockLocationId locationName businessDay rule severity subjectKind staffId staffName sessionId registerId registerName zNumber status measure { key value unit } thresholds { key value unit } evidence { orders { orderId code receiptNumber amount } sessionIds truncated } detectedAt lastEvaluatedAt acknowledgedAt acknowledgedByName note } totalItems } }";
150
+ export declare const POS_ANOMALY_FLAG_QUERY = "query PosAnomalyFlag($id: ID!) { posAnomalyFlag(id: $id) { id stockLocationId locationName businessDay rule severity subjectKind staffId staffName sessionId registerId registerName zNumber status measure { key value unit } thresholds { key value unit } evidence { orders { orderId code receiptNumber amount } sessionIds truncated } detectedAt lastEvaluatedAt acknowledgedAt acknowledgedByName note } }";
151
+ export declare const POS_ANOMALY_OVERVIEW_QUERY = "query PosAnomalyOverview { posAnomalyOverview { enabled open openHigh openWarning openInfo oldestOpenDay } }";
152
+ export declare const ACKNOWLEDGE_POS_ANOMALY_FLAG_MUTATION = "mutation AcknowledgePosAnomalyFlag($input: AcknowledgePosAnomalyFlagInput!) { acknowledgePosAnomalyFlag(input: $input) { id stockLocationId locationName businessDay rule severity subjectKind staffId staffName sessionId registerId registerName zNumber status measure { key value unit } thresholds { key value unit } evidence { orders { orderId code receiptNumber amount } sessionIds truncated } detectedAt lastEvaluatedAt acknowledgedAt acknowledgedByName note } }";
153
+ export declare const RUN_POS_ANOMALY_SCAN_MUTATION = "mutation RunPosAnomalyScan($input: RunPosAnomalyScanInput!) { runPosAnomalyScan(input: $input) { stockLocationId businessDay newFlagCount openFlagCount skippedRules } }";
154
+ /** A flag page: at most this many. */
155
+ export declare const POS_ANOMALY_FLAGS_MAX_PAGE = 100;
156
+ /** ... and this many when `limit` is omitted. */
157
+ export declare const POS_ANOMALY_FLAGS_DEFAULT_PAGE = 25;
158
+ export declare function createPosAnomaliesModule(transport: Transport): PosAnomaliesModule;
@@ -0,0 +1,64 @@
1
+ import { pageFromVendureList, readOffsetCursor, } from '@sixtyninecommerce/core';
2
+ const THRESHOLDS = 'minCount minSales multiplier floorPercent fallbackPercent percentile amount';
3
+ const RULES = `enabled rulesVersion rules { code enabled available severity subject parameters thresholds { ${THRESHOLDS} } defaults { ${THRESHOLDS} } }`;
4
+ const FIGURE = 'key value unit';
5
+ export const POS_ANOMALY_FLAG_FIELDS = `id stockLocationId locationName businessDay rule severity subjectKind staffId staffName sessionId registerId registerName zNumber status measure { ${FIGURE} } thresholds { ${FIGURE} } evidence { orders { orderId code receiptNumber amount } sessionIds truncated } detectedAt lastEvaluatedAt acknowledgedAt acknowledgedByName note`;
6
+ export const POS_ANOMALY_RULES_QUERY = `query PosAnomalyRules { posAnomalyRules { ${RULES} } }`;
7
+ export const SET_POS_ANOMALY_RULES_MUTATION = `mutation SetPosAnomalyRules($input: PosAnomalyRulesInput!) { setPosAnomalyRules(input: $input) { ${RULES} } }`;
8
+ export const POS_ANOMALY_FLAGS_QUERY = `query PosAnomalyFlags($input: PosAnomalyFlagListInput) { posAnomalyFlags(input: $input) { items { ${POS_ANOMALY_FLAG_FIELDS} } totalItems } }`;
9
+ export const POS_ANOMALY_FLAG_QUERY = `query PosAnomalyFlag($id: ID!) { posAnomalyFlag(id: $id) { ${POS_ANOMALY_FLAG_FIELDS} } }`;
10
+ export const POS_ANOMALY_OVERVIEW_QUERY = 'query PosAnomalyOverview { posAnomalyOverview { enabled open openHigh openWarning openInfo oldestOpenDay } }';
11
+ export const ACKNOWLEDGE_POS_ANOMALY_FLAG_MUTATION = `mutation AcknowledgePosAnomalyFlag($input: AcknowledgePosAnomalyFlagInput!) { acknowledgePosAnomalyFlag(input: $input) { ${POS_ANOMALY_FLAG_FIELDS} } }`;
12
+ export const RUN_POS_ANOMALY_SCAN_MUTATION = 'mutation RunPosAnomalyScan($input: RunPosAnomalyScanInput!) { runPosAnomalyScan(input: $input) { stockLocationId businessDay newFlagCount openFlagCount skippedRules } }';
13
+ /** A flag page: at most this many. */
14
+ export const POS_ANOMALY_FLAGS_MAX_PAGE = 100;
15
+ /** ... and this many when `limit` is omitted. */
16
+ export const POS_ANOMALY_FLAGS_DEFAULT_PAGE = 25;
17
+ const FILTERS = [
18
+ 'status',
19
+ 'fromDay',
20
+ 'toDay',
21
+ 'stockLocationId',
22
+ 'rule',
23
+ 'severity',
24
+ 'staffId',
25
+ ];
26
+ export function createPosAnomaliesModule(transport) {
27
+ const gql = (query, variables, options) => transport.graphql({ api: 'admin', query, variables }, options);
28
+ const page = async (skip, take, options) => {
29
+ const input = { skip, take };
30
+ for (const key of FILTERS) {
31
+ const value = options?.[key];
32
+ if (value !== undefined && value !== '')
33
+ input[key] = value;
34
+ }
35
+ const data = await gql(POS_ANOMALY_FLAGS_QUERY, { input }, options);
36
+ return pageFromVendureList(data.posAnomalyFlags, skip, take, (cursor) => page(readOffsetCursor(cursor), take, options));
37
+ };
38
+ return {
39
+ async rules(options) {
40
+ return (await gql(POS_ANOMALY_RULES_QUERY, {}, options))
41
+ .posAnomalyRules;
42
+ },
43
+ async setRules(input, options) {
44
+ return (await gql(SET_POS_ANOMALY_RULES_MUTATION, { input }, options)).setPosAnomalyRules;
45
+ },
46
+ async list(options) {
47
+ const take = Math.min(Math.max(Math.trunc(options?.limit ?? POS_ANOMALY_FLAGS_DEFAULT_PAGE), 1), POS_ANOMALY_FLAGS_MAX_PAGE);
48
+ const skip = options?.after === undefined ? 0 : readOffsetCursor(options.after);
49
+ return page(skip, take, options);
50
+ },
51
+ async get(id, options) {
52
+ return (await gql(POS_ANOMALY_FLAG_QUERY, { id }, options)).posAnomalyFlag;
53
+ },
54
+ async overview(options) {
55
+ return (await gql(POS_ANOMALY_OVERVIEW_QUERY, {}, options)).posAnomalyOverview;
56
+ },
57
+ async acknowledge(input, options) {
58
+ return (await gql(ACKNOWLEDGE_POS_ANOMALY_FLAG_MUTATION, { input }, options)).acknowledgePosAnomalyFlag;
59
+ },
60
+ async scanDay(input, options) {
61
+ return (await gql(RUN_POS_ANOMALY_SCAN_MUTATION, { input }, options)).runPosAnomalyScan;
62
+ },
63
+ };
64
+ }
@@ -0,0 +1,79 @@
1
+ import type { Transport } from '@sixtyninecommerce/core';
2
+ import type { Call } from '../types.js';
3
+ /**
4
+ * A store's assisted selling at the till (engine sprint C4/44): upsell prompts under the till's
5
+ * cart, from the store's recommendation groups, and assisted search ("Ask": the cashier's words
6
+ * planned by the platform's AI, then searched in the catalogue). Upsell is on unless the store
7
+ * turns it off; assisted search is OFF unless the platform has enabled it AND the store turns it
8
+ * on.
9
+ */
10
+ /** The most upsell suggestions a store may choose, and the most groups it may name. */
11
+ export declare const POS_ASSISTED_SELLING_LIMITS: {
12
+ readonly upsellMaxItems: 8;
13
+ readonly upsellGroups: 10;
14
+ readonly assistedSearchDailyLimit: 5000;
15
+ readonly usageDays: 31;
16
+ };
17
+ export interface PosAssistedSelling {
18
+ /** Upsell prompts under the till's cart. */
19
+ upsellEnabled: boolean;
20
+ /** At most this many suggestions (1-8; 4 by default). */
21
+ upsellMaxItems: number;
22
+ /** Recommendation group slugs that feed the till, in order; empty = every enabled group. */
23
+ upsellGroupSlugs: string[];
24
+ /** AI-planned search at the till; always false while `assistedSearchAvailable` is false. */
25
+ assistedSearchEnabled: boolean;
26
+ /** The platform has enabled AI search; until then the store cannot turn it on. */
27
+ assistedSearchAvailable: boolean;
28
+ /** AI plans per day in the store's time zone (1-5,000; 300 by default). */
29
+ assistedSearchDailyLimit: number;
30
+ }
31
+ export interface PosAssistedSellingInput {
32
+ upsellEnabled: boolean;
33
+ /** Omitted keeps the stored value. */
34
+ upsellMaxItems?: number;
35
+ /** Replaces the list; omitted keeps it. */
36
+ upsellGroupSlugs?: string[];
37
+ assistedSearchEnabled: boolean;
38
+ /** Omitted keeps the stored value. */
39
+ assistedSearchDailyLimit?: number;
40
+ }
41
+ /** Why a search ran plain, counted per day. More reasons may come. */
42
+ export interface PosAssistedSearchFallbackCount {
43
+ reason: string;
44
+ count: number;
45
+ }
46
+ /** One day of a store's assisted search; the words are never kept. */
47
+ export interface PosAssistedSearchUsageDay {
48
+ /** YYYY-MM-DD in the store's time zone. */
49
+ day: string;
50
+ searches: number;
51
+ /** AI plans asked for (each counts against the daily limit). */
52
+ planned: number;
53
+ fallbacks: PosAssistedSearchFallbackCount[];
54
+ inputTokens: number;
55
+ outputTokens: number;
56
+ }
57
+ /** `get` needs any staff session of the store; `set` needs `UpdateSettings`; `usage` needs `UpdateSettings` or `ManagePosDevices`. */
58
+ export interface PosAssistedSellingModule {
59
+ /** The store's assisted selling, defaults applied. */
60
+ get(options?: Call): Promise<PosAssistedSelling>;
61
+ /**
62
+ * Set it. Refusals: `POS_ASSISTED_SELLING_INVALID` (`ValidationError`; `field` and `reason`:
63
+ * `upsellMaxItems` outside 1-8, `assistedSearchDailyLimit` outside 1-5,000, more than 10
64
+ * groups, a repeated or blank slug, or a newly picked slug that is not an enabled group of the
65
+ * store), `POS_ASSISTED_SEARCH_UNAVAILABLE` (turning assisted search on while the platform has
66
+ * it off), `ORGANIZATION_WORKSPACE_NOT_A_STORE`. An unchanged setting writes nothing.
67
+ */
68
+ set(input: PosAssistedSellingInput, options?: Call): Promise<PosAssistedSelling>;
69
+ /**
70
+ * The last `days` (1-31, 30 when omitted) of the store's assisted search, newest first; a day
71
+ * nobody searched has no entry. Refused `POS_ASSISTED_SELLING_INVALID` (`field: 'days'`) out of
72
+ * range; the SDK refuses a `days` that is not a whole number before sending.
73
+ */
74
+ usage(days?: number, options?: Call): Promise<PosAssistedSearchUsageDay[]>;
75
+ }
76
+ export declare const POS_ASSISTED_SELLING_QUERY = "query PosAssistedSelling { posAssistedSelling { upsellEnabled upsellMaxItems upsellGroupSlugs assistedSearchEnabled assistedSearchAvailable assistedSearchDailyLimit } }";
77
+ export declare const SET_POS_ASSISTED_SELLING_MUTATION = "mutation SetPosAssistedSelling($input: PosAssistedSellingInput!) { setPosAssistedSelling(input: $input) { upsellEnabled upsellMaxItems upsellGroupSlugs assistedSearchEnabled assistedSearchAvailable assistedSearchDailyLimit } }";
78
+ export declare const POS_ASSISTED_SEARCH_USAGE_QUERY = "query PosAssistedSearchUsage($days: Int) { posAssistedSearchUsage(days: $days) { day searches planned fallbacks { reason count } inputTokens outputTokens } }";
79
+ export declare function createPosAssistedSellingModule(transport: Transport): PosAssistedSellingModule;
@@ -0,0 +1,38 @@
1
+ /**
2
+ * A store's assisted selling at the till (engine sprint C4/44): upsell prompts under the till's
3
+ * cart, from the store's recommendation groups, and assisted search ("Ask": the cashier's words
4
+ * planned by the platform's AI, then searched in the catalogue). Upsell is on unless the store
5
+ * turns it off; assisted search is OFF unless the platform has enabled it AND the store turns it
6
+ * on.
7
+ */
8
+ /** The most upsell suggestions a store may choose, and the most groups it may name. */
9
+ export const POS_ASSISTED_SELLING_LIMITS = {
10
+ upsellMaxItems: 8,
11
+ upsellGroups: 10,
12
+ assistedSearchDailyLimit: 5000,
13
+ usageDays: 31,
14
+ };
15
+ const SELLING_FIELDS = 'upsellEnabled upsellMaxItems upsellGroupSlugs assistedSearchEnabled assistedSearchAvailable assistedSearchDailyLimit';
16
+ export const POS_ASSISTED_SELLING_QUERY = `query PosAssistedSelling { posAssistedSelling { ${SELLING_FIELDS} } }`;
17
+ export const SET_POS_ASSISTED_SELLING_MUTATION = `mutation SetPosAssistedSelling($input: PosAssistedSellingInput!) { setPosAssistedSelling(input: $input) { ${SELLING_FIELDS} } }`;
18
+ export const POS_ASSISTED_SEARCH_USAGE_QUERY = 'query PosAssistedSearchUsage($days: Int) { posAssistedSearchUsage(days: $days) { day searches planned fallbacks { reason count } inputTokens outputTokens } }';
19
+ export function createPosAssistedSellingModule(transport) {
20
+ const gql = async (query, variables, options) => transport.graphql({ api: 'admin', query, variables }, options);
21
+ return {
22
+ async get(options) {
23
+ const data = await gql(POS_ASSISTED_SELLING_QUERY, {}, options);
24
+ return data.posAssistedSelling;
25
+ },
26
+ async set(input, options) {
27
+ const data = await gql(SET_POS_ASSISTED_SELLING_MUTATION, { input }, options);
28
+ return data.setPosAssistedSelling;
29
+ },
30
+ async usage(days, options) {
31
+ if (days !== undefined && !Number.isInteger(days)) {
32
+ throw new TypeError('assistedSelling.usage(days): days is a whole number from 1 to 31.');
33
+ }
34
+ const data = await gql(POS_ASSISTED_SEARCH_USAGE_QUERY, days === undefined ? {} : { days }, options);
35
+ return data.posAssistedSearchUsage;
36
+ },
37
+ };
38
+ }