@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
@@ -1,6 +1,8 @@
1
1
  import { type Page, type Transport } from '@sixtyninecommerce/core';
2
- import type { ConfigurableOperation, ConfigurableOperationInput, LanguageCode } from '../catalog/types.js';
3
- import type { Call } from '../types.js';
2
+ import { type ConfigurableOperation, type ConfigurableOperationInput, type LanguageCode } from '../catalog/types.js';
3
+ import type { Call, ConfigurableOperationDefinition, ListOptions } from '../types.js';
4
+ import { type PricingBulkCouponsModule } from './bulk-coupons.js';
5
+ import { type PricingPriceListsModule } from './price-lists.js';
4
6
  import { type PricingVouchersModule } from './vouchers.js';
5
7
  /**
6
8
  * Promotions at the register (headless spec §9.2 `pricing`; incentives spec §5,
@@ -36,6 +38,11 @@ export interface PricingModule {
36
38
  coupons: PricingCouponsModule;
37
39
  /** Personal vouchers: templates, issuing, a customer's vouchers (`./vouchers.ts`). */
38
40
  vouchers: PricingVouchersModule;
41
+ /**
42
+ * The store's B2B price lists: the lists, their entries, assignments and order rules, and
43
+ * bulk enable/disable/delete (`./price-lists.ts`).
44
+ */
45
+ priceLists: PricingPriceListsModule;
39
46
  /**
40
47
  * The order's discounts as they stand: its coupon codes, the order-level
41
48
  * discounts, and each line's discounts, every one naming the promotion it came
@@ -45,6 +52,80 @@ export interface PricingModule {
45
52
  discounts(orderId: string, options?: Call): Promise<OrderDiscounts>;
46
53
  }
47
54
  export interface PricingPromotionsModule {
55
+ /**
56
+ * One page of the store's promotions (`limit` 1 to 1,000, default 25), every state and date
57
+ * window: what a back office lists, unlike {@link active}. Walk them all with `for await`:
58
+ * every following page re-sends the same filters, sort and store.
59
+ *
60
+ * - `term` (trimmed; a blank one is ignored) matches a case-insensitive part of the name, in
61
+ * ANY of its languages, or of the coupon code. A row found through another language's name
62
+ * answers that language's `name`. EXCEPT while sorted by `name`: the engine then reads the
63
+ * name in the request's language only (the store's default language where a promotion has
64
+ * none in it), so a term matches no other language; sort by another key to search them all.
65
+ * - `enabled` keeps only the enabled (or disabled) ones; their date window is not judged.
66
+ * - `sort`: one key; the engine's own order when omitted.
67
+ *
68
+ * The store's auto-managed order-rule promotion is never listed (see {@link active}).
69
+ *
70
+ * Refused before sending: `INVALID_PAGE_SIZE` (`ValidationError`, 400) for a `limit` outside
71
+ * 1 to 1,000; `INVALID_PROMOTION_SORT` (`ValidationError`, 400) for a sort field or direction
72
+ * this method does not name; `INVALID_PROMOTION_FILTER` (`ValidationError`, 400) for a `term`
73
+ * that is not a string or an `enabled` that is not a boolean.
74
+ *
75
+ * @effect read
76
+ * @permission ReadPromotion
77
+ */
78
+ list(options?: PromotionListOptions): Promise<Page<PromotionListItem>>;
79
+ /**
80
+ * One promotion of this store with its translations, conditions and actions as stored (the
81
+ * stacking guard included), or `null` when the store has none by that id (another store's
82
+ * answers the same).
83
+ *
84
+ * The store's auto-managed order-rule promotion (the id an "Order discount" on an order names)
85
+ * is answered with `customFields.managedBy` set: it is read-only, every change and the delete
86
+ * are refused `MANAGED_PROMOTION_NOT_ALLOWED`; its rules are set on the price lists
87
+ * (`priceLists.orderRules`). A merchant's promotion answers `managedBy: null`.
88
+ *
89
+ * @effect read
90
+ * @permission ReadPromotion
91
+ */
92
+ get(id: string, options?: Call): Promise<PromotionDetail | null>;
93
+ /**
94
+ * Delete a promotion of this store. It stops applying: an order priced after the delete no
95
+ * longer gets its discount, and its coupon code (and every bulk code generated for it) is no
96
+ * longer accepted.
97
+ *
98
+ * Refusals: `ENTITY_NOT_FOUND` (`NotFoundError`, 404) for an id this store does not hold (one
99
+ * answer for another store's and an unknown one), `SHARED_PROMOTION_NOT_ALLOWED` (403) for a
100
+ * promotion other stores hold too, `MANAGED_PROMOTION_NOT_ALLOWED` (`PermissionDeniedError`,
101
+ * 403) for the store's auto-managed order-rule promotion, and `PROMOTION_NOT_DELETED`
102
+ * (`ConflictError`, 409) should the engine answer that it kept it.
103
+ *
104
+ * @effect destructive
105
+ * @permission DeletePromotion
106
+ */
107
+ delete(id: string, options?: Call): Promise<void>;
108
+ /**
109
+ * The conditions a promotion of this store can carry, each with its arguments, in the
110
+ * language of the request. Two the engine registers are left out because a caller never sets
111
+ * them: the stacking guard (`promotion_stacking_guard`, which {@link create} and
112
+ * {@link update} add themselves) and the price-list order-rule condition
113
+ * (`price_list_order_rules`, refused on every promotion but the store's auto-managed one).
114
+ *
115
+ * `args[].required` is NOT the enforced rule (see `ConfigArgDefinition.required`).
116
+ *
117
+ * @effect read
118
+ * @permission ReadPromotion
119
+ */
120
+ conditionDefinitions(options?: Call): Promise<ConfigurableOperationDefinition[]>;
121
+ /**
122
+ * The actions a promotion of this store can carry, as {@link conditionDefinitions} answers the
123
+ * conditions: the price-list order-rule action (`price_list_order_rules`) is left out.
124
+ *
125
+ * @effect read
126
+ * @permission ReadPromotion
127
+ */
128
+ actionDefinitions(options?: Call): Promise<ConfigurableOperationDefinition[]>;
48
129
  /**
49
130
  * The store's promotions that can apply right now: enabled, inside their date
50
131
  * window, not used up, and — with `customerId` — open to that customer (a
@@ -61,9 +142,17 @@ export interface PricingPromotionsModule {
61
142
  * location of this store that the credential may act at
62
143
  * (`LOCATION_NOT_IN_CHANNEL` / `LOCATION_NOT_ALLOWED`).
63
144
  *
145
+ * The store's auto-managed order-rule promotion is never listed: it applies
146
+ * the order rules of the store's price lists (`priceLists.orderRules`), is no
147
+ * offer, and is managed by the platform. Its discount still shows on an order
148
+ * ("Order discount", {@link PricingOrdersModule.discounts}), naming that
149
+ * promotion's id.
150
+ *
64
151
  * Needs `ReadPromotion`, `CreateOrder` or `OperatePos`. A `Page` because every
65
152
  * list in this SDK is one; the engine answers the whole list, so it is always
66
153
  * the last page.
154
+ *
155
+ * @effect read
67
156
  */
68
157
  active(filter?: ActivePromotionsFilter, options?: Call): Promise<Page<ActivePromotion>>;
69
158
  /**
@@ -85,12 +174,18 @@ export interface PricingPromotionsModule {
85
174
  * targeting or set argument the engine cannot read, a second set condition or
86
175
  * a set action without its condition (`argument: "conditions"`), or a set
87
176
  * condition without its action or a second copy of a set action
88
- * (`argument: "actions"`), judged on `update` for the pair the update leaves; `extensions.details` names the condition and
177
+ * (`argument: "actions"`), judged on `update` for the pair the update leaves,
178
+ * or the price-list order-rule pair `price_list_order_rules`, which only the
179
+ * store's own auto-managed promotion carries (`argument: "conditions"` or
180
+ * `"actions"`: order rules are set on a price list); `extensions.details` names the condition and
89
181
  * argument), `LOCATION_NOT_IN_CHANNEL` (a location of another store, or not
90
182
  * an id), `LOCATION_NOT_ALLOWED` (outside the credential's location
91
183
  * restriction), `FACET_VALUE_NOT_FOUND` / `COLLECTION_NOT_FOUND`
92
184
  * (`NotFoundError`, 404: a set component names a facet value or collection
93
185
  * this store does not have; another store's answers the same).
186
+ *
187
+ * @effect write
188
+ * @permission CreatePromotion
94
189
  */
95
190
  create(input: CreatePromotionInput, options?: Call): Promise<PricingPromotion>;
96
191
  /**
@@ -98,7 +193,10 @@ export interface PricingPromotionsModule {
98
193
  * replace the whole list (the guard is kept as on create). Needs
99
194
  * `UpdatePromotion`.
100
195
  *
101
- * Refusals: those of {@link PricingPromotionsModule.create}, and
196
+ * Refusals: those of {@link PricingPromotionsModule.create},
197
+ * `MANAGED_PROMOTION_NOT_ALLOWED` (`PermissionDeniedError`, 403) for the
198
+ * store's auto-managed order-rule promotion (the id an "Order discount" on an
199
+ * order names; change the price list's order rules instead), and
102
200
  * `MISSING_CONDITIONS_ERROR` (`BusinessRuleError`, 422) for one case: the input
103
201
  * does not name `conditions`, the STORED promotion has none (an imported
104
202
  * coupon, a seed: no guard was ever added), and the result would have no coupon
@@ -106,6 +204,9 @@ export interface PricingPromotionsModule {
106
204
  * conditions from the stored ones, and the guard is added only to conditions
107
205
  * the input sends: send `conditions` (even `[]`) to keep such a promotion
108
206
  * without a code.
207
+ *
208
+ * @effect write
209
+ * @permission UpdatePromotion
109
210
  */
110
211
  update(input: UpdatePromotionInput, options?: Call): Promise<PricingPromotion>;
111
212
  }
@@ -255,7 +356,71 @@ export interface PricingPromotion {
255
356
  priority: number | null;
256
357
  };
257
358
  }
359
+ /** What {@link PricingPromotionsModule.list} can sort by. */
360
+ export type PromotionSortField = 'name' | 'couponCode' | 'startsAt' | 'endsAt' | 'createdAt' | 'updatedAt';
361
+ export declare const PROMOTION_SORT_FIELDS: readonly PromotionSortField[];
362
+ export interface PromotionListOptions extends ListOptions {
363
+ /**
364
+ * A part of the name (any language, unless sorted by `name`: see `list`) or of the coupon code,
365
+ * capitals ignored; trimmed.
366
+ */
367
+ term?: string;
368
+ /** Only the enabled (`true`) or the disabled (`false`) ones. */
369
+ enabled?: boolean;
370
+ /** ONE sort key; the engine's own order when omitted. */
371
+ sort?: {
372
+ field: PromotionSortField;
373
+ direction: 'ASC' | 'DESC';
374
+ };
375
+ }
376
+ /** A promotion as {@link PricingPromotionsModule.list} answers it. */
377
+ export interface PromotionListItem {
378
+ id: string;
379
+ /** In the request's language, or the language whose name a `term` matched. */
380
+ name: string;
381
+ description: string;
382
+ couponCode: string | null;
383
+ enabled: boolean;
384
+ /** ISO-8601 instants; null for an open start or end. */
385
+ startsAt: string | null;
386
+ endsAt: string | null;
387
+ usageLimit: number | null;
388
+ perCustomerUsageLimit: number | null;
389
+ createdAt: string;
390
+ updatedAt: string;
391
+ customFields: {
392
+ combineWithB2b: boolean | null;
393
+ combineWithOtherPromotions: boolean | null;
394
+ priority: number | null;
395
+ };
396
+ }
397
+ /** A promotion as {@link PricingPromotionsModule.get} answers it. */
398
+ export interface PromotionDetail extends Omit<PromotionListItem, 'customFields'> {
399
+ translations: Array<{
400
+ id: string;
401
+ languageCode: LanguageCode;
402
+ name: string;
403
+ description: string;
404
+ }>;
405
+ /** As stored, the stacking guard (`promotion_stacking_guard`) included. */
406
+ conditions: ConfigurableOperation[];
407
+ actions: ConfigurableOperation[];
408
+ customFields: PromotionListItem['customFields'] & {
409
+ /**
410
+ * Set only on the store's auto-managed order-rule promotion (`price-list-order-rules`): a
411
+ * platform service owns it, and every change and the delete are refused. `null` for a
412
+ * merchant's promotion.
413
+ */
414
+ managedBy: string | null;
415
+ };
416
+ }
258
417
  export interface PricingCouponsModule {
418
+ /**
419
+ * Unique codes generated in bulk for a promotion with a coupon code (`./bulk-coupons.ts`):
420
+ * the groups, their codes, generating, switching a code or a group off, deleting a group, and
421
+ * a group's codes as CSV.
422
+ */
423
+ bulk: PricingBulkCouponsModule;
259
424
  /**
260
425
  * Apply a coupon code — a promotion's own code or a unique code generated for
261
426
  * it — to a DRAFT order of this store: a back-office draft, or an order
@@ -400,6 +565,11 @@ export declare const ORDER_DISCOUNTS_FIELDS = "\n id\n code\n state\n curren
400
565
  export declare const ACTIVE_PROMOTIONS_QUERY = "\n query ActivePromotions($locationId: ID, $customerId: ID) {\n activePromotions(locationId: $locationId, customerId: $customerId) {\n id\n name\n description\n startsAt\n endsAt\n requiresCouponCode\n usageLimit\n perCustomerUsageLimit\n conditions { code args { name value } summary }\n actions { code args { name value } summary }\n summary\n }\n }\n";
401
566
  export declare const CREATE_PROMOTION_MUTATION = "\n mutation CreatePromotion($input: CreatePromotionInput!) {\n createPromotion(input: $input) {\n ... on Promotion { \n id\n name\n description\n enabled\n couponCode\n startsAt\n endsAt\n usageLimit\n perCustomerUsageLimit\n conditions { code args { name value } }\n actions { code args { name value } }\n customFields { combineWithB2b combineWithOtherPromotions priority }\n }\n ... on ErrorResult { errorCode message }\n }\n }\n";
402
567
  export declare const UPDATE_PROMOTION_MUTATION = "\n mutation UpdatePromotion($input: UpdatePromotionInput!) {\n updatePromotion(input: $input) {\n ... on Promotion { \n id\n name\n description\n enabled\n couponCode\n startsAt\n endsAt\n usageLimit\n perCustomerUsageLimit\n conditions { code args { name value } }\n actions { code args { name value } }\n customFields { combineWithB2b combineWithOtherPromotions priority }\n }\n ... on ErrorResult { errorCode message }\n }\n }\n";
568
+ export declare const PROMOTIONS_QUERY = "\n query StorePromotions($options: PromotionListOptions) {\n promotions(options: $options) {\n items {\n \n id\n name\n description\n couponCode\n enabled\n startsAt\n endsAt\n usageLimit\n perCustomerUsageLimit\n createdAt\n updatedAt\n\n customFields { combineWithB2b combineWithOtherPromotions priority }\n }\n totalItems\n }\n }\n";
569
+ export declare const PROMOTION_QUERY = "\n query StorePromotion($id: ID!) {\n promotion(id: $id) {\n \n id\n name\n description\n couponCode\n enabled\n startsAt\n endsAt\n usageLimit\n perCustomerUsageLimit\n createdAt\n updatedAt\n\n translations { id languageCode name description }\n conditions { code args { name value } }\n actions { code args { name value } }\n customFields { combineWithB2b combineWithOtherPromotions priority managedBy }\n }\n }\n";
570
+ export declare const DELETE_PROMOTION_MUTATION = "\n mutation DeleteStorePromotion($id: ID!) {\n deletePromotion(id: $id) {\n result\n message\n }\n }\n";
571
+ export declare const PROMOTION_CONDITION_DEFINITIONS_QUERY = "\n query PromotionConditionDefinitions {\n promotionConditions { \n code\n description\n args {\n name\n type\n list\n required\n defaultValue\n label\n description\n ui\n }\n }\n }\n";
572
+ export declare const PROMOTION_ACTION_DEFINITIONS_QUERY = "\n query PromotionActionDefinitions {\n promotionActions { \n code\n description\n args {\n name\n type\n list\n required\n defaultValue\n label\n description\n ui\n }\n }\n }\n";
403
573
  /** The condition the dashboard and the admin app put on every promotion they save. */
404
574
  export declare const STACKING_GUARD_CONDITION = "promotion_stacking_guard";
405
575
  export declare const APPLY_COUPON_CODE_TO_ORDER_MUTATION = "\n mutation ApplyCouponCodeToOrder($orderId: ID!, $couponCode: String!, $idempotencyKey: String) {\n applyCouponCodeToOrder(\n orderId: $orderId\n couponCode: $couponCode\n idempotencyKey: $idempotencyKey\n ) {\n \n id\n code\n state\n currencyCode\n couponCodes\n subTotal\n subTotalWithTax\n shipping\n shippingWithTax\n total\n totalWithTax\n discounts { promotionId adjustmentSource type description amount amountWithTax }\n promotions { id name }\n lines {\n id\n quantity\n productVariant { id sku name }\n unitPrice\n unitPriceWithTax\n linePrice\n linePriceWithTax\n discountedLinePrice\n discountedLinePriceWithTax\n proratedLinePrice\n proratedLinePriceWithTax\n discounts { promotionId adjustmentSource type description amount amountWithTax }\n }\n surcharges { id description sku price priceWithTax }\n packages { promotionId label price priceWithTax lineIds quantity }\n\n }\n }\n";
@@ -1,4 +1,7 @@
1
- import { createPage, errorFromErrorResult, isErrorResult, NotFoundError, ValidationError, } from '@sixtyninecommerce/core';
1
+ import { ConflictError, createPage, errorFromErrorResult, isErrorResult, NotFoundError, UpstreamError, ValidationError, } from '@sixtyninecommerce/core';
2
+ import { fieldOf, vendureListPage, } from '../catalog/types.js';
3
+ import { createPricingBulkCouponsModule } from './bulk-coupons.js';
4
+ import { createPricingPriceListsModule } from './price-lists.js';
2
5
  import { createPricingVouchersModule } from './vouchers.js';
3
6
  /**
4
7
  * The targeting conditions (incentives sprint 2), encoded as the engine stores
@@ -142,6 +145,14 @@ export const promotionActions = {
142
145
  return { code: 'mix_and_match', arguments: [] };
143
146
  },
144
147
  };
148
+ export const PROMOTION_SORT_FIELDS = [
149
+ 'name',
150
+ 'couponCode',
151
+ 'startsAt',
152
+ 'endsAt',
153
+ 'createdAt',
154
+ 'updatedAt',
155
+ ];
145
156
  const DISCOUNT_FIELDS = 'promotionId adjustmentSource type description amount amountWithTax';
146
157
  /** An order's pricing readout; the manual pricing doors (`orders.setLinePrices`, …) answer it too. */
147
158
  export const ORDER_DISCOUNTS_FIELDS = /* GraphQL */ `
@@ -223,8 +234,144 @@ export const UPDATE_PROMOTION_MUTATION = /* GraphQL */ `
223
234
  }
224
235
  }
225
236
  `;
237
+ const PROMOTION_ROW_FIELDS = /* GraphQL */ `
238
+ id
239
+ name
240
+ description
241
+ couponCode
242
+ enabled
243
+ startsAt
244
+ endsAt
245
+ usageLimit
246
+ perCustomerUsageLimit
247
+ createdAt
248
+ updatedAt
249
+ `;
250
+ export const PROMOTIONS_QUERY = /* GraphQL */ `
251
+ query StorePromotions($options: PromotionListOptions) {
252
+ promotions(options: $options) {
253
+ items {
254
+ ${PROMOTION_ROW_FIELDS}
255
+ customFields { combineWithB2b combineWithOtherPromotions priority }
256
+ }
257
+ totalItems
258
+ }
259
+ }
260
+ `;
261
+ export const PROMOTION_QUERY = /* GraphQL */ `
262
+ query StorePromotion($id: ID!) {
263
+ promotion(id: $id) {
264
+ ${PROMOTION_ROW_FIELDS}
265
+ translations { id languageCode name description }
266
+ conditions { code args { name value } }
267
+ actions { code args { name value } }
268
+ customFields { combineWithB2b combineWithOtherPromotions priority managedBy }
269
+ }
270
+ }
271
+ `;
272
+ export const DELETE_PROMOTION_MUTATION = /* GraphQL */ `
273
+ mutation DeleteStorePromotion($id: ID!) {
274
+ deletePromotion(id: $id) {
275
+ result
276
+ message
277
+ }
278
+ }
279
+ `;
280
+ const DEFINITION_FIELDS = /* GraphQL */ `
281
+ code
282
+ description
283
+ args {
284
+ name
285
+ type
286
+ list
287
+ required
288
+ defaultValue
289
+ label
290
+ description
291
+ ui
292
+ }
293
+ `;
294
+ export const PROMOTION_CONDITION_DEFINITIONS_QUERY = /* GraphQL */ `
295
+ query PromotionConditionDefinitions {
296
+ promotionConditions { ${DEFINITION_FIELDS} }
297
+ }
298
+ `;
299
+ export const PROMOTION_ACTION_DEFINITIONS_QUERY = /* GraphQL */ `
300
+ query PromotionActionDefinitions {
301
+ promotionActions { ${DEFINITION_FIELDS} }
302
+ }
303
+ `;
226
304
  /** The condition the dashboard and the admin app put on every promotion they save. */
227
305
  export const STACKING_GUARD_CONDITION = 'promotion_stacking_guard';
306
+ /**
307
+ * The price-list order-rule condition and action (`vendure-plugin-price-list`'s
308
+ * `order-rule-promotion.ts`): only the store's auto-managed promotion carries them, and the engine
309
+ * refuses them on any other (`PROMOTION_CONDITION_INVALID`), so they are never offered.
310
+ */
311
+ const ORDER_RULE_OPERATION = 'price_list_order_rules';
312
+ /** Registered conditions a caller never sets itself (see `conditionDefinitions`). */
313
+ const NOT_OFFERED_CONDITIONS = new Set([
314
+ STACKING_GUARD_CONDITION,
315
+ ORDER_RULE_OPERATION,
316
+ ]);
317
+ /** Registered actions a caller never sets itself (see `actionDefinitions`). */
318
+ const NOT_OFFERED_ACTIONS = new Set([ORDER_RULE_OPERATION]);
319
+ /**
320
+ * Every list read asks only for promotions no platform service manages: the store's order-rule
321
+ * promotion (`customFields.managedBy`) is never a row, on any page or search.
322
+ */
323
+ const MERCHANT_PROMOTIONS = { managedBy: { isNull: true } };
324
+ function invalidPromotionList(code, message) {
325
+ return new ValidationError({ code, message, status: 400, service: 'vendure' });
326
+ }
327
+ /** `promotions(options)`'s variables for one page, the filters and the sort checked first. */
328
+ function promotionListVariables(options) {
329
+ const filter = { ...MERCHANT_PROMOTIONS };
330
+ const term = options?.term;
331
+ if (term !== undefined) {
332
+ if (typeof term !== 'string') {
333
+ throw invalidPromotionList('INVALID_PROMOTION_FILTER', 'term must be a string.');
334
+ }
335
+ const trimmed = term.trim();
336
+ if (trimmed !== '') {
337
+ filter._or = [{ name: { contains: trimmed } }, { couponCode: { contains: trimmed } }];
338
+ }
339
+ }
340
+ const enabled = options?.enabled;
341
+ if (enabled !== undefined) {
342
+ if (typeof enabled !== 'boolean') {
343
+ throw invalidPromotionList('INVALID_PROMOTION_FILTER', 'enabled must be true or false.');
344
+ }
345
+ filter.enabled = { eq: enabled };
346
+ }
347
+ const sort = options?.sort;
348
+ if (sort !== undefined &&
349
+ (!PROMOTION_SORT_FIELDS.includes(sort.field) ||
350
+ (sort.direction !== 'ASC' && sort.direction !== 'DESC'))) {
351
+ throw invalidPromotionList('INVALID_PROMOTION_SORT', `sort must name one of ${PROMOTION_SORT_FIELDS.join(', ')} and a direction ASC or DESC.`);
352
+ }
353
+ return (skip, take) => ({
354
+ options: {
355
+ skip,
356
+ take,
357
+ filter,
358
+ ...(sort === undefined ? {} : { sort: { [sort.field]: sort.direction } }),
359
+ },
360
+ });
361
+ }
362
+ /** A definitions list read by name: anything but a list is refused, never answered empty. */
363
+ async function definitionsOf(transport, document, field, hidden, options) {
364
+ const definitions = await fieldOf(transport, document, field, {}, options);
365
+ if (!Array.isArray(definitions)) {
366
+ throw new UpstreamError({
367
+ code: 'UNEXPECTED_RESPONSE',
368
+ message: `The engine answered "${field}" without a list.`,
369
+ status: 502,
370
+ service: 'vendure',
371
+ });
372
+ }
373
+ return definitions.filter((definition) => !hidden.has(definition.code));
374
+ }
228
375
  function withStackingGuard(conditions) {
229
376
  return conditions.some((condition) => condition.code === STACKING_GUARD_CONDITION)
230
377
  ? conditions
@@ -280,6 +427,30 @@ function idVariable(value) {
280
427
  export function createPricingModule(transport) {
281
428
  return {
282
429
  promotions: {
430
+ // Async, so a refused option rejects the promise like every refusal, never throws.
431
+ async list(options) {
432
+ return vendureListPage(transport, PROMOTIONS_QUERY, 'promotions', promotionListVariables(options), options);
433
+ },
434
+ get(id, options) {
435
+ return fieldOf(transport, PROMOTION_QUERY, 'promotion', { id }, options);
436
+ },
437
+ async delete(id, options) {
438
+ const answer = await fieldOf(transport, DELETE_PROMOTION_MUTATION, 'deletePromotion', { id }, options);
439
+ if (answer.result !== 'DELETED') {
440
+ throw new ConflictError({
441
+ code: 'PROMOTION_NOT_DELETED',
442
+ message: answer.message || `The engine kept promotion ${id}.`,
443
+ status: 409,
444
+ service: 'vendure',
445
+ });
446
+ }
447
+ },
448
+ conditionDefinitions(options) {
449
+ return definitionsOf(transport, PROMOTION_CONDITION_DEFINITIONS_QUERY, 'promotionConditions', NOT_OFFERED_CONDITIONS, options);
450
+ },
451
+ actionDefinitions(options) {
452
+ return definitionsOf(transport, PROMOTION_ACTION_DEFINITIONS_QUERY, 'promotionActions', NOT_OFFERED_ACTIONS, options);
453
+ },
283
454
  async active(filter, options) {
284
455
  const data = await transport.graphql({
285
456
  api: 'admin',
@@ -319,7 +490,9 @@ export function createPricingModule(transport) {
319
490
  },
320
491
  },
321
492
  vouchers: createPricingVouchersModule(transport),
493
+ priceLists: createPricingPriceListsModule(transport),
322
494
  coupons: {
495
+ bulk: createPricingBulkCouponsModule(transport),
323
496
  async apply(orderId, couponCode, options) {
324
497
  const data = await transport.graphql({
325
498
  api: 'admin',