@sixtyninecommerce/admin 0.8.0 → 0.10.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 (179) hide show
  1. package/README.md +2739 -17
  2. package/dist/api-tokens/index.d.ts +15 -5
  3. package/dist/api-tokens/index.js +1 -0
  4. package/dist/apps/event-subscription.d.ts +59 -0
  5. package/dist/apps/event-subscription.js +32 -0
  6. package/dist/apps/hook-secret.d.ts +22 -0
  7. package/dist/apps/hook-secret.js +36 -0
  8. package/dist/apps/index.d.ts +54 -3
  9. package/dist/apps/index.js +17 -0
  10. package/dist/audit/index.d.ts +7 -0
  11. package/dist/auth/queries.d.ts +5 -1
  12. package/dist/auth/queries.js +6 -0
  13. package/dist/bulk/index.d.ts +323 -0
  14. package/dist/bulk/index.js +162 -0
  15. package/dist/catalog/assets.d.ts +147 -0
  16. package/dist/catalog/assets.js +164 -0
  17. package/dist/catalog/collections.d.ts +109 -0
  18. package/dist/catalog/collections.js +91 -0
  19. package/dist/catalog/facets.d.ts +103 -0
  20. package/dist/catalog/facets.js +100 -0
  21. package/dist/catalog/index.d.ts +115 -0
  22. package/dist/catalog/index.js +21 -0
  23. package/dist/catalog/options.d.ts +89 -0
  24. package/dist/catalog/options.js +88 -0
  25. package/dist/catalog/products-bulk.d.ts +21 -0
  26. package/dist/catalog/products-bulk.js +58 -0
  27. package/dist/catalog/products.d.ts +650 -0
  28. package/dist/catalog/products.js +458 -0
  29. package/dist/catalog/properties.d.ts +234 -0
  30. package/dist/catalog/properties.js +158 -0
  31. package/dist/catalog/types.d.ts +174 -0
  32. package/dist/catalog/types.js +141 -0
  33. package/dist/catalog/variants.d.ts +324 -0
  34. package/dist/catalog/variants.js +288 -0
  35. package/dist/catalog/visibility.d.ts +57 -0
  36. package/dist/catalog/visibility.js +59 -0
  37. package/dist/client.d.ts +192 -3
  38. package/dist/client.js +87 -12
  39. package/dist/compliance/index.d.ts +88 -0
  40. package/dist/compliance/index.js +88 -0
  41. package/dist/customer-data-redaction.d.ts +14 -0
  42. package/dist/customer-data-redaction.js +22 -0
  43. package/dist/customers/index.d.ts +428 -17
  44. package/dist/customers/index.js +322 -15
  45. package/dist/documents/index.d.ts +513 -16
  46. package/dist/documents/index.js +229 -3
  47. package/dist/events/index.d.ts +259 -0
  48. package/dist/events/index.js +147 -0
  49. package/dist/feeds/ai.d.ts +46 -0
  50. package/dist/feeds/ai.js +43 -0
  51. package/dist/feeds/categories.d.ts +50 -0
  52. package/dist/feeds/categories.js +56 -0
  53. package/dist/feeds/configs.d.ts +54 -0
  54. package/dist/feeds/configs.js +85 -0
  55. package/dist/feeds/identifier-fields.d.ts +25 -0
  56. package/dist/feeds/identifier-fields.js +29 -0
  57. package/dist/feeds/index.d.ts +54 -0
  58. package/dist/feeds/index.js +46 -0
  59. package/dist/feeds/preserve.d.ts +38 -0
  60. package/dist/feeds/preserve.js +74 -0
  61. package/dist/feeds/rules.d.ts +42 -0
  62. package/dist/feeds/rules.js +56 -0
  63. package/dist/feeds/types.d.ts +654 -0
  64. package/dist/feeds/types.js +135 -0
  65. package/dist/fulfillments/index.d.ts +437 -0
  66. package/dist/fulfillments/index.js +534 -0
  67. package/dist/heads/index.d.ts +60 -0
  68. package/dist/heads/index.js +45 -0
  69. package/dist/hooks/assignments.d.ts +90 -0
  70. package/dist/hooks/assignments.js +53 -0
  71. package/dist/hooks/index.d.ts +97 -0
  72. package/dist/hooks/index.js +76 -0
  73. package/dist/index.d.ts +95 -9
  74. package/dist/index.js +21 -1
  75. package/dist/integrations/index.d.ts +14 -0
  76. package/dist/integrations/index.js +9 -0
  77. package/dist/integrations/pipelines.d.ts +113 -0
  78. package/dist/integrations/pipelines.js +62 -0
  79. package/dist/integrations/types.d.ts +176 -0
  80. package/dist/integrations/types.js +8 -0
  81. package/dist/jobs/bulk-action-run.d.ts +74 -0
  82. package/dist/jobs/bulk-action-run.js +69 -0
  83. package/dist/locations/index.d.ts +6 -2
  84. package/dist/meta/index.d.ts +32 -0
  85. package/dist/orders/bulk.d.ts +75 -0
  86. package/dist/orders/bulk.js +150 -0
  87. package/dist/orders/commit-edit.d.ts +123 -0
  88. package/dist/orders/commit-edit.js +142 -0
  89. package/dist/orders/deposit-policy.d.ts +103 -0
  90. package/dist/orders/deposit-policy.js +202 -0
  91. package/dist/orders/get.d.ts +722 -0
  92. package/dist/orders/get.js +530 -0
  93. package/dist/orders/index.d.ts +186 -21
  94. package/dist/orders/index.js +57 -0
  95. package/dist/orders/line-price-preview.d.ts +297 -0
  96. package/dist/orders/line-price-preview.js +50 -0
  97. package/dist/orders/manual-discounts.d.ts +141 -0
  98. package/dist/orders/manual-discounts.js +97 -0
  99. package/dist/orders/manual-pricing.d.ts +192 -0
  100. package/dist/orders/manual-pricing.js +72 -0
  101. package/dist/orders/order-entry.d.ts +566 -0
  102. package/dist/orders/order-entry.js +129 -0
  103. package/dist/orders/parcel-charge.d.ts +45 -0
  104. package/dist/orders/parcel-charge.js +55 -0
  105. package/dist/orders/plan-edit.d.ts +489 -0
  106. package/dist/orders/plan-edit.js +93 -0
  107. package/dist/orders/status.d.ts +235 -0
  108. package/dist/orders/status.js +96 -0
  109. package/dist/orders/surcharges.d.ts +75 -2
  110. package/dist/orders/surcharges.js +110 -4
  111. package/dist/payments/account-credit.d.ts +171 -0
  112. package/dist/payments/account-credit.js +107 -0
  113. package/dist/payments/index.d.ts +241 -9
  114. package/dist/payments/index.js +92 -0
  115. package/dist/payments/methods.d.ts +37 -0
  116. package/dist/payments/methods.js +33 -0
  117. package/dist/platform/catalog.d.ts +148 -0
  118. package/dist/platform/catalog.js +74 -0
  119. package/dist/platform/entitlements.d.ts +111 -0
  120. package/dist/platform/entitlements.js +86 -0
  121. package/dist/platform/legal-entities.d.ts +139 -0
  122. package/dist/platform/legal-entities.js +126 -0
  123. package/dist/platform/legal-entity-numbering.d.ts +103 -0
  124. package/dist/platform/legal-entity-numbering.js +101 -0
  125. package/dist/platform/organization-membership.d.ts +80 -0
  126. package/dist/platform/organization-membership.js +71 -0
  127. package/dist/platform/organization-settings.d.ts +33 -0
  128. package/dist/platform/organization-settings.js +42 -0
  129. package/dist/platform/organization-sharing.d.ts +172 -0
  130. package/dist/platform/organization-sharing.js +120 -0
  131. package/dist/platform/organizations.d.ts +205 -0
  132. package/dist/platform/organizations.js +180 -0
  133. package/dist/platform/provision-store.d.ts +88 -8
  134. package/dist/platform/provision-store.js +12 -0
  135. package/dist/platform/reports.d.ts +46 -0
  136. package/dist/platform/reports.js +31 -0
  137. package/dist/platform/server-metrics.d.ts +58 -0
  138. package/dist/platform/server-metrics.js +11 -0
  139. package/dist/pos/index.d.ts +567 -0
  140. package/dist/pos/index.js +205 -0
  141. package/dist/pricing/index.d.ts +408 -0
  142. package/dist/pricing/index.js +353 -0
  143. package/dist/pricing/vouchers.d.ts +103 -0
  144. package/dist/pricing/vouchers.js +69 -0
  145. package/dist/provenance/index.d.ts +93 -0
  146. package/dist/provenance/index.js +53 -0
  147. package/dist/reports/index.d.ts +199 -0
  148. package/dist/reports/index.js +154 -0
  149. package/dist/returns/index.d.ts +225 -0
  150. package/dist/returns/index.js +160 -0
  151. package/dist/search/index.d.ts +99 -0
  152. package/dist/search/index.js +62 -0
  153. package/dist/shipping/parcel-count-suggestion.d.ts +52 -0
  154. package/dist/shipping/parcel-count-suggestion.js +73 -0
  155. package/dist/shipping/parcel-rule.d.ts +48 -0
  156. package/dist/shipping/parcel-rule.js +91 -0
  157. package/dist/stock/index.d.ts +166 -0
  158. package/dist/stock/index.js +115 -0
  159. package/dist/stock/transfers.d.ts +520 -0
  160. package/dist/stock/transfers.js +437 -0
  161. package/dist/stored-value/index.d.ts +154 -0
  162. package/dist/stored-value/index.js +130 -0
  163. package/dist/tenant/capabilities.d.ts +10 -0
  164. package/dist/tenant/entitlements.d.ts +35 -0
  165. package/dist/tenant/entitlements.js +15 -0
  166. package/dist/tenant/field-groups.d.ts +64 -0
  167. package/dist/tenant/field-groups.js +34 -0
  168. package/dist/tenant/legal-entity.d.ts +32 -0
  169. package/dist/tenant/legal-entity.js +41 -0
  170. package/dist/tenant/notifications.d.ts +148 -0
  171. package/dist/tenant/notifications.js +79 -0
  172. package/dist/tenant/retention.d.ts +10 -4
  173. package/dist/tenant/settings-sources.d.ts +103 -0
  174. package/dist/tenant/settings-sources.js +92 -0
  175. package/dist/types.d.ts +86 -11
  176. package/dist/uploads/index.d.ts +11 -7
  177. package/dist/users/index.d.ts +104 -0
  178. package/dist/users/index.js +80 -0
  179. package/package.json +3 -2
@@ -0,0 +1,150 @@
1
+ /**
2
+ * `admin.orders.bulk`, `admin.orders.bulkRun` and `admin.orders.delete` (headless spec §7
3
+ * `orders.bulk`, plan W9-43; rulings G19, G28, G29).
4
+ */
5
+ import { idempotencyKey, ValidationError } from '@sixtyninecommerce/core';
6
+ import { assertDeleted, fieldOf } from '../catalog/types.js';
7
+ import { bulkActionHandle, } from '../jobs/bulk-action-run.js';
8
+ export const ORDER_BULK_ACTIONS = [
9
+ 'TRANSITION',
10
+ 'CANCEL',
11
+ 'DELETE',
12
+ 'MARK_PAID',
13
+ ];
14
+ /** The engine's bound on one bulk run (`MAX_BULK_ACTION_ITEMS`). Split a larger selection. */
15
+ export const MAX_BULK_ORDERS = 50;
16
+ /**
17
+ * The states a TRANSITION never names, each with its own action or door: `Cancelled` (CANCEL),
18
+ * `PaymentSettled` (MARK_PAID), `Modifying` (the order edit) and `AddingItems`.
19
+ */
20
+ export const ORDER_BULK_TRANSITION_REFUSED = [
21
+ 'Cancelled',
22
+ 'PaymentSettled',
23
+ 'Modifying',
24
+ 'AddingItems',
25
+ ];
26
+ export const BULK_ORDER_ACTION_MUTATION = /* GraphQL */ `
27
+ mutation BulkOrderAction($input: BulkOrderActionInput!, $idempotencyKey: String) {
28
+ bulkOrderAction(input: $input, idempotencyKey: $idempotencyKey) {
29
+ runId
30
+ }
31
+ }
32
+ `;
33
+ /**
34
+ * The run read with the order fields. Its own document, so `catalog.products.bulkRun` keeps
35
+ * selecting only what an engine without the orders kind has.
36
+ */
37
+ export const ORDER_BULK_RUN_QUERY = /* GraphQL */ `
38
+ query OrderBulkRun($runId: ID!) {
39
+ bulkActionRun(runId: $runId) {
40
+ id
41
+ kind
42
+ action
43
+ status
44
+ total
45
+ done
46
+ items {
47
+ id
48
+ status
49
+ code
50
+ message
51
+ newId
52
+ reasonCode
53
+ captured {
54
+ paymentId
55
+ state
56
+ code
57
+ message
58
+ }
59
+ }
60
+ failure {
61
+ code
62
+ message
63
+ }
64
+ }
65
+ }
66
+ `;
67
+ export const DELETE_ORDER_MUTATION = /* GraphQL */ `
68
+ mutation DeleteOrder($orderId: ID!) {
69
+ deleteOrder(orderId: $orderId) {
70
+ result
71
+ message
72
+ }
73
+ }
74
+ `;
75
+ function refuse(message) {
76
+ return new ValidationError({
77
+ code: 'BULK_ACTION_INPUT_INVALID',
78
+ message,
79
+ status: 400,
80
+ service: 'vendure',
81
+ });
82
+ }
83
+ /** The engine's own checks of a submit (`BULK_ACTION_INPUT_INVALID`), before sending. */
84
+ function assertBulkInput(input) {
85
+ if (!ORDER_BULK_ACTIONS.includes(input?.action)) {
86
+ throw refuse(`"${String(input?.action)}" is not a bulk order action: ${ORDER_BULK_ACTIONS.join(', ')}. Nothing was sent.`);
87
+ }
88
+ const ids = input.orderIds;
89
+ if (!Array.isArray(ids) || ids.length === 0) {
90
+ throw refuse('Name at least one order. Nothing was sent.');
91
+ }
92
+ if (ids.length > MAX_BULK_ORDERS) {
93
+ throw refuse(`Name at most ${String(MAX_BULK_ORDERS)} orders in one bulk action; this one named ${String(ids.length)}. Split the selection into several actions. Nothing was sent.`);
94
+ }
95
+ if (new Set(ids.map((id) => String(id).toLowerCase())).size !== ids.length) {
96
+ throw refuse('The selection names an order more than once. Name each order once. Nothing was sent.');
97
+ }
98
+ const toState = input.toState?.trim() ?? '';
99
+ if (input.action === 'TRANSITION') {
100
+ if (toState === '')
101
+ throw refuse('Name the status to move the orders to. Nothing was sent.');
102
+ if (ORDER_BULK_TRANSITION_REFUSED.includes(toState)) {
103
+ throw refuse(`Orders are not moved to "${toState}" by a status change${toState === 'Cancelled'
104
+ ? ': use CANCEL'
105
+ : toState === 'PaymentSettled'
106
+ ? ': use MARK_PAID'
107
+ : ''}. Nothing was sent.`);
108
+ }
109
+ }
110
+ else if (toState !== '') {
111
+ throw refuse(`toState is only for TRANSITION, not ${input.action}. Nothing was sent.`);
112
+ }
113
+ if ((input.reason?.trim() ?? '') !== '' && input.action !== 'CANCEL') {
114
+ throw refuse(`reason is only for CANCEL, not ${input.action}. Nothing was sent.`);
115
+ }
116
+ }
117
+ /** One read of a bulk order run. A run of another store, or a missing one, is `NotFoundError`. */
118
+ export function readOrderBulkRun(transport, runId, options) {
119
+ return fieldOf(transport, ORDER_BULK_RUN_QUERY, 'bulkActionRun', { runId }, options);
120
+ }
121
+ /** `orders.bulk`; see `OrdersModule.bulk`. */
122
+ export async function bulkOrders(transport, input, options) {
123
+ assertBulkInput(input);
124
+ // Minted when the caller gave none, so a retry of THIS call answers the same run instead of
125
+ // starting a second one (and capturing nothing twice).
126
+ const key = options?.idempotencyKey ?? idempotencyKey();
127
+ const toState = input.toState?.trim();
128
+ const reason = input.reason?.trim();
129
+ const { runId } = await fieldOf(transport, BULK_ORDER_ACTION_MUTATION, 'bulkOrderAction', {
130
+ input: {
131
+ action: input.action,
132
+ orderIds: [...input.orderIds],
133
+ // Omitted, never null, when not given: an absent option stays off the wire.
134
+ ...(toState ? { toState } : {}),
135
+ ...(reason ? { reason } : {}),
136
+ },
137
+ idempotencyKey: key,
138
+ }, { ...options, idempotencyKey: key });
139
+ return bulkActionHandle(transport, runId, options, (id, call) => readOrderBulkRun(transport, id, call));
140
+ }
141
+ /**
142
+ * `orders.delete`; see `OrdersModule.delete`. The engine's `NOT_DELETED` is raised as every other
143
+ * `*_NOT_DELETED` refusal of this SDK is (`assertDeleted`): a `ConflictError` with the engine's own
144
+ * reason.
145
+ */
146
+ export async function deleteOrder(transport, orderId, options) {
147
+ assertDeleted('ORDER_NOT_DELETED', [
148
+ await fieldOf(transport, DELETE_ORDER_MUTATION, 'deleteOrder', { orderId }, options),
149
+ ]);
150
+ }
@@ -0,0 +1,123 @@
1
+ import { type Transport } from '@sixtyninecommerce/core';
2
+ import type { Call } from '../types.js';
3
+ import type { OrderEditDiff, OrderEditPlan } from './plan-edit.js';
4
+ import type { OrderOverpaymentChoice } from './surcharges.js';
5
+ /** The order as a committed edit left it: what a head refreshes its view from. */
6
+ export interface OrderEditCommittedOrder {
7
+ id: string;
8
+ code: string;
9
+ /** The order's state: for an edit that raised a paid order's total online, `ArrangingAdditionalPayment`. */
10
+ state: string;
11
+ currencyCode: string;
12
+ /** Minor units. */
13
+ totalWithTax: number;
14
+ }
15
+ /** The refund an edit ended with. */
16
+ export interface OrderEditCommittedRefund {
17
+ id: string;
18
+ /**
19
+ * The payment provider's answer: `Pending` until a gateway confirms it, `Settled` for money
20
+ * returned by hand (an offline method). `Failed` is never answered here: a refusal throws.
21
+ */
22
+ state: string;
23
+ /** Minor units, as the refund row records it. */
24
+ total: number;
25
+ paymentId: string;
26
+ }
27
+ /** How the edit settled its plan's `overpayment`. */
28
+ export interface OrderEditOverpaymentSettlement {
29
+ choice: OrderOverpaymentChoice;
30
+ /** Minor units the choice settled: the plan's `overpayment.amount`. */
31
+ amount: number;
32
+ currencyCode: string;
33
+ /** For `ACCOUNT_CREDIT`: the receipts on the customer's account, one per payment it came from. */
34
+ unappliedCashIds: string[];
35
+ }
36
+ export interface OrderEditCommit {
37
+ order: OrderEditCommittedOrder;
38
+ /**
39
+ * The plan that was carried out, as `planEdit` answered it. A repeat under the same
40
+ * `idempotencyKey` answers the plan as it was, and the order and refund as they are now.
41
+ */
42
+ plan: OrderEditPlan;
43
+ /**
44
+ * The ONE refund the edit ended with, made last, or `null`: the plan's `refund`, or with
45
+ * `overpaymentChoice: 'REFUND'` its `overpayment.refundWhenChosen`.
46
+ */
47
+ refund: OrderEditCommittedRefund | null;
48
+ /** How the plan's `overpayment` was settled; `null` when it had none. */
49
+ overpayment: OrderEditOverpaymentSettlement | null;
50
+ }
51
+ export interface CommitOrderEditCall extends Call {
52
+ /** The `planHash` of the plan the merchant saw (`planEdit`). Required. */
53
+ expectedPlanHash: string;
54
+ /**
55
+ * One key per attempt to save, re-sent unchanged on a retry of THAT attempt. Pass your own:
56
+ * left out, one is made up (a UUIDv7) and returned as `idempotencyKey` on the result, but on a
57
+ * thrown error only as an untyped own property of the error. Never reuse a key for a
58
+ * different edit or a fresh attempt.
59
+ */
60
+ idempotencyKey?: string;
61
+ /**
62
+ * How the merchant settles the plan's `overpayment` (a surcharge lowered or removed on a paid
63
+ * order): `REFUND` returns it to the customer's payment in the same one refund as the plan's
64
+ * `refund`; `ACCOUNT_CREDIT` credits it to the customer's account first, and the plan's
65
+ * `refund` follows. Required when the plan has an `overpayment`; ignored when it has none.
66
+ * Part of the request: a retry under the same key re-sends the same choice.
67
+ */
68
+ overpaymentChoice?: OrderOverpaymentChoice;
69
+ }
70
+ /**
71
+ * Its own document on purpose: `commitOrderEdit` exists only on an engine with the order-edit
72
+ * commit, so on an older one this call alone fails validation and no other order call does.
73
+ */
74
+ export declare const COMMIT_ORDER_EDIT_MUTATION = "\n mutation CommitOrderEdit(\n $orderId: ID!\n $diff: OrderEditDiffInput!\n $expectedPlanHash: String!\n $idempotencyKey: String!\n $overpaymentChoice: OrderOverpaymentChoice\n ) {\n commitOrderEdit(\n orderId: $orderId\n diff: $diff\n expectedPlanHash: $expectedPlanHash\n idempotencyKey: $idempotencyKey\n overpaymentChoice: $overpaymentChoice\n ) {\n order {\n id\n code\n state\n currencyCode\n totalWithTax\n }\n plan {\n orderId\n planHash\n orderVersion\n steps {\n kind\n input\n moneyEffect\n }\n refund {\n paymentId\n amount\n }\n overpayment {\n amount\n currencyCode\n surchargeIds\n refund {\n available\n code\n message\n }\n accountCredit {\n available\n code\n message\n }\n refundWhenChosen {\n paymentId\n amount\n }\n }\n returnState\n blockers {\n code\n message\n details\n }\n notices {\n code\n message\n details\n }\n payment {\n collected\n reason\n method\n }\n preview {\n currencyCode\n subTotal\n subTotalWithTax\n shipping\n shippingWithTax\n surcharges\n surchargesWithTax\n total\n totalWithTax\n taxSummary {\n description\n taxRate\n taxBase\n taxTotal\n }\n totalWithTaxBefore\n }\n }\n refund {\n id\n state\n total\n paymentId\n }\n overpayment {\n choice\n amount\n currencyCode\n unappliedCashIds\n }\n }\n }\n";
75
+ export interface OrderCommitEditModule {
76
+ /**
77
+ * Carry out an edit of a placed order as its plan (`planEdit`) states it, once. Needs
78
+ * `UpdateOrder`, and an engine that serves `commitOrderEdit`.
79
+ *
80
+ * Hand it the SAME `diff` you planned and the plan's `planHash` as `expectedPlanHash`. The
81
+ * engine runs the plan again inside one transaction and keeps that run only when its hash is
82
+ * yours and it has no blockers; otherwise nothing of the edit is saved. The plan's refund, if
83
+ * it has one, is made LAST, after every other step, through the platform's refund guard.
84
+ *
85
+ * When the plan has an `overpayment` (a surcharge lowered or removed on a paid order), pass the
86
+ * merchant's `overpaymentChoice`: `REFUND` makes the plan's `overpayment.refundWhenChosen`
87
+ * (one refund of both parts); `ACCOUNT_CREDIT` credits the share to the customer's account,
88
+ * then makes the plan's `refund`.
89
+ *
90
+ * `idempotencyKey`: one per attempt to save. A retry of that attempt (a timeout, a dropped
91
+ * connection) re-sends it and gets the first answer back, with nothing done twice. Left out,
92
+ * one is made up and returned as `idempotencyKey` on the result and on a thrown error.
93
+ *
94
+ * Refusals, with nothing saved:
95
+ * - `ORDER_EDIT_PLAN_CONFLICT` (`ConflictError`, 409): the order changed since the plan (another
96
+ * change landed, a price or tax answer moved). Plan again, show the merchant the new totals,
97
+ * and save under a NEW key.
98
+ * - `ORDER_EDIT_BLOCKED` (`BusinessRuleError`, 422): the plan has blockers; `error.details`
99
+ * lists them, `code` = the blocker's code.
100
+ * - `ORDER_BUSY` (`ConflictError`, 409): another change of the order was being applied. Retry
101
+ * under the same key.
102
+ * - `ORDER_EDIT_OVERPAYMENT_CHOICE_REQUIRED` (`BusinessRuleError`, 422): the plan has an
103
+ * `overpayment` and no `overpaymentChoice` was given. Ask the merchant, then save under a
104
+ * NEW key (the choice is part of the request).
105
+ * - A closed option chosen anyway: its own refusal (`REFUND_EXCEEDS_PAYMENT`,
106
+ * `REFUND_METHOD_UNAVAILABLE`, `AR_ACCOUNT_IN_ERP`, `AR_LEDGER_NOT_ENABLED`, …), as the
107
+ * plan's option names it.
108
+ * - `IDEMPOTENCY_CONFLICT` (409): the key was used for another request.
109
+ * - `planEdit`'s refusals of the call, and the refund guard's `REFUND_*` when the refund was
110
+ * refused before money moved.
111
+ *
112
+ * `IDEMPOTENCY_OUTCOME_UNKNOWN` (`error.outcomeUnknown`): the refund reached the payment
113
+ * provider and its answer never came. The edit is NOT saved; the refund attempt is recorded
114
+ * and reserved on the order, and this key answers the same until the provider's answer is
115
+ * recorded (`admin.payments.reconcileRefund`), which frees it. Until then an edit that gives
116
+ * money back is blocked (`ORDER_OVERPAYMENT_REFUND_UNRECONCILED`). Then plan and save again:
117
+ * a refund recorded as made is not made a second time.
118
+ */
119
+ commitEdit(orderId: string, diff: OrderEditDiff, options: CommitOrderEditCall): Promise<OrderEditCommit & {
120
+ idempotencyKey: string;
121
+ }>;
122
+ }
123
+ export declare function createOrderCommitEditModule(transport: Transport): OrderCommitEditModule;
@@ -0,0 +1,142 @@
1
+ import { idempotencyKey as mintIdempotencyKey } from '@sixtyninecommerce/core';
2
+ /**
3
+ * Its own document on purpose: `commitOrderEdit` exists only on an engine with the order-edit
4
+ * commit, so on an older one this call alone fails validation and no other order call does.
5
+ */
6
+ export const COMMIT_ORDER_EDIT_MUTATION = /* GraphQL */ `
7
+ mutation CommitOrderEdit(
8
+ $orderId: ID!
9
+ $diff: OrderEditDiffInput!
10
+ $expectedPlanHash: String!
11
+ $idempotencyKey: String!
12
+ $overpaymentChoice: OrderOverpaymentChoice
13
+ ) {
14
+ commitOrderEdit(
15
+ orderId: $orderId
16
+ diff: $diff
17
+ expectedPlanHash: $expectedPlanHash
18
+ idempotencyKey: $idempotencyKey
19
+ overpaymentChoice: $overpaymentChoice
20
+ ) {
21
+ order {
22
+ id
23
+ code
24
+ state
25
+ currencyCode
26
+ totalWithTax
27
+ }
28
+ plan {
29
+ orderId
30
+ planHash
31
+ orderVersion
32
+ steps {
33
+ kind
34
+ input
35
+ moneyEffect
36
+ }
37
+ refund {
38
+ paymentId
39
+ amount
40
+ }
41
+ overpayment {
42
+ amount
43
+ currencyCode
44
+ surchargeIds
45
+ refund {
46
+ available
47
+ code
48
+ message
49
+ }
50
+ accountCredit {
51
+ available
52
+ code
53
+ message
54
+ }
55
+ refundWhenChosen {
56
+ paymentId
57
+ amount
58
+ }
59
+ }
60
+ returnState
61
+ blockers {
62
+ code
63
+ message
64
+ details
65
+ }
66
+ notices {
67
+ code
68
+ message
69
+ details
70
+ }
71
+ payment {
72
+ collected
73
+ reason
74
+ method
75
+ }
76
+ preview {
77
+ currencyCode
78
+ subTotal
79
+ subTotalWithTax
80
+ shipping
81
+ shippingWithTax
82
+ surcharges
83
+ surchargesWithTax
84
+ total
85
+ totalWithTax
86
+ taxSummary {
87
+ description
88
+ taxRate
89
+ taxBase
90
+ taxTotal
91
+ }
92
+ totalWithTaxBefore
93
+ }
94
+ }
95
+ refund {
96
+ id
97
+ state
98
+ total
99
+ paymentId
100
+ }
101
+ overpayment {
102
+ choice
103
+ amount
104
+ currencyCode
105
+ unappliedCashIds
106
+ }
107
+ }
108
+ }
109
+ `;
110
+ export function createOrderCommitEditModule(transport) {
111
+ return {
112
+ async commitEdit(orderId, diff, options) {
113
+ const key = options.idempotencyKey ?? mintIdempotencyKey();
114
+ try {
115
+ const data = await transport.graphql({
116
+ api: 'admin',
117
+ query: COMMIT_ORDER_EDIT_MUTATION,
118
+ // The diff goes out as given, never normalised (see `planEdit`): left out, `null` and
119
+ // a value are three different requests.
120
+ variables: {
121
+ orderId,
122
+ diff,
123
+ expectedPlanHash: options.expectedPlanHash,
124
+ idempotencyKey: key,
125
+ // Sent only when given: left out, the engine reads no choice.
126
+ ...(options.overpaymentChoice !== undefined
127
+ ? { overpaymentChoice: options.overpaymentChoice }
128
+ : {}),
129
+ },
130
+ }, { ...options, idempotencyKey: key });
131
+ return { ...data.commitOrderEdit, idempotencyKey: key };
132
+ }
133
+ catch (error) {
134
+ // The key the caller retries under, when it did not choose one.
135
+ if (error !== null && typeof error === 'object' && !('idempotencyKey' in error)) {
136
+ Object.defineProperty(error, 'idempotencyKey', { value: key, enumerable: true });
137
+ }
138
+ throw error;
139
+ }
140
+ },
141
+ };
142
+ }
@@ -0,0 +1,103 @@
1
+ import { type Transport } from '@sixtyninecommerce/core';
2
+ import type { Call } from '../types.js';
3
+ /** The fewest days `autoCancelAfterDays` may be; `null` means never. */
4
+ export declare const DEPOSIT_POLICY_AUTO_CANCEL_DAYS_MIN = 1;
5
+ /** The largest `storefront.minimumPercent`: a whole percentage of the order total. */
6
+ export declare const DEPOSIT_POLICY_MINIMUM_PERCENT_MAX = 100;
7
+ /** The most payment method codes `storefront.methods` may name. */
8
+ export declare const DEPOSIT_POLICY_STOREFRONT_METHODS_MAX = 50;
9
+ /** Deposits a SHOPPER pays online at checkout. Applies only while `enabled` is on as well. */
10
+ export interface StorefrontDepositPolicy {
11
+ /** The online switch. */
12
+ enabled: boolean;
13
+ /**
14
+ * Payment method CODES a shopper may pay a deposit with: offline methods and
15
+ * Mollie. Empty: none, so no shopper can pay a deposit online.
16
+ */
17
+ methods: string[];
18
+ /**
19
+ * The least an online deposit may be, as a whole percentage (0–100) of the
20
+ * order's total, judged in the order's currency. Beside `minimum`, not instead
21
+ * of it: the larger of the two applies.
22
+ */
23
+ minimumPercent: number;
24
+ }
25
+ /**
26
+ * The store's deposit policy (`Channel.customFields.orderDepositPolicy`): whether
27
+ * staff may take a deposit and park an order (`orders.park`), and whether a
28
+ * shopper may pay one at checkout. Every field present: this is what the engine
29
+ * APPLIES, absent and malformed fields read as their defaults.
30
+ */
31
+ export interface OrderDepositPolicy {
32
+ /**
33
+ * The store-wide switch. Off: a payment must cover the whole outstanding
34
+ * amount (`payments.record` refuses a part payment `DEPOSITS_NOT_ENABLED`) and
35
+ * no order can be parked.
36
+ */
37
+ enabled: boolean;
38
+ /**
39
+ * The least a deposit must be before an order can be parked, in minor units of
40
+ * the store's DEFAULT currency; 0 means any deposit will do. An order in another
41
+ * currency is held to it converted at the rate checkout charges with.
42
+ */
43
+ minimum: number;
44
+ /** Whether an order may be parked with nothing paid at all. */
45
+ allowZeroDepositPark: boolean;
46
+ /**
47
+ * Whether the storefront shows a parked order's reason to the shopper. Off by
48
+ * default: staff write that reason for staff.
49
+ */
50
+ showParkReasonToCustomer: boolean;
51
+ /**
52
+ * RESERVED: days after which a parked order is cancelled. Saved and read back,
53
+ * but nothing cancels a parked order automatically yet. `null`: never.
54
+ */
55
+ autoCancelAfterDays: number | null;
56
+ storefront: StorefrontDepositPolicy;
57
+ }
58
+ /**
59
+ * The policy of a store that never set one, and of every field that cannot be
60
+ * read: deposits off, no minimum, no zero-deposit park, the reason kept from the
61
+ * shopper, never auto-cancelled, no online deposits.
62
+ */
63
+ export declare const DEFAULT_ORDER_DEPOSIT_POLICY: Readonly<OrderDepositPolicy>;
64
+ /**
65
+ * The ACTIVE store's deposit policy (`admin.orders.depositPolicy`), stored as a
66
+ * Channel custom field and written through core `updateChannel`.
67
+ *
68
+ * Reading needs an authenticated administrator on the store; writing needs
69
+ * `UpdateChannel`.
70
+ */
71
+ export interface OrderDepositPolicyModule {
72
+ /**
73
+ * The policy the engine applies, read as tolerantly as the engine reads it: a
74
+ * store that never set one, a malformed column and a field of the wrong type
75
+ * all answer their defaults ({@link DEFAULT_ORDER_DEPOSIT_POLICY}), so this is
76
+ * what `orders.park` and `payments.record` will hold an order to.
77
+ */
78
+ get(options?: Call): Promise<OrderDepositPolicy>;
79
+ /**
80
+ * Replace the whole policy, and answer it as the engine now applies it.
81
+ *
82
+ * Every field is required: read it with {@link get}, change what you mean to,
83
+ * and send it back. Only the schema's fields are stored (anything else on the
84
+ * object is left out), and the method codes are stored as given.
85
+ *
86
+ * Refused before any request with `DEPOSIT_POLICY_INVALID` ({@link ValidationError},
87
+ * one `details[]` entry per failing field, named by its path such as
88
+ * `storefront.minimumPercent`): a non-boolean switch, a `minimum` that is not a
89
+ * whole number of 0 or more, an `autoCancelAfterDays` that is neither `null` nor
90
+ * a whole number of 1 or more, a `minimumPercent` outside 0–100, a blank or
91
+ * repeated method code, or more than 50 of them. The engine itself stores any
92
+ * JSON in the column and reads what it cannot use as the default, so this check
93
+ * is what keeps a bad value from silently turning deposits off.
94
+ *
95
+ * Absent and "set to the defaults" mean the same thing to the engine, and a
96
+ * store's column is never backfilled: write the policy when a merchant changed
97
+ * it, not as a side effect of saving something else.
98
+ */
99
+ set(policy: OrderDepositPolicy, options?: Call): Promise<OrderDepositPolicy>;
100
+ }
101
+ export declare const ORDER_DEPOSIT_POLICY_QUERY = "\n query OrderDepositPolicy {\n activeChannel { \n id\n customFields {\n orderDepositPolicy\n }\n }\n }\n";
102
+ export declare const SET_ORDER_DEPOSIT_POLICY_MUTATION = "\n mutation SetOrderDepositPolicy($input: UpdateChannelInput!) {\n updateChannel(input: $input) {\n ... on Channel { \n id\n customFields {\n orderDepositPolicy\n }\n }\n ... on ErrorResult { errorCode message }\n }\n }\n";
103
+ export declare function createOrderDepositPolicyModule(transport: Transport): OrderDepositPolicyModule;