@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.
Files changed (302) hide show
  1. package/README.md +5772 -118
  2. package/dist/auth/index.d.ts +7 -1
  3. package/dist/auth/index.js +8 -1
  4. package/dist/catalog/assets.d.ts +120 -8
  5. package/dist/catalog/assets.js +98 -12
  6. package/dist/catalog/collections.d.ts +279 -14
  7. package/dist/catalog/collections.js +246 -15
  8. package/dist/catalog/documents.d.ts +142 -0
  9. package/dist/catalog/documents.js +114 -0
  10. package/dist/catalog/index.d.ts +54 -6
  11. package/dist/catalog/index.js +10 -1
  12. package/dist/catalog/metadata.d.ts +244 -0
  13. package/dist/catalog/metadata.js +220 -0
  14. package/dist/catalog/products.d.ts +159 -19
  15. package/dist/catalog/products.js +88 -13
  16. package/dist/catalog/properties.d.ts +140 -14
  17. package/dist/catalog/properties.js +65 -1
  18. package/dist/catalog/recommendations.d.ts +288 -0
  19. package/dist/catalog/recommendations.js +237 -0
  20. package/dist/catalog/reviews.d.ts +381 -0
  21. package/dist/catalog/reviews.js +325 -0
  22. package/dist/catalog/types.d.ts +17 -1
  23. package/dist/catalog/types.js +10 -0
  24. package/dist/catalog/variant-find.d.ts +136 -0
  25. package/dist/catalog/variant-find.js +239 -0
  26. package/dist/catalog/variants.d.ts +293 -26
  27. package/dist/catalog/variants.js +164 -7
  28. package/dist/catalog/visibility.d.ts +38 -7
  29. package/dist/catalog/visibility.js +19 -1
  30. package/dist/client.d.ts +121 -9
  31. package/dist/client.js +53 -14
  32. package/dist/content/assets.d.ts +285 -0
  33. package/dist/content/assets.js +181 -0
  34. package/dist/content/forms.d.ts +332 -1
  35. package/dist/content/forms.js +140 -4
  36. package/dist/content/items.d.ts +292 -0
  37. package/dist/content/items.js +170 -0
  38. package/dist/content/menus.d.ts +254 -0
  39. package/dist/content/menus.js +70 -0
  40. package/dist/content/strings.d.ts +137 -0
  41. package/dist/content/strings.js +82 -0
  42. package/dist/content/types.d.ts +282 -0
  43. package/dist/content/types.js +100 -0
  44. package/dist/customers/age-verification.d.ts +66 -0
  45. package/dist/customers/age-verification.js +79 -0
  46. package/dist/customers/credit.d.ts +263 -0
  47. package/dist/customers/credit.js +244 -0
  48. package/dist/customers/delivery-preferences.d.ts +120 -0
  49. package/dist/customers/delivery-preferences.js +97 -0
  50. package/dist/customers/delivery-terms.d.ts +44 -0
  51. package/dist/customers/delivery-terms.js +32 -0
  52. package/dist/customers/groups.d.ts +207 -0
  53. package/dist/customers/groups.js +438 -0
  54. package/dist/customers/index.d.ts +462 -37
  55. package/dist/customers/index.js +317 -40
  56. package/dist/customers/invitation-status.d.ts +57 -0
  57. package/dist/customers/invitation-status.js +21 -0
  58. package/dist/customers/notes.d.ts +67 -0
  59. package/dist/customers/notes.js +51 -0
  60. package/dist/customers/notification-recipients.d.ts +97 -0
  61. package/dist/customers/notification-recipients.js +84 -0
  62. package/dist/customers/saved-lists.d.ts +42 -0
  63. package/dist/customers/saved-lists.js +61 -0
  64. package/dist/customers/vat.d.ts +83 -0
  65. package/dist/customers/vat.js +46 -0
  66. package/dist/customers/wire.d.ts +20 -0
  67. package/dist/customers/wire.js +35 -0
  68. package/dist/documents/ar.d.ts +307 -0
  69. package/dist/documents/ar.js +254 -0
  70. package/dist/documents/emails.d.ts +150 -0
  71. package/dist/documents/emails.js +220 -0
  72. package/dist/documents/index.d.ts +744 -21
  73. package/dist/documents/index.js +438 -24
  74. package/dist/documents/pdf.d.ts +2 -0
  75. package/dist/documents/pdf.js +11 -0
  76. package/dist/fulfillments/create.d.ts +167 -0
  77. package/dist/fulfillments/create.js +216 -0
  78. package/dist/fulfillments/index.d.ts +163 -11
  79. package/dist/fulfillments/index.js +135 -6
  80. package/dist/fulfillments/payment-policy.d.ts +64 -0
  81. package/dist/fulfillments/payment-policy.js +140 -0
  82. package/dist/fulfillments/warehouse.d.ts +724 -0
  83. package/dist/fulfillments/warehouse.js +914 -0
  84. package/dist/geo/index.d.ts +119 -0
  85. package/dist/geo/index.js +107 -0
  86. package/dist/index.d.ts +147 -39
  87. package/dist/index.js +51 -12
  88. package/dist/integrations/afas-actions.d.ts +234 -0
  89. package/dist/integrations/afas-actions.js +310 -0
  90. package/dist/integrations/afas-types.d.ts +483 -0
  91. package/dist/integrations/afas-types.js +5 -0
  92. package/dist/integrations/afas.d.ts +234 -0
  93. package/dist/integrations/afas.js +290 -0
  94. package/dist/integrations/connections.d.ts +103 -0
  95. package/dist/integrations/connections.js +55 -0
  96. package/dist/integrations/esp.d.ts +313 -0
  97. package/dist/integrations/esp.js +169 -0
  98. package/dist/integrations/exact-online-types.d.ts +965 -0
  99. package/dist/integrations/exact-online-types.js +6 -0
  100. package/dist/integrations/exact-online.d.ts +784 -0
  101. package/dist/integrations/exact-online.js +1089 -0
  102. package/dist/integrations/index.d.ts +44 -3
  103. package/dist/integrations/index.js +23 -3
  104. package/dist/integrations/pipeline-discoveries.d.ts +65 -0
  105. package/dist/integrations/pipeline-discoveries.js +65 -0
  106. package/dist/integrations/pipeline-keys.d.ts +13 -0
  107. package/dist/integrations/pipeline-keys.js +22 -0
  108. package/dist/integrations/pipeline-runs.d.ts +119 -0
  109. package/dist/integrations/pipeline-runs.js +87 -0
  110. package/dist/integrations/pipelines.d.ts +87 -15
  111. package/dist/integrations/pipelines.js +41 -22
  112. package/dist/integrations/price-import.d.ts +223 -0
  113. package/dist/integrations/price-import.js +124 -0
  114. package/dist/integrations/types.d.ts +367 -3
  115. package/dist/integrations/types.js +4 -3
  116. package/dist/locations/index.d.ts +66 -0
  117. package/dist/locations/index.js +31 -0
  118. package/dist/meta/index.d.ts +172 -0
  119. package/dist/metafields/index.d.ts +8 -1
  120. package/dist/metafields/index.js +10 -0
  121. package/dist/orders/cancel-with-money.d.ts +237 -0
  122. package/dist/orders/cancel-with-money.js +155 -0
  123. package/dist/orders/commit-edit.d.ts +23 -1
  124. package/dist/orders/commit-edit.js +19 -2
  125. package/dist/orders/deposit-policy.d.ts +3 -1
  126. package/dist/orders/drafts.d.ts +800 -0
  127. package/dist/orders/drafts.js +771 -0
  128. package/dist/orders/fields.d.ts +245 -0
  129. package/dist/orders/fields.js +188 -0
  130. package/dist/orders/get.d.ts +29 -19
  131. package/dist/orders/get.js +17 -8
  132. package/dist/orders/index.d.ts +66 -15
  133. package/dist/orders/index.js +25 -2
  134. package/dist/orders/lifecycle.d.ts +128 -0
  135. package/dist/orders/lifecycle.js +158 -0
  136. package/dist/orders/line-price-preview.d.ts +7 -2
  137. package/dist/orders/list.d.ts +243 -0
  138. package/dist/orders/list.js +487 -0
  139. package/dist/orders/manual-discounts.d.ts +13 -5
  140. package/dist/orders/manual-pricing.d.ts +5 -0
  141. package/dist/orders/money-view.d.ts +149 -0
  142. package/dist/orders/money-view.js +99 -0
  143. package/dist/orders/order-entry.d.ts +20 -7
  144. package/dist/orders/plan-edit.d.ts +34 -2
  145. package/dist/orders/plan-edit.js +112 -11
  146. package/dist/orders/settings.d.ts +201 -0
  147. package/dist/orders/settings.js +325 -0
  148. package/dist/orders/status.d.ts +159 -13
  149. package/dist/orders/status.js +21 -0
  150. package/dist/orders/surcharges.d.ts +20 -1
  151. package/dist/orders/surcharges.js +37 -11
  152. package/dist/payments/account-credit.d.ts +46 -0
  153. package/dist/payments/account-credit.js +42 -0
  154. package/dist/payments/ar.d.ts +292 -0
  155. package/dist/payments/ar.js +223 -0
  156. package/dist/payments/connected-account.d.ts +47 -0
  157. package/dist/payments/connected-account.js +61 -0
  158. package/dist/payments/credit-noted-fields.d.ts +19 -0
  159. package/dist/payments/credit-noted-fields.js +69 -0
  160. package/dist/payments/customer-consent.d.ts +30 -0
  161. package/dist/payments/customer-consent.js +49 -0
  162. package/dist/payments/index.d.ts +340 -19
  163. package/dist/payments/index.js +151 -1
  164. package/dist/payments/methods.d.ts +303 -8
  165. package/dist/payments/methods.js +337 -7
  166. package/dist/payments/mollie-methods.d.ts +159 -0
  167. package/dist/payments/mollie-methods.js +141 -0
  168. package/dist/payments/payment-links.d.ts +180 -0
  169. package/dist/payments/payment-links.js +97 -0
  170. package/dist/payments/provider-keys.d.ts +150 -0
  171. package/dist/payments/provider-keys.js +118 -0
  172. package/dist/payments/providers.d.ts +86 -11
  173. package/dist/payments/providers.js +29 -0
  174. package/dist/payments/requests.d.ts +147 -0
  175. package/dist/payments/requests.js +93 -0
  176. package/dist/payments/store-credit-fields.d.ts +15 -0
  177. package/dist/payments/store-credit-fields.js +51 -0
  178. package/dist/pickups/index.d.ts +106 -0
  179. package/dist/pickups/index.js +108 -0
  180. package/dist/platform/channels.d.ts +132 -0
  181. package/dist/platform/channels.js +128 -0
  182. package/dist/platform/email-gateways.d.ts +165 -0
  183. package/dist/platform/email-gateways.js +78 -0
  184. package/dist/platform/geo.d.ts +123 -0
  185. package/dist/platform/geo.js +144 -0
  186. package/dist/platform/tax.d.ts +162 -0
  187. package/dist/platform/tax.js +169 -0
  188. package/dist/pos/anomalies.d.ts +158 -0
  189. package/dist/pos/anomalies.js +64 -0
  190. package/dist/pos/assisted-selling.d.ts +79 -0
  191. package/dist/pos/assisted-selling.js +38 -0
  192. package/dist/pos/exchanges.d.ts +108 -0
  193. package/dist/pos/exchanges.js +22 -0
  194. package/dist/pos/gift-cards.d.ts +135 -0
  195. package/dist/pos/gift-cards.js +47 -0
  196. package/dist/pos/index.d.ts +2370 -58
  197. package/dist/pos/index.js +854 -7
  198. package/dist/pos/no-receipt.d.ts +94 -0
  199. package/dist/pos/no-receipt.js +25 -0
  200. package/dist/pos/offline-sales.d.ts +228 -0
  201. package/dist/pos/offline-sales.js +170 -0
  202. package/dist/pos/pay-by-link.d.ts +143 -0
  203. package/dist/pos/pay-by-link.js +57 -0
  204. package/dist/pos/quick-keys.d.ts +103 -0
  205. package/dist/pos/quick-keys.js +45 -0
  206. package/dist/pos/reports.d.ts +360 -0
  207. package/dist/pos/reports.js +62 -0
  208. package/dist/pos/returns.d.ts +244 -0
  209. package/dist/pos/returns.js +83 -0
  210. package/dist/pricing/bulk-coupons.d.ts +139 -0
  211. package/dist/pricing/bulk-coupons.js +112 -0
  212. package/dist/pricing/index.d.ts +174 -4
  213. package/dist/pricing/index.js +174 -1
  214. package/dist/pricing/price-lists.d.ts +606 -0
  215. package/dist/pricing/price-lists.js +600 -0
  216. package/dist/purchasing/alerts.d.ts +104 -0
  217. package/dist/purchasing/alerts.js +88 -0
  218. package/dist/purchasing/backorders.d.ts +61 -0
  219. package/dist/purchasing/backorders.js +92 -0
  220. package/dist/purchasing/cost.d.ts +110 -0
  221. package/dist/purchasing/cost.js +86 -0
  222. package/dist/purchasing/index.d.ts +54 -0
  223. package/dist/purchasing/index.js +24 -0
  224. package/dist/purchasing/links.d.ts +263 -0
  225. package/dist/purchasing/links.js +192 -0
  226. package/dist/purchasing/purchase-orders.d.ts +551 -0
  227. package/dist/purchasing/purchase-orders.js +491 -0
  228. package/dist/purchasing/receipts.d.ts +396 -0
  229. package/dist/purchasing/receipts.js +287 -0
  230. package/dist/purchasing/replenishment.d.ts +281 -0
  231. package/dist/purchasing/replenishment.js +240 -0
  232. package/dist/purchasing/returns.d.ts +273 -0
  233. package/dist/purchasing/returns.js +229 -0
  234. package/dist/purchasing/settings.d.ts +152 -0
  235. package/dist/purchasing/settings.js +181 -0
  236. package/dist/purchasing/suppliers.d.ts +476 -0
  237. package/dist/purchasing/suppliers.js +438 -0
  238. package/dist/quotes/index.d.ts +518 -0
  239. package/dist/quotes/index.js +439 -0
  240. package/dist/reports/index.d.ts +71 -8
  241. package/dist/reports/index.js +74 -11
  242. package/dist/returns/index.d.ts +675 -21
  243. package/dist/returns/index.js +756 -11
  244. package/dist/search/index.d.ts +76 -1
  245. package/dist/search/index.js +63 -0
  246. package/dist/seo/config.d.ts +128 -0
  247. package/dist/seo/config.js +95 -0
  248. package/dist/seo/redirects.d.ts +125 -0
  249. package/dist/seo/redirects.js +60 -1
  250. package/dist/seo/settings.d.ts +147 -0
  251. package/dist/seo/settings.js +209 -0
  252. package/dist/shipping/definitions.d.ts +29 -0
  253. package/dist/shipping/definitions.js +47 -0
  254. package/dist/shipping/fulfillment-profiles.d.ts +174 -0
  255. package/dist/shipping/fulfillment-profiles.js +104 -0
  256. package/dist/shipping/hendriks.d.ts +97 -0
  257. package/dist/shipping/hendriks.js +50 -0
  258. package/dist/shipping/index.d.ts +54 -0
  259. package/dist/shipping/index.js +27 -0
  260. package/dist/shipping/methods.d.ts +205 -0
  261. package/dist/shipping/methods.js +240 -0
  262. package/dist/shipping/myparcel.d.ts +668 -0
  263. package/dist/shipping/myparcel.js +466 -0
  264. package/dist/shipping/parcel-count-suggestion.d.ts +2 -0
  265. package/dist/shipping/parcel-rule.d.ts +6 -5
  266. package/dist/shipping/parcel-rule.js +21 -23
  267. package/dist/shipping/rate-tables.d.ts +324 -0
  268. package/dist/shipping/rate-tables.js +390 -0
  269. package/dist/shipping/ship-to-countries.d.ts +75 -0
  270. package/dist/shipping/ship-to-countries.js +47 -0
  271. package/dist/stock/by-location.d.ts +86 -0
  272. package/dist/stock/by-location.js +94 -0
  273. package/dist/stock/index.d.ts +18 -4
  274. package/dist/stock/index.js +7 -0
  275. package/dist/stock/locations.d.ts +144 -0
  276. package/dist/stock/locations.js +168 -0
  277. package/dist/stock/settings.d.ts +106 -0
  278. package/dist/stock/settings.js +103 -0
  279. package/dist/stock/transfers.d.ts +386 -52
  280. package/dist/stock/transfers.js +222 -17
  281. package/dist/stored-value/index.d.ts +312 -11
  282. package/dist/stored-value/index.js +223 -4
  283. package/dist/subscriptions/index.d.ts +682 -0
  284. package/dist/subscriptions/index.js +815 -0
  285. package/dist/tax/display-policy.d.ts +105 -0
  286. package/dist/tax/display-policy.js +84 -0
  287. package/dist/tax/index.d.ts +79 -1
  288. package/dist/tax/index.js +52 -0
  289. package/dist/tenant/email-style.d.ts +102 -0
  290. package/dist/tenant/email-style.js +72 -0
  291. package/dist/tenant/email-templates.d.ts +287 -0
  292. package/dist/tenant/email-templates.js +271 -0
  293. package/dist/tenant/notifications.d.ts +23 -17
  294. package/dist/tenant/settings-sources.d.ts +1 -1
  295. package/dist/tenant/time-zone.d.ts +17 -0
  296. package/dist/tenant/time-zone.js +11 -0
  297. package/dist/types.d.ts +50 -3
  298. package/dist/users/index.d.ts +3 -0
  299. package/dist/users/index.js +2 -0
  300. package/dist/users/warehouses.d.ts +50 -0
  301. package/dist/users/warehouses.js +51 -0
  302. package/package.json +2 -2
@@ -0,0 +1,97 @@
1
+ /**
2
+ * A customer's additional notification recipients (headless spec §9.2 `customers` "notification
3
+ * recipients"; W10-33): extra addresses (accounting, purchasing, a warehouse) the store's order
4
+ * emails to the customer also go to. Who an order's document email goes to with them applied is
5
+ * `documents.emailRecipients`.
6
+ */
7
+ import type { Transport } from '@sixtyninecommerce/core';
8
+ import type { Call } from '../types.js';
9
+ export interface CustomerNotificationRecipient {
10
+ id: string;
11
+ /** ISO-8601 with offset. */
12
+ createdAt: string;
13
+ /** ISO-8601 with offset. */
14
+ updatedAt: string;
15
+ email: string;
16
+ label: string | null;
17
+ /**
18
+ * The notification event codes the recipient receives (`order_placed`, `order_shipped`,
19
+ * `invoice_generated`, …). Empty means every event a customer's contacts may receive; a
20
+ * security email (password reset, verification) never goes to a recipient.
21
+ */
22
+ events: string[];
23
+ enabled: boolean;
24
+ /**
25
+ * "Send only to this address": for its events the address takes the customer's own place
26
+ * instead of being copied beside it.
27
+ */
28
+ replaceCustomerEmail: boolean;
29
+ /**
30
+ * Set when the caller's customer-data level blanked `email` or `label` (an app installation
31
+ * below `identity`): "" or null then means "not granted". Never write such a recipient back.
32
+ */
33
+ redacted?: true;
34
+ }
35
+ export interface CreateNotificationRecipientInput {
36
+ customerId: string;
37
+ email: string;
38
+ label?: string | null;
39
+ /** Empty or left out: every event a customer's contacts may receive. */
40
+ events?: string[];
41
+ /** Default true. */
42
+ enabled?: boolean;
43
+ /** Default false. */
44
+ replaceCustomerEmail?: boolean;
45
+ }
46
+ export interface UpdateNotificationRecipientInput {
47
+ email?: string;
48
+ /** `null` clears the label. */
49
+ label?: string | null;
50
+ events?: string[];
51
+ enabled?: boolean;
52
+ replaceCustomerEmail?: boolean;
53
+ }
54
+ export interface CustomerNotificationRecipientsModule {
55
+ /**
56
+ * The customer's notification recipients in this store, oldest first; `[]` for a customer
57
+ * with none, and for one the store does not hold. Needs `ReadCustomer`.
58
+ *
59
+ * @effect read
60
+ */
61
+ list(customerId: string, options?: Call): Promise<CustomerNotificationRecipient[]>;
62
+ /**
63
+ * Add a recipient to a customer. Needs `UpdateCustomer`.
64
+ *
65
+ * Refused with the engine's sentence (`ValidationError`, `USER_INPUT_ERROR`, 400): a value
66
+ * that is not an email address, an address the customer already has as a recipient, an event
67
+ * code a customer's contacts may not receive, a label over 100 characters, or a customer that
68
+ * already has 20. A customer this store does not hold is a `NotFoundError`
69
+ * (`ENTITY_NOT_FOUND`); an engine older than that check saved the recipient under any id,
70
+ * where no read ever showed it.
71
+ *
72
+ * @effect write
73
+ */
74
+ create(input: CreateNotificationRecipientInput, options?: Call): Promise<CustomerNotificationRecipient>;
75
+ /**
76
+ * Change a recipient; what is left out is kept. Needs `UpdateCustomer`. Refused like
77
+ * {@link create}, and for an id that is not a recipient of this store.
78
+ *
79
+ * @effect write
80
+ */
81
+ update(id: string, input: UpdateNotificationRecipientInput, options?: Call): Promise<CustomerNotificationRecipient>;
82
+ /**
83
+ * Remove a recipient: the store's emails stop going to the address. Needs `UpdateCustomer`.
84
+ *
85
+ * Refused `CUSTOMER_NOTIFICATION_RECIPIENT_NOT_DELETED` (`ConflictError`, 409) with the
86
+ * engine's own reason when this store has no such recipient.
87
+ *
88
+ * @effect destructive
89
+ */
90
+ delete(id: string, options?: Call): Promise<void>;
91
+ }
92
+ export declare const NOTIFICATION_RECIPIENT_FIELDS = "\n id\n createdAt\n updatedAt\n email\n label\n events\n enabled\n replaceCustomerEmail\n";
93
+ export declare const NOTIFICATION_RECIPIENTS_QUERY = "\n query CustomerNotificationRecipients($id: ID!) {\n customer(id: $id) {\n id\n notificationRecipients {\n \n id\n createdAt\n updatedAt\n email\n label\n events\n enabled\n replaceCustomerEmail\n\n }\n }\n }\n";
94
+ export declare const CREATE_NOTIFICATION_RECIPIENT_MUTATION = "\n mutation CreateCustomerNotificationRecipient($input: CreateCustomerNotificationRecipientInput!) {\n createCustomerNotificationRecipient(input: $input) {\n \n id\n createdAt\n updatedAt\n email\n label\n events\n enabled\n replaceCustomerEmail\n\n }\n }\n";
95
+ export declare const UPDATE_NOTIFICATION_RECIPIENT_MUTATION = "\n mutation UpdateCustomerNotificationRecipient($input: UpdateCustomerNotificationRecipientInput!) {\n updateCustomerNotificationRecipient(input: $input) {\n \n id\n createdAt\n updatedAt\n email\n label\n events\n enabled\n replaceCustomerEmail\n\n }\n }\n";
96
+ export declare const DELETE_NOTIFICATION_RECIPIENT_MUTATION = "\n mutation DeleteCustomerNotificationRecipient($id: ID!) {\n deleteCustomerNotificationRecipient(id: $id) {\n result\n message\n }\n }\n";
97
+ export declare function createCustomerNotificationRecipientsModule(transport: Transport): CustomerNotificationRecipientsModule;
@@ -0,0 +1,84 @@
1
+ import { assertDeleted, fieldOf } from '../catalog/types.js';
2
+ import { customerDataField } from './wire.js';
3
+ export const NOTIFICATION_RECIPIENT_FIELDS = /* GraphQL */ `
4
+ id
5
+ createdAt
6
+ updatedAt
7
+ email
8
+ label
9
+ events
10
+ enabled
11
+ replaceCustomerEmail
12
+ `;
13
+ export const NOTIFICATION_RECIPIENTS_QUERY = /* GraphQL */ `
14
+ query CustomerNotificationRecipients($id: ID!) {
15
+ customer(id: $id) {
16
+ id
17
+ notificationRecipients {
18
+ ${NOTIFICATION_RECIPIENT_FIELDS}
19
+ }
20
+ }
21
+ }
22
+ `;
23
+ export const CREATE_NOTIFICATION_RECIPIENT_MUTATION = /* GraphQL */ `
24
+ mutation CreateCustomerNotificationRecipient($input: CreateCustomerNotificationRecipientInput!) {
25
+ createCustomerNotificationRecipient(input: $input) {
26
+ ${NOTIFICATION_RECIPIENT_FIELDS}
27
+ }
28
+ }
29
+ `;
30
+ export const UPDATE_NOTIFICATION_RECIPIENT_MUTATION = /* GraphQL */ `
31
+ mutation UpdateCustomerNotificationRecipient($input: UpdateCustomerNotificationRecipientInput!) {
32
+ updateCustomerNotificationRecipient(input: $input) {
33
+ ${NOTIFICATION_RECIPIENT_FIELDS}
34
+ }
35
+ }
36
+ `;
37
+ export const DELETE_NOTIFICATION_RECIPIENT_MUTATION = /* GraphQL */ `
38
+ mutation DeleteCustomerNotificationRecipient($id: ID!) {
39
+ deleteCustomerNotificationRecipient(id: $id) {
40
+ result
41
+ message
42
+ }
43
+ }
44
+ `;
45
+ export function createCustomerNotificationRecipientsModule(transport) {
46
+ return {
47
+ async list(customerId, options) {
48
+ const { value: customer, mark } = await customerDataField(transport, NOTIFICATION_RECIPIENTS_QUERY, 'customer', { id: customerId }, options);
49
+ return (customer?.notificationRecipients ?? []).map(mark);
50
+ },
51
+ async create(input, options) {
52
+ const { value, mark } = await customerDataField(transport, CREATE_NOTIFICATION_RECIPIENT_MUTATION, 'createCustomerNotificationRecipient', {
53
+ input: {
54
+ customerId: input.customerId,
55
+ email: input.email,
56
+ label: input.label,
57
+ events: input.events,
58
+ enabled: input.enabled,
59
+ replaceCustomerEmail: input.replaceCustomerEmail,
60
+ },
61
+ }, options);
62
+ return mark(value);
63
+ },
64
+ async update(id, input, options) {
65
+ const { value, mark } = await customerDataField(transport, UPDATE_NOTIFICATION_RECIPIENT_MUTATION, 'updateCustomerNotificationRecipient', {
66
+ // `label: null` clears it and is sent; everything left out stays off the wire, and kept.
67
+ input: {
68
+ id,
69
+ email: input.email,
70
+ label: input.label,
71
+ events: input.events,
72
+ enabled: input.enabled,
73
+ replaceCustomerEmail: input.replaceCustomerEmail,
74
+ },
75
+ }, options);
76
+ return mark(value);
77
+ },
78
+ async delete(id, options) {
79
+ assertDeleted('CUSTOMER_NOTIFICATION_RECIPIENT_NOT_DELETED', [
80
+ await fieldOf(transport, DELETE_NOTIFICATION_RECIPIENT_MUTATION, 'deleteCustomerNotificationRecipient', { id }, options),
81
+ ]);
82
+ },
83
+ };
84
+ }
@@ -0,0 +1,42 @@
1
+ /**
2
+ * A customer's saved lists (headless W10-15, spec §9.2 `customers`): the named lists of products
3
+ * and quantities a shopper keeps on the storefront to order again. Read-only here: the shopper
4
+ * writes them through the Shop API, and the back office reads them on the customer's page.
5
+ */
6
+ import { type Transport } from '@sixtyninecommerce/core';
7
+ import type { Call } from '../types.js';
8
+ export interface CustomerSavedListItem {
9
+ id: string;
10
+ productVariantId: string;
11
+ quantity: number;
12
+ /** The shopper's order of the items, lowest first; the items are answered in it. */
13
+ position: number;
14
+ /**
15
+ * The variant as the store holds it now, or `null` when it no longer does. A variant of a
16
+ * DISABLED product is still answered here: the Shop API hides it from the shopper's own list
17
+ * (multi-region decision 87), the back office still sees what the list holds.
18
+ */
19
+ productVariant: {
20
+ id: string;
21
+ name: string;
22
+ sku: string;
23
+ } | null;
24
+ }
25
+ export interface CustomerSavedList {
26
+ id: string;
27
+ /** What the shopper called the list: customer data, withheld below `customerData: full`. */
28
+ name: string;
29
+ createdAt: string;
30
+ updatedAt: string;
31
+ items: CustomerSavedListItem[];
32
+ /** Set when the caller's customer-data level withheld the name (an app below `full`). */
33
+ redacted?: true;
34
+ }
35
+ /**
36
+ * The customer's own read (`customer(id) { id }`) beside the lists: the lists' door answers `[]`
37
+ * for an id the store does not hold, and only the customer read tells a customer with no lists
38
+ * apart from a customer the store does not hold.
39
+ */
40
+ export declare const CUSTOMER_SAVED_LISTS_QUERY = "\n query CustomerSavedLists($customerId: ID!) {\n customer(id: $customerId) {\n id\n }\n savedListsForCustomer(customerId: $customerId) {\n id\n name\n createdAt\n updatedAt\n items {\n id\n productVariantId\n quantity\n position\n productVariant {\n id\n name\n sku\n }\n }\n }\n }\n";
41
+ /** `customers.savedLists`: see `CustomersModule.savedLists`. */
42
+ export declare function readCustomerSavedLists(transport: Transport, customerId: string, options: Call | undefined): Promise<CustomerSavedList[] | null>;
@@ -0,0 +1,61 @@
1
+ /**
2
+ * A customer's saved lists (headless W10-15, spec §9.2 `customers`): the named lists of products
3
+ * and quantities a shopper keeps on the storefront to order again. Read-only here: the shopper
4
+ * writes them through the Shop API, and the back office reads them on the customer's page.
5
+ */
6
+ import { UpstreamError } from '@sixtyninecommerce/core';
7
+ import { redactionWatcher } from '../customer-data-redaction.js';
8
+ /**
9
+ * The customer's own read (`customer(id) { id }`) beside the lists: the lists' door answers `[]`
10
+ * for an id the store does not hold, and only the customer read tells a customer with no lists
11
+ * apart from a customer the store does not hold.
12
+ */
13
+ export const CUSTOMER_SAVED_LISTS_QUERY = /* GraphQL */ `
14
+ query CustomerSavedLists($customerId: ID!) {
15
+ customer(id: $customerId) {
16
+ id
17
+ }
18
+ savedListsForCustomer(customerId: $customerId) {
19
+ id
20
+ name
21
+ createdAt
22
+ updatedAt
23
+ items {
24
+ id
25
+ productVariantId
26
+ quantity
27
+ position
28
+ productVariant {
29
+ id
30
+ name
31
+ sku
32
+ }
33
+ }
34
+ }
35
+ }
36
+ `;
37
+ /** `customers.savedLists`: see `CustomersModule.savedLists`. */
38
+ export async function readCustomerSavedLists(transport, customerId, options) {
39
+ const redaction = redactionWatcher();
40
+ const data = await transport.graphql({
41
+ api: 'admin',
42
+ query: CUSTOMER_SAVED_LISTS_QUERY,
43
+ variables: { customerId },
44
+ onExtensions: redaction.onExtensions,
45
+ }, options);
46
+ if (data === null || typeof data !== 'object' || !Array.isArray(data.savedListsForCustomer)) {
47
+ throw new UpstreamError({
48
+ code: 'UNEXPECTED_RESPONSE',
49
+ message: 'The engine answered without "savedListsForCustomer".',
50
+ status: 502,
51
+ service: 'vendure',
52
+ });
53
+ }
54
+ if (!data.customer)
55
+ return null;
56
+ return data.savedListsForCustomer.map((list) => redaction.mark({
57
+ ...list,
58
+ // The engine keeps no order on the items; the shopper's is `position`, then the id.
59
+ items: [...list.items].sort((a, b) => a.position - b.position || a.id.localeCompare(b.id)),
60
+ }));
61
+ }
@@ -0,0 +1,83 @@
1
+ /**
2
+ * A customer's VAT number, checked against the EU's VIES service (headless spec §9.2
3
+ * `customers` "VAT validation"; W10-33). The stored number and its standing verdict are on
4
+ * `customers.get(id, { include: ['customFields'] })`.
5
+ */
6
+ import type { Transport } from '@sixtyninecommerce/core';
7
+ import type { Call } from '../types.js';
8
+ /**
9
+ * How long {@link CustomerVatModule.validate} waits for the engine, which asks VIES up to three
10
+ * times (a 5 s limit each, with a pause between) before it answers.
11
+ */
12
+ export declare const VAT_VALIDATION_TIMEOUT_MS = 25000;
13
+ /**
14
+ * What a check of a VAT number found. Only `valid` and `invalid` say something about the
15
+ * number:
16
+ *
17
+ * - `valid`: VIES confirmed the number is registered.
18
+ * - `invalid`: VIES confirmed it is not, or the number failed a check before VIES was asked
19
+ * (too short, no EU member state's prefix); `error` then says which.
20
+ * - `pending`: VIES could not be reached or kept failing. The number was not checked: try
21
+ * again later.
22
+ * - `error`: VIES refused the lookup for a reason that will not pass by itself (`error`
23
+ * carries it). The number was not checked.
24
+ * - `none`: no verdict (never answered by a check).
25
+ */
26
+ export type VatValidationStatus = 'valid' | 'invalid' | 'pending' | 'error' | 'none';
27
+ export interface CustomerVatValidation {
28
+ status: VatValidationStatus | (string & {});
29
+ /** The number as checked, normalised (upper case, no spaces). */
30
+ vatNumber: string;
31
+ /**
32
+ * The country the number's two-letter prefix names (Greece's `EL` reads `GR`), whether or not
33
+ * it is an EU member state; "" for a number too short to have one.
34
+ */
35
+ countryCode: string;
36
+ /** The registered name VIES answered, when it shares one. */
37
+ companyName: string | null;
38
+ /** The registered address VIES answered, when it shares one. */
39
+ companyAddress: string | null;
40
+ /** ISO-8601 with offset; when VIES confirmed the number. */
41
+ validatedAt: string | null;
42
+ /** Why the number is `invalid`, or what stopped the check. */
43
+ error: string | null;
44
+ /**
45
+ * Set when the caller's customer-data level blanked the number, the name and the address (an
46
+ * app installation below `full`): "" or null then means "not granted".
47
+ */
48
+ redacted?: true;
49
+ }
50
+ export interface CustomerVatModule {
51
+ /**
52
+ * Check a VAT number with the EU's VIES service and store it on the customer with the
53
+ * verdict. Needs `UpdateCustomer`.
54
+ *
55
+ * **The verdict is `status`, never an error.** A number VIES does not know resolves
56
+ * `invalid`; a VIES that cannot be reached resolves `pending`, and one that refuses the lookup
57
+ * `error`, neither of which says anything about the number. The number and the verdict are
58
+ * stored either way, with one exception: `pending` or `error` for the number the customer
59
+ * already has as `valid` changes nothing, so an outage never downgrades a checked number.
60
+ *
61
+ * The call can take up to {@link VAT_VALIDATION_TIMEOUT_MS} (it waits that long instead of
62
+ * the client's own limit); pass `signal` to give up earlier.
63
+ *
64
+ * While an app or API token owns Customer details on the store, a number that differs from
65
+ * the stored one is refused `FIELD_GROUP_LOCKED` (`BusinessRuleError`); checking the stored
66
+ * number again passes. A customer this store does not hold is a `NotFoundError`
67
+ * (`ENTITY_NOT_FOUND`).
68
+ *
69
+ * @effect write
70
+ */
71
+ validate(customerId: string, vatNumber: string, options?: Call): Promise<CustomerVatValidation>;
72
+ /**
73
+ * Remove the customer's VAT number and its verdict. Needs `UpdateCustomer`. Refused
74
+ * `FIELD_GROUP_LOCKED` like {@link validate} while the customer has a number; a customer this
75
+ * store does not hold is a `NotFoundError` (`ENTITY_NOT_FOUND`).
76
+ *
77
+ * @effect write
78
+ */
79
+ clear(customerId: string, options?: Call): Promise<void>;
80
+ }
81
+ export declare const VALIDATE_VAT_MUTATION = "\n mutation ValidateCustomerVatNumber($customerId: ID!, $vatNumber: String!) {\n validateCustomerVatNumber(customerId: $customerId, vatNumber: $vatNumber) {\n status\n vatNumber\n countryCode\n companyName\n companyAddress\n validatedAt\n error\n }\n }\n";
82
+ export declare const CLEAR_VAT_MUTATION = "\n mutation ClearCustomerVatNumber($customerId: ID!) {\n clearCustomerVatNumber(customerId: $customerId)\n }\n";
83
+ export declare function createCustomerVatModule(transport: Transport): CustomerVatModule;
@@ -0,0 +1,46 @@
1
+ import { fieldOf } from '../catalog/types.js';
2
+ import { customerDataField } from './wire.js';
3
+ /**
4
+ * How long {@link CustomerVatModule.validate} waits for the engine, which asks VIES up to three
5
+ * times (a 5 s limit each, with a pause between) before it answers.
6
+ */
7
+ export const VAT_VALIDATION_TIMEOUT_MS = 25_000;
8
+ export const VALIDATE_VAT_MUTATION = /* GraphQL */ `
9
+ mutation ValidateCustomerVatNumber($customerId: ID!, $vatNumber: String!) {
10
+ validateCustomerVatNumber(customerId: $customerId, vatNumber: $vatNumber) {
11
+ status
12
+ vatNumber
13
+ countryCode
14
+ companyName
15
+ companyAddress
16
+ validatedAt
17
+ error
18
+ }
19
+ }
20
+ `;
21
+ export const CLEAR_VAT_MUTATION = /* GraphQL */ `
22
+ mutation ClearCustomerVatNumber($customerId: ID!) {
23
+ clearCustomerVatNumber(customerId: $customerId)
24
+ }
25
+ `;
26
+ export function createCustomerVatModule(transport) {
27
+ return {
28
+ async validate(customerId, vatNumber, options) {
29
+ const { value, mark } = await customerDataField(transport, VALIDATE_VAT_MUTATION, 'validateCustomerVatNumber', { customerId, vatNumber },
30
+ // The method's own limit: the transport's default would give up before VIES answers.
31
+ { ...options, timeoutMs: VAT_VALIDATION_TIMEOUT_MS });
32
+ return mark({
33
+ status: value.status,
34
+ vatNumber: value.vatNumber,
35
+ countryCode: value.countryCode,
36
+ companyName: value.companyName ?? null,
37
+ companyAddress: value.companyAddress ?? null,
38
+ validatedAt: value.validatedAt ?? null,
39
+ error: value.error ?? null,
40
+ });
41
+ },
42
+ async clear(customerId, options) {
43
+ await fieldOf(transport, CLEAR_VAT_MUTATION, 'clearCustomerVatNumber', { customerId }, options);
44
+ },
45
+ };
46
+ }
@@ -0,0 +1,20 @@
1
+ import { type CallOptions, type Transport } from '@sixtyninecommerce/core';
2
+ import { redactionWatcher } from '../customer-data-redaction.js';
3
+ /**
4
+ * One Admin API document's single root field, with the call's customer-data watcher: `mark`
5
+ * stamps `redacted: true` on a record of the answer when the caller's level blanked anything in
6
+ * it (an app installation below `customerData: full`). An absent field is refused, as
7
+ * `fieldOf` refuses it; a null one is a real answer.
8
+ */
9
+ export declare function customerDataField<T>(transport: Transport, document: string, field: string, variables: Record<string, unknown>, options: CallOptions | undefined): Promise<{
10
+ value: T;
11
+ mark: ReturnType<typeof redactionWatcher>['mark'];
12
+ }>;
13
+ /** The company flags of one address, as a list row carries them. */
14
+ export interface CustomerAddressSummary {
15
+ company: string | null;
16
+ defaultBillingAddress: boolean | null;
17
+ defaultShippingAddress: boolean | null;
18
+ }
19
+ /** The company a list shows for a customer, by the dashboard's own rule (`customerCompanyOf`). */
20
+ export declare function companyOf(addresses: readonly CustomerAddressSummary[]): string | null;
@@ -0,0 +1,35 @@
1
+ import { UpstreamError } from '@sixtyninecommerce/core';
2
+ import { redactionWatcher } from '../customer-data-redaction.js';
3
+ /**
4
+ * One Admin API document's single root field, with the call's customer-data watcher: `mark`
5
+ * stamps `redacted: true` on a record of the answer when the caller's level blanked anything in
6
+ * it (an app installation below `customerData: full`). An absent field is refused, as
7
+ * `fieldOf` refuses it; a null one is a real answer.
8
+ */
9
+ export async function customerDataField(transport, document, field, variables, options) {
10
+ const redaction = redactionWatcher();
11
+ const data = await transport.graphql({ api: 'admin', query: document, variables, onExtensions: redaction.onExtensions }, options);
12
+ if (data === null || typeof data !== 'object' || !Object.hasOwn(data, field)) {
13
+ throw new UpstreamError({
14
+ code: 'UNEXPECTED_RESPONSE',
15
+ message: `The engine answered without "${field}".`,
16
+ status: 502,
17
+ service: 'vendure',
18
+ });
19
+ }
20
+ return { value: data[field], mark: redaction.mark };
21
+ }
22
+ /** The company a list shows for a customer, by the dashboard's own rule (`customerCompanyOf`). */
23
+ export function companyOf(addresses) {
24
+ const candidates = [
25
+ addresses.find((address) => address.defaultBillingAddress === true),
26
+ addresses.find((address) => address.defaultShippingAddress === true),
27
+ ...addresses,
28
+ ];
29
+ for (const address of candidates) {
30
+ const company = address?.company?.trim();
31
+ if (company)
32
+ return company;
33
+ }
34
+ return null;
35
+ }