@sixtyninecommerce/admin 0.11.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 (147) hide show
  1. package/README.md +1501 -23
  2. package/dist/auth/index.d.ts +7 -1
  3. package/dist/auth/index.js +8 -1
  4. package/dist/catalog/documents.d.ts +142 -0
  5. package/dist/catalog/documents.js +114 -0
  6. package/dist/catalog/index.d.ts +48 -7
  7. package/dist/catalog/index.js +6 -1
  8. package/dist/catalog/metadata.d.ts +244 -0
  9. package/dist/catalog/metadata.js +220 -0
  10. package/dist/catalog/properties.d.ts +38 -0
  11. package/dist/catalog/properties.js +52 -1
  12. package/dist/catalog/recommendations.d.ts +33 -6
  13. package/dist/catalog/recommendations.js +94 -2
  14. package/dist/catalog/reviews.d.ts +17 -4
  15. package/dist/catalog/reviews.js +7 -0
  16. package/dist/catalog/variants.d.ts +60 -0
  17. package/dist/catalog/variants.js +39 -0
  18. package/dist/catalog/visibility.d.ts +18 -2
  19. package/dist/client.d.ts +29 -3
  20. package/dist/client.js +19 -8
  21. package/dist/content/assets.d.ts +3 -4
  22. package/dist/content/forms.d.ts +332 -1
  23. package/dist/content/forms.js +140 -4
  24. package/dist/content/items.d.ts +31 -8
  25. package/dist/content/items.js +1 -1
  26. package/dist/content/menus.d.ts +254 -0
  27. package/dist/content/menus.js +70 -0
  28. package/dist/content/strings.d.ts +137 -0
  29. package/dist/content/strings.js +82 -0
  30. package/dist/customers/delivery-terms.d.ts +44 -0
  31. package/dist/customers/delivery-terms.js +32 -0
  32. package/dist/customers/index.d.ts +15 -0
  33. package/dist/customers/index.js +4 -0
  34. package/dist/documents/emails.d.ts +150 -0
  35. package/dist/documents/emails.js +220 -0
  36. package/dist/documents/index.d.ts +13 -0
  37. package/dist/documents/index.js +2 -0
  38. package/dist/fulfillments/index.d.ts +119 -1
  39. package/dist/fulfillments/index.js +124 -4
  40. package/dist/index.d.ts +43 -23
  41. package/dist/index.js +11 -5
  42. package/dist/integrations/exact-online-types.d.ts +542 -0
  43. package/dist/integrations/exact-online.d.ts +541 -5
  44. package/dist/integrations/exact-online.js +714 -1
  45. package/dist/integrations/index.d.ts +23 -8
  46. package/dist/integrations/index.js +9 -4
  47. package/dist/integrations/pipeline-discoveries.d.ts +65 -0
  48. package/dist/integrations/pipeline-discoveries.js +65 -0
  49. package/dist/integrations/pipeline-runs.d.ts +119 -0
  50. package/dist/integrations/pipeline-runs.js +87 -0
  51. package/dist/integrations/pipelines.d.ts +73 -2
  52. package/dist/integrations/pipelines.js +36 -1
  53. package/dist/integrations/price-import.d.ts +223 -0
  54. package/dist/integrations/price-import.js +124 -0
  55. package/dist/integrations/types.d.ts +221 -3
  56. package/dist/integrations/types.js +4 -3
  57. package/dist/meta/index.d.ts +10 -0
  58. package/dist/metafields/index.d.ts +8 -1
  59. package/dist/metafields/index.js +10 -0
  60. package/dist/orders/cancel-with-money.d.ts +10 -0
  61. package/dist/orders/cancel-with-money.js +2 -0
  62. package/dist/orders/commit-edit.d.ts +16 -0
  63. package/dist/orders/commit-edit.js +14 -1
  64. package/dist/orders/deposit-policy.d.ts +3 -1
  65. package/dist/orders/index.d.ts +22 -11
  66. package/dist/orders/index.js +5 -2
  67. package/dist/orders/list.d.ts +26 -5
  68. package/dist/orders/list.js +123 -13
  69. package/dist/orders/manual-discounts.d.ts +13 -5
  70. package/dist/orders/money-view.d.ts +149 -0
  71. package/dist/orders/money-view.js +99 -0
  72. package/dist/orders/plan-edit.d.ts +34 -2
  73. package/dist/orders/plan-edit.js +110 -12
  74. package/dist/orders/surcharges.d.ts +12 -0
  75. package/dist/orders/surcharges.js +34 -9
  76. package/dist/payments/account-credit.d.ts +17 -1
  77. package/dist/payments/account-credit.js +25 -2
  78. package/dist/payments/credit-noted-fields.d.ts +8 -1
  79. package/dist/payments/credit-noted-fields.js +34 -2
  80. package/dist/payments/customer-consent.d.ts +30 -0
  81. package/dist/payments/customer-consent.js +49 -0
  82. package/dist/payments/index.d.ts +89 -14
  83. package/dist/payments/index.js +22 -2
  84. package/dist/payments/requests.d.ts +6 -3
  85. package/dist/payments/requests.js +1 -0
  86. package/dist/pickups/index.d.ts +5 -3
  87. package/dist/pickups/index.js +5 -2
  88. package/dist/platform/email-gateways.d.ts +165 -0
  89. package/dist/platform/email-gateways.js +78 -0
  90. package/dist/platform/tax.d.ts +11 -3
  91. package/dist/platform/tax.js +30 -0
  92. package/dist/pos/exchanges.d.ts +6 -1
  93. package/dist/pos/index.d.ts +229 -10
  94. package/dist/pos/index.js +113 -4
  95. package/dist/pos/offline-sales.d.ts +44 -3
  96. package/dist/pos/offline-sales.js +57 -3
  97. package/dist/pos/returns.d.ts +28 -1
  98. package/dist/pos/returns.js +36 -6
  99. package/dist/pricing/price-lists.d.ts +3 -1
  100. package/dist/purchasing/alerts.d.ts +19 -4
  101. package/dist/purchasing/alerts.js +29 -3
  102. package/dist/purchasing/backorders.d.ts +61 -0
  103. package/dist/purchasing/backorders.js +92 -0
  104. package/dist/purchasing/index.d.ts +21 -3
  105. package/dist/purchasing/index.js +8 -0
  106. package/dist/purchasing/links.d.ts +263 -0
  107. package/dist/purchasing/links.js +192 -0
  108. package/dist/purchasing/purchase-orders.d.ts +4 -1
  109. package/dist/purchasing/receipts.d.ts +396 -0
  110. package/dist/purchasing/receipts.js +287 -0
  111. package/dist/purchasing/returns.d.ts +273 -0
  112. package/dist/purchasing/returns.js +229 -0
  113. package/dist/quotes/index.d.ts +20 -3
  114. package/dist/returns/index.d.ts +62 -1
  115. package/dist/returns/index.js +61 -0
  116. package/dist/seo/config.d.ts +128 -0
  117. package/dist/seo/config.js +95 -0
  118. package/dist/seo/redirects.d.ts +125 -0
  119. package/dist/seo/redirects.js +60 -1
  120. package/dist/seo/settings.d.ts +147 -0
  121. package/dist/seo/settings.js +209 -0
  122. package/dist/shipping/index.d.ts +6 -0
  123. package/dist/shipping/index.js +2 -0
  124. package/dist/shipping/methods.d.ts +8 -1
  125. package/dist/shipping/myparcel.d.ts +415 -1
  126. package/dist/shipping/myparcel.js +291 -3
  127. package/dist/shipping/rate-tables.d.ts +149 -4
  128. package/dist/shipping/rate-tables.js +229 -23
  129. package/dist/shipping/ship-to-countries.d.ts +75 -0
  130. package/dist/shipping/ship-to-countries.js +47 -0
  131. package/dist/stock/by-location.d.ts +86 -0
  132. package/dist/stock/by-location.js +94 -0
  133. package/dist/stock/index.d.ts +8 -1
  134. package/dist/stock/index.js +4 -0
  135. package/dist/stock/settings.d.ts +106 -0
  136. package/dist/stock/settings.js +103 -0
  137. package/dist/stock/transfers.d.ts +171 -10
  138. package/dist/stock/transfers.js +82 -4
  139. package/dist/stored-value/index.d.ts +98 -7
  140. package/dist/stored-value/index.js +71 -4
  141. package/dist/tax/display-policy.d.ts +105 -0
  142. package/dist/tax/display-policy.js +84 -0
  143. package/dist/tax/index.d.ts +3 -0
  144. package/dist/tax/index.js +2 -0
  145. package/dist/tenant/email-templates.d.ts +222 -1
  146. package/dist/tenant/email-templates.js +227 -10
  147. package/package.json +2 -2
@@ -1,3 +1,4 @@
1
+ import { customerAgreedVariable } from './customer-consent.js';
1
2
  import { STORE_CREDIT_MOVE_FIELDS } from './store-credit-fields.js';
2
3
  const UNAPPLIED_CASH_FIELDS = /* GraphQL */ `
3
4
  id
@@ -34,6 +35,25 @@ export const CREDIT_ORDER_OVERPAYMENT_TO_STORE_CREDIT_MUTATION = /* GraphQL */ `
34
35
  }
35
36
  }
36
37
  `;
38
+ /**
39
+ * The same, declaring the customer's answer to store credit: sent only by a call that states it,
40
+ * so an engine before the argument still takes every call that does not.
41
+ */
42
+ export const CREDIT_ORDER_OVERPAYMENT_TO_STORE_CREDIT_WITH_CONSENT_MUTATION = /* GraphQL */ `
43
+ mutation CreditOrderOverpaymentToStoreCredit(
44
+ $input: CreditOrderOverpaymentInput!
45
+ $idempotencyKey: String
46
+ $customerAgreed: Boolean
47
+ ) {
48
+ creditOrderOverpaymentToStoreCredit(
49
+ input: $input
50
+ idempotencyKey: $idempotencyKey
51
+ customerAgreed: $customerAgreed
52
+ ) {
53
+ ${STORE_CREDIT_MOVE_FIELDS}
54
+ }
55
+ }
56
+ `;
37
57
  export const UNAPPLIED_CASH_QUERY = /* GraphQL */ `
38
58
  query ArUnappliedCash($customerId: ID!) {
39
59
  arUnappliedCash(customerId: $customerId) {
@@ -91,10 +111,13 @@ export function createAccountCreditModule(transport) {
91
111
  return data.creditOrderOverpaymentToAccount;
92
112
  },
93
113
  async creditOverpaymentToStoreCredit(input, options) {
114
+ const customerAgreed = customerAgreedVariable(options?.customerAgreed);
94
115
  const data = await transport.graphql({
95
116
  api: 'admin',
96
- query: CREDIT_ORDER_OVERPAYMENT_TO_STORE_CREDIT_MUTATION,
97
- variables: { input, idempotencyKey: options?.idempotencyKey },
117
+ query: customerAgreed === undefined
118
+ ? CREDIT_ORDER_OVERPAYMENT_TO_STORE_CREDIT_MUTATION
119
+ : CREDIT_ORDER_OVERPAYMENT_TO_STORE_CREDIT_WITH_CONSENT_MUTATION,
120
+ variables: { input, idempotencyKey: options?.idempotencyKey, customerAgreed },
98
121
  }, options);
99
122
  return data.creditOrderOverpaymentToStoreCredit;
100
123
  },
@@ -1,5 +1,8 @@
1
1
  import type { Transport } from '@sixtyninecommerce/core';
2
- /** `document` without the fields above: what an engine before them accepts. */
2
+ /**
3
+ * `document` without the fields above: what an engine before them accepts. `payable` is newer
4
+ * still (`payableAware`), so an engine without the credit fields lacks it too and it goes with them.
5
+ */
3
6
  export declare function withoutCreditNotedFields(document: string): string;
4
7
  /**
5
8
  * The transport, sending a document that names the credit fields once more without them when the
@@ -10,3 +13,7 @@ export declare function withoutCreditNotedFields(document: string): string;
10
13
  * that knows neither (four sends at most).
11
14
  */
12
15
  export declare function creditNotedAware(transport: Pick<Transport, 'graphql'>): Pick<Transport, 'graphql'>;
16
+ /** `document` without `payable`: what an engine before it accepts. */
17
+ export declare function withoutPayableField(document: string): string;
18
+ /** The transport, sending a document that names `payable` once more without it when refused. */
19
+ export declare function payableAware(transport: Pick<Transport, 'graphql'>): Pick<Transport, 'graphql'>;
@@ -7,8 +7,11 @@ import { isUnknownFieldRejection } from './store-credit-fields.js';
7
7
  * credited, the customer owes `outstanding`). So the position reads keep working on an older
8
8
  * engine, as `storeCreditAware` keeps the "credit the customer" answers working.
9
9
  */
10
- const CREDIT_NOTED_FIELDS = [/\bcreditNoted\b/g, /\bowed\b/g];
11
- /** `document` without the fields above: what an engine before them accepts. */
10
+ const CREDIT_NOTED_FIELDS = [/\bcreditNoted\b/g, /\bowed\b/g, /\bpayable\b/g];
11
+ /**
12
+ * `document` without the fields above: what an engine before them accepts. `payable` is newer
13
+ * still (`payableAware`), so an engine without the credit fields lacks it too and it goes with them.
14
+ */
12
15
  export function withoutCreditNotedFields(document) {
13
16
  return CREDIT_NOTED_FIELDS.reduce((text, field) => text.replace(field, ''), document);
14
17
  }
@@ -35,3 +38,32 @@ export function creditNotedAware(transport) {
35
38
  },
36
39
  };
37
40
  }
41
+ /**
42
+ * The payment position's `payable` (branch `murat/order-paid-measures-credit-notes`): what the
43
+ * order's settled money must reach before it counts as paid, its total less what a live invoice's
44
+ * credit notes took off. Newer than `creditNoted` and `owed`, so it falls away FIRST:
45
+ * `creditNotedAware(payableAware(transport))` resends without `payable` on an engine that has the
46
+ * credit fields and not this one (two sends), and without all three on an engine before them
47
+ * (three sends: the credit fallback drops `payable` too). Absent, it reads as `total`.
48
+ */
49
+ const PAYABLE_FIELD = /\bpayable\b/g;
50
+ /** `document` without `payable`: what an engine before it accepts. */
51
+ export function withoutPayableField(document) {
52
+ return document.replace(PAYABLE_FIELD, '');
53
+ }
54
+ /** The transport, sending a document that names `payable` once more without it when refused. */
55
+ export function payableAware(transport) {
56
+ return {
57
+ async graphql(call, options) {
58
+ try {
59
+ return await transport.graphql(call, options);
60
+ }
61
+ catch (error) {
62
+ const legacy = withoutPayableField(call.query);
63
+ if (legacy === call.query || !isUnknownFieldRejection(error))
64
+ throw error;
65
+ return transport.graphql({ ...call, query: legacy }, options);
66
+ }
67
+ },
68
+ };
69
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * The customer's answer to store credit (incentives sprint 8, ruling Q4): on a door where staff
3
+ * choose to credit the customer instead of refunding them, whether the customer EXPRESSLY agreed
4
+ * to store credit instead of a refund to their payment (EU consumer law, CRD art. 13(1)). In a
5
+ * store whose book is store credit the move records it on its ledger entries
6
+ * (`StoredValueEntry.customerAgreed`); in an AR store, on a refund, or when nothing moves it is
7
+ * accepted and recorded nowhere. It is a record, never a condition: no door refuses for it.
8
+ *
9
+ * Sent only when stated. Left out, nothing of it reaches the wire, so a call that does not state
10
+ * it is the request it always was, and an engine before the field still takes it. A call that
11
+ * DOES state it needs an engine that knows the field (incentives sprint 8 PR 6a): an older one
12
+ * refuses the document before it runs, and that refusal is surfaced, never retried without the
13
+ * answer.
14
+ */
15
+ /** `value` as a variable: `true` or `false` when stated, else `undefined` (off the wire). */
16
+ export declare function customerAgreedVariable(value: unknown): boolean | undefined;
17
+ /** `{ customerAgreed }` when stated, else nothing: spread into an input object. */
18
+ export declare function statedCustomerAgreed(value: unknown): {
19
+ customerAgreed?: boolean;
20
+ };
21
+ /**
22
+ * `document` with `$customerAgreed: Boolean` declared after the line `declaration` and passed as
23
+ * `customerAgreed: $customerAgreed` after the line `argument` (each matched whole, trimmed), in
24
+ * the same indentation. Built from the document a call without the answer sends, so the two never
25
+ * drift; it throws at load when either line is missing.
26
+ */
27
+ export declare function withCustomerAgreed(document: string, anchor: {
28
+ declaration: string;
29
+ argument: string;
30
+ }): string;
@@ -0,0 +1,49 @@
1
+ /**
2
+ * The customer's answer to store credit (incentives sprint 8, ruling Q4): on a door where staff
3
+ * choose to credit the customer instead of refunding them, whether the customer EXPRESSLY agreed
4
+ * to store credit instead of a refund to their payment (EU consumer law, CRD art. 13(1)). In a
5
+ * store whose book is store credit the move records it on its ledger entries
6
+ * (`StoredValueEntry.customerAgreed`); in an AR store, on a refund, or when nothing moves it is
7
+ * accepted and recorded nowhere. It is a record, never a condition: no door refuses for it.
8
+ *
9
+ * Sent only when stated. Left out, nothing of it reaches the wire, so a call that does not state
10
+ * it is the request it always was, and an engine before the field still takes it. A call that
11
+ * DOES state it needs an engine that knows the field (incentives sprint 8 PR 6a): an older one
12
+ * refuses the document before it runs, and that refusal is surfaced, never retried without the
13
+ * answer.
14
+ */
15
+ /** `value` as a variable: `true` or `false` when stated, else `undefined` (off the wire). */
16
+ export function customerAgreedVariable(value) {
17
+ return typeof value === 'boolean' ? value : undefined;
18
+ }
19
+ /** `{ customerAgreed }` when stated, else nothing: spread into an input object. */
20
+ export function statedCustomerAgreed(value) {
21
+ const stated = customerAgreedVariable(value);
22
+ return stated === undefined ? {} : { customerAgreed: stated };
23
+ }
24
+ /**
25
+ * `document` with `$customerAgreed: Boolean` declared after the line `declaration` and passed as
26
+ * `customerAgreed: $customerAgreed` after the line `argument` (each matched whole, trimmed), in
27
+ * the same indentation. Built from the document a call without the answer sends, so the two never
28
+ * drift; it throws at load when either line is missing.
29
+ */
30
+ export function withCustomerAgreed(document, anchor) {
31
+ let declared = false;
32
+ let passed = false;
33
+ const lines = document.split('\n').flatMap((line) => {
34
+ const indent = /^\s*/.exec(line)?.[0] ?? '';
35
+ if (!declared && line.trim() === anchor.declaration) {
36
+ declared = true;
37
+ return [line, `${indent}$customerAgreed: Boolean`];
38
+ }
39
+ if (declared && !passed && line.trim() === anchor.argument) {
40
+ passed = true;
41
+ return [line, `${indent}customerAgreed: $customerAgreed`];
42
+ }
43
+ return [line];
44
+ });
45
+ if (!declared || !passed) {
46
+ throw new Error(`withCustomerAgreed: "${anchor.declaration}" or "${anchor.argument}" is not a line of the document`);
47
+ }
48
+ return lines.join('\n');
49
+ }
@@ -52,9 +52,20 @@ export interface OrderPaymentPosition {
52
52
  */
53
53
  owed?: number;
54
54
  /**
55
- * `total - covered`, floored at zero: what the payments are short of the order's total, and
56
- * what `record` caps a payment at. On an order whose credit notes took part of its bill off,
57
- * `owed` is what the customer still owes.
55
+ * What the order's SETTLED money must reach before it counts as paid: `total` less what a live
56
+ * invoice's credit notes took off it. An order paid down to what its invoice bills net of its
57
+ * credit notes is paid in full: `orders.settle`, the staff move into `PaymentSettled` and the
58
+ * platform's own settlement all measure this figure. Equals `total` when nothing was credited,
59
+ * and also when the order's only invoice was cancelled with nothing in its place (it owes
60
+ * nothing more, `owed`, but counts as paid only once it is invoiced again or cancelled). Read by
61
+ * {@link PaymentsModule.position} and `orders.paymentPosition`; against an engine that does not
62
+ * serve it those calls resend without it, and an absent `payable` reads as `total`.
63
+ */
64
+ payable?: number;
65
+ /**
66
+ * `total - covered`, floored at zero: what the payments are short of the order's total. On an
67
+ * order whose credit notes took part of its bill off, `owed` is what the customer still owes,
68
+ * and what `record` caps a payment at.
58
69
  */
59
70
  outstanding: number;
60
71
  /**
@@ -67,14 +78,19 @@ export interface OrderPaymentPosition {
67
78
  * (`payments.accountCredit.creditOverpayment`) no longer counts here.
68
79
  */
69
80
  overpaid: number;
70
- /** What a further payment may take. */
81
+ /**
82
+ * What a further payment may take: what is still owed once the credit notes are counted
83
+ * (`owed`; `outstanding` when nothing was credited). An engine before the credit-noted caps
84
+ * answers `outstanding` here.
85
+ */
71
86
  availableToCharge: number;
72
87
  }
73
88
  /** Money the merchant HAS, recorded against an order. */
74
89
  export interface RecordPaymentInput {
75
90
  /**
76
- * Minor units of the order's currency. Greater than zero, and at most the
77
- * order's `outstanding` — an over-payment is refused rather than accepted,
91
+ * Minor units of the order's currency. Greater than zero, and at most what the
92
+ * order still owes (its position's `owed`: `outstanding` less what its credit
93
+ * notes took off its bill) — an over-payment is refused rather than accepted,
78
94
  * and the refusal carries the position so a till can correct itself without a
79
95
  * second round trip.
80
96
  */
@@ -306,6 +322,36 @@ export interface OrderPaymentRecord {
306
322
  /** The provider's reference for the payment, when it gave one. */
307
323
  transactionId: string | null;
308
324
  }
325
+ /** A coded refusal "mark as paid" would answer now ({@link PaymentsModule.settlePreview}). */
326
+ export interface PaymentSettleRefusal {
327
+ /**
328
+ * `PAYMENT_CAPTURE_EXCEEDS_BILLED`, `ORDER_CANCELLED_PAYMENT_CONFLICT` or
329
+ * `PAYMENT_STATE_TRANSITION_ERROR`: the code {@link PaymentsModule.settle} would throw.
330
+ */
331
+ code: string;
332
+ /** The engine's sentence for staff: why, and what to do instead. */
333
+ message: string;
334
+ }
335
+ /**
336
+ * What {@link PaymentsModule.settle} would do to an authorized payment as its order stands now
337
+ * ({@link PaymentsModule.settlePreview}). Nothing was written. Minor units of the order's currency.
338
+ */
339
+ export interface PaymentSettlePreview {
340
+ paymentId: string;
341
+ /** The payment's amount as it stands: what it authorized. */
342
+ authorized: number;
343
+ /**
344
+ * What the capture records now: `authorized`, or less on an order whose credit notes lowered
345
+ * what it bills (the rest of a promise whose money moves by hand is dropped). 0 when refused.
346
+ */
347
+ records: number;
348
+ /** What the order's credit notes took off what it bills; 0 when the capture is whole. */
349
+ creditNoted: number;
350
+ /** The numbers of the credit notes behind `records` or the refusal, oldest first. */
351
+ creditNotes: string[];
352
+ /** Null when the capture may run; else the coded refusal it would answer now. */
353
+ refusal: PaymentSettleRefusal | null;
354
+ }
309
355
  /** What a payment app reports happened to a payment it took (`reportAppPayment`). */
310
356
  export type AppPaymentReportState = 'Authorized' | 'Settled' | 'Declined' | 'Cancelled';
311
357
  /** An app's report on one of its payments. */
@@ -417,11 +463,15 @@ export interface PaymentsModule {
417
463
  * argument, so a retry under the same key returns the first call's order
418
464
  * rather than taking the money twice. Use a fresh key per intended payment.
419
465
  *
420
- * Refusals: `AMOUNT_EXCEEDS_OUTSTANDING` (over-payment, with the position
421
- * attached), `AMOUNT_NOT_POSITIVE`, `ORDER_NOT_RECORDABLE` (the order's state
422
- * cannot take a payment), `DEPOSITS_NOT_ENABLED` — a PARTIAL payment on a
423
- * store that has not turned deposits on; paying the whole outstanding balance
424
- * is not a deposit and always works — `METADATA_KEY_RESERVED`,
466
+ * Refusals: `AMOUNT_EXCEEDS_OUTSTANDING` (more than the order still owes,
467
+ * `owed`, with the position attached; its message names the credit notes that
468
+ * lowered it), `AMOUNT_NOT_POSITIVE`, `ORDER_NOT_RECORDABLE` (the order's state
469
+ * cannot take a payment), `DEPOSITS_NOT_ENABLED` — a PARTIAL payment (less
470
+ * than `owed`) on a store that has not turned deposits on; paying all it owes
471
+ * is not a deposit and always works, and neither is a stored-value payment (a
472
+ * gift card or store credit) on an order still arranging payment: that part is
473
+ * taken whatever the deposit policy, and the order is placed only once its
474
+ * money covers it — `METADATA_KEY_RESERVED`,
425
475
  * `PAYMENT_METHOD_NOT_FOUND`, `ORDER_NOT_FOUND`.
426
476
  *
427
477
  * @effect money
@@ -429,7 +479,8 @@ export interface PaymentsModule {
429
479
  record(orderId: string, input: RecordPaymentInput, options?: Call): Promise<PaidOrder>;
430
480
  /**
431
481
  * Read an order's payment position: what it bills, what was paid and refunded, what its credit
432
- * notes took off (`creditNoted`) and what the customer still owes after them (`owed`).
482
+ * notes took off (`creditNoted`), what the customer still owes after them (`owed`) and what its
483
+ * settled money must reach before it counts as paid (`payable`).
433
484
  *
434
485
  * @effect read
435
486
  */
@@ -551,15 +602,38 @@ export interface PaymentsModule {
551
602
  * order could not move on as it stands.
552
603
  * - `ORDER_CANCELLED_PAYMENT_CONFLICT` (409): the payment's order is cancelled, and a cancelled
553
604
  * order is never paid. Cancel the payment instead to release it.
605
+ * - `PAYMENT_CAPTURE_EXCEEDS_BILLED` (422): the order's credit notes lowered what it bills, and
606
+ * the payment would take more: its provider can only capture it in full, the order's other
607
+ * payments already cover the bill, or its only invoice was cancelled with nothing in its
608
+ * place. Nothing was captured; the error's `extensions.leftToPay` is what is left to pay
609
+ * without this payment (the bill after its credit notes, less the order's other payments),
610
+ * and the message names the credit notes and what to do instead.
554
611
  * - `PAYMENT_SETTLE_CONFLICT` (409): the payment moved while it was being captured. Read it
555
612
  * again.
556
613
  * - `ENTITY_NOT_FOUND` (404): no payment of an order of this store has that id.
557
614
  *
615
+ * On such an order, a promise whose money moves by hand (bank transfer, invoice, net terms) is
616
+ * recorded at what the order still bills: the returned payment's `amount` is that figure, and
617
+ * the rest of the promise is dropped. {@link settlePreview} says which before you call this.
618
+ *
558
619
  * Needs `UpdateOrder`.
559
620
  *
560
621
  * @effect money
561
622
  */
562
623
  settle(paymentId: string, options?: Call): Promise<OrderPaymentRecord>;
624
+ /**
625
+ * What {@link settle} would do to this authorized payment now, without doing it: the amount it
626
+ * records, or the coded refusal it would answer (`refusal`). Nothing is written, nothing is
627
+ * locked and no provider is asked, so {@link settle} still judges again (and the provider may
628
+ * still decline it).
629
+ *
630
+ * Refuses `ENTITY_NOT_FOUND` (404) for a payment of no order of this store. An engine older
631
+ * than this method answers a GraphQL validation error: treat that as "no preview" and let
632
+ * {@link settle} judge. Needs `ReadOrder`.
633
+ *
634
+ * @effect read
635
+ */
636
+ settlePreview(paymentId: string, options?: Call): Promise<PaymentSettlePreview>;
563
637
  /**
564
638
  * Void an authorized payment (release the hold), and return the payment.
565
639
  *
@@ -700,7 +774,7 @@ export interface PaymentsModule {
700
774
  appPayments(orderId: string, options?: Call): Promise<AppPayment[]>;
701
775
  }
702
776
  export declare const RECORD_ORDER_PAYMENT_MUTATION = "\n mutation RecordOrderPayment($orderId: ID!, $input: RecordPaymentInput!, $idempotencyKey: String) {\n recordOrderPayment(orderId: $orderId, input: $input, idempotencyKey: $idempotencyKey) {\n \n id\n code\n state\n currencyCode\n total\n totalWithTax\n\n }\n }\n";
703
- export declare const ORDER_PAYMENT_POSITION_QUERY = "\n query OrderPaymentPosition($orderId: ID!) {\n orderPaymentPosition(orderId: $orderId) {\n \n total\n covered\n settled\n authorized\n refunded\n creditNoted\n owed\n outstanding\n overpaid\n availableToCharge\n\n }\n }\n";
777
+ export declare const ORDER_PAYMENT_POSITION_QUERY = "\n query OrderPaymentPosition($orderId: ID!) {\n orderPaymentPosition(orderId: $orderId) {\n \n total\n covered\n settled\n authorized\n refunded\n creditNoted\n owed\n payable\n outstanding\n overpaid\n availableToCharge\n\n }\n }\n";
704
778
  export declare const ORDER_REFUND_POSITION_QUERY = "\n query OrderRefundPosition($orderId: ID!) {\n orderRefundPosition(orderId: $orderId) {\n \n currencyCode\n refunded\n refundable\n perPayment {\n paymentId\n state\n method\n amount\n refunded\n refundable\n tookMoney\n }\n\n }\n }\n";
705
779
  export declare const REFUND_ORDER_PAYMENT_MUTATION = "\n mutation RefundOrderPayment($input: RefundPaymentInput!, $idempotencyKey: String) {\n refundOrderPayment(input: $input, idempotencyKey: $idempotencyKey) {\n id\n total\n state\n method\n transactionId\n reason\n }\n }\n";
706
780
  export declare const UNRECONCILED_REFUNDS_QUERY = "\n query UnreconciledRefunds($orderId: ID!) {\n orderRefundPosition(orderId: $orderId) {\n unreconciled {\n refundId\n paymentId\n amount\n createdAt\n }\n }\n }\n";
@@ -709,10 +783,11 @@ export declare const REFUND_CREDIT_NOTE_REQUIREMENT_QUERY = "\n query RefundCre
709
783
  export declare const RECONCILE_REFUND_OUTCOME_MUTATION = "\n mutation ReconcileRefundOutcome($input: ReconcileRefundOutcomeInput!, $idempotencyKey: String) {\n reconcileRefundOutcome(input: $input, idempotencyKey: $idempotencyKey) {\n id\n total\n state\n method\n transactionId\n reason\n }\n }\n";
710
784
  export declare const SETTLE_PAYMENT_MUTATION = "\n mutation SettlePayment($id: ID!) {\n settlePayment(id: $id) {\n __typename\n ... on Payment {\n \n id\n state\n method\n amount\n transactionId\n\n }\n ... on SettlePaymentError {\n paymentErrorMessage\n }\n ... on PaymentStateTransitionError {\n transitionError\n }\n ... on OrderStateTransitionError {\n transitionError\n }\n ... on ErrorResult {\n errorCode\n message\n }\n }\n }\n";
711
785
  export declare const CANCEL_PAYMENT_MUTATION = "\n mutation CancelPayment($id: ID!) {\n cancelPayment(id: $id) {\n __typename\n ... on Payment {\n \n id\n state\n method\n amount\n transactionId\n\n }\n ... on CancelPaymentError {\n paymentErrorMessage\n }\n ... on PaymentStateTransitionError {\n transitionError\n }\n ... on ErrorResult {\n errorCode\n message\n }\n }\n }\n";
786
+ export declare const SETTLE_PAYMENT_PREVIEW_QUERY = "\n query SettlePaymentPreview($paymentId: ID!) {\n settlePaymentPreview(paymentId: $paymentId) {\n paymentId\n authorized\n records\n creditNoted\n creditNotes\n refusal {\n code\n message\n }\n }\n }\n";
712
787
  export declare const REPORT_APP_PAYMENT_MUTATION = "\n mutation ReportAppPayment(\n $paymentId: ID!\n $input: ReportAppPaymentInput!\n $idempotencyKey: String!\n ) {\n reportAppPayment(paymentId: $paymentId, input: $input, idempotencyKey: $idempotencyKey) {\n id\n state\n amount\n method\n transactionId\n }\n }\n";
713
788
  export declare const APP_PAYMENTS_QUERY = "\n query AppPayments($orderId: ID!) {\n appPayments(orderId: $orderId) {\n id\n orderId\n orderCode\n state\n amount\n currencyCode\n providerReference\n methodCode\n outcomeUnknown\n createdAt\n }\n }\n";
714
789
  export declare function createPaymentsModule(transport: Transport): PaymentsModule;
715
- export type { AccountCreditModule, ApplyUnappliedCashInput, CreditOverpaymentInput, OrderMoneyOnAccount, RefundUnappliedCashInput, StoreCreditMove, UnappliedCash, UnappliedCashRefund, } from './account-credit.js';
790
+ export type { AccountCreditModule, ApplyUnappliedCashInput, CreditOverpaymentInput, CreditOverpaymentToStoreCreditCall, OrderMoneyOnAccount, RefundUnappliedCashInput, StoreCreditMove, UnappliedCash, UnappliedCashRefund, } from './account-credit.js';
716
791
  export type { ConnectedAccountModule, StripeConnectedAccount, } from './connected-account.js';
717
792
  export type { CreatePaymentMethodInput, PaymentMethod, PaymentMethodCredential, PaymentMethodCredentialPath, PaymentMethodsModule, PaymentMethodTranslation, PaymentMethodTranslationInput, UpdatePaymentMethodInput, } from './methods.js';
718
793
  export type { MollieDiagnosis, MollieDiagnosisMethod, MollieDiagnosisVerdict, MollieDirectDebitDiagnosis, MollieMethod, MollieMethodList, MollieMethodsModule, MollieProbeError, MollieProbeErrorKind, SetMollieMethodsInput, } from './mollie-methods.js';
@@ -1,7 +1,7 @@
1
1
  import { BusinessRuleError, errorFromErrorResult, isErrorResult, } from '@sixtyninecommerce/core';
2
2
  import { createAccountCreditModule } from './account-credit.js';
3
3
  import { createArPaymentsModule } from './ar.js';
4
- import { creditNotedAware } from './credit-noted-fields.js';
4
+ import { creditNotedAware, payableAware } from './credit-noted-fields.js';
5
5
  import { createPaymentMethodsModule } from './methods.js';
6
6
  import { createPaymentLinksModule } from './payment-links.js';
7
7
  import { createProvidersModule } from './providers.js';
@@ -22,6 +22,7 @@ const POSITION_FIELDS = /* GraphQL */ `
22
22
  refunded
23
23
  creditNoted
24
24
  owed
25
+ payable
25
26
  outstanding
26
27
  overpaid
27
28
  availableToCharge
@@ -175,6 +176,21 @@ export const CANCEL_PAYMENT_MUTATION = /* GraphQL */ `
175
176
  }
176
177
  }
177
178
  `;
179
+ export const SETTLE_PAYMENT_PREVIEW_QUERY = /* GraphQL */ `
180
+ query SettlePaymentPreview($paymentId: ID!) {
181
+ settlePaymentPreview(paymentId: $paymentId) {
182
+ paymentId
183
+ authorized
184
+ records
185
+ creditNoted
186
+ creditNotes
187
+ refusal {
188
+ code
189
+ message
190
+ }
191
+ }
192
+ }
193
+ `;
178
194
  /** The union members that mean "the provider said no", renamed so a caller branches on intent. */
179
195
  const DECLINE_CODES = {
180
196
  SETTLE_PAYMENT_ERROR: 'PAYMENT_SETTLE_DECLINED',
@@ -251,7 +267,7 @@ export function createPaymentsModule(transport) {
251
267
  },
252
268
  async position(orderId, options) {
253
269
  // The credit fields fall away on an engine before them: the position itself still reads.
254
- const data = await creditNotedAware(transport).graphql({ api: 'admin', query: ORDER_PAYMENT_POSITION_QUERY, variables: { orderId } }, options);
270
+ const data = await creditNotedAware(payableAware(transport)).graphql({ api: 'admin', query: ORDER_PAYMENT_POSITION_QUERY, variables: { orderId } }, options);
255
271
  return data.orderPaymentPosition;
256
272
  },
257
273
  async refund(input, options) {
@@ -269,6 +285,10 @@ export function createPaymentsModule(transport) {
269
285
  const data = await transport.graphql({ api: 'admin', query: SETTLE_PAYMENT_MUTATION, variables: { id: paymentId } }, options);
270
286
  return paymentOrThrow(data.settlePayment);
271
287
  },
288
+ async settlePreview(paymentId, options) {
289
+ const data = await transport.graphql({ api: 'admin', query: SETTLE_PAYMENT_PREVIEW_QUERY, variables: { paymentId } }, options);
290
+ return data.settlePaymentPreview;
291
+ },
272
292
  async cancel(paymentId, options) {
273
293
  const data = await transport.graphql({ api: 'admin', query: CANCEL_PAYMENT_MUTATION, variables: { id: paymentId } }, options);
274
294
  return paymentOrThrow(data.cancelPayment);
@@ -10,13 +10,16 @@ export type PaymentRequestStatus = (typeof PAYMENT_REQUEST_STATUSES)[number];
10
10
  /**
11
11
  * Why a payment request closed: `PAID` (its payment landed), `EXPIRED`,
12
12
  * `CANCELLED` (by staff, `requests.cancel`), `ORDER_SETTLED` (the order's
13
- * balance reached zero through another payment), `ORDER_CANCELLED`, or
13
+ * balance reached zero through another payment), `ORDER_CANCELLED`,
14
14
  * `ORDER_CURRENCY_CHANGED` (the order is now billed in another currency than
15
- * the request asked in: send a new one).
15
+ * the request asked in: send a new one), or `ORDER_CREDITED` (a credit note
16
+ * lowered what the order still owes below the request's amount, so it was
17
+ * withdrawn: send a new one, which asks what is owed now). An older engine never
18
+ * answers the last one.
16
19
  */
17
20
  export type PaymentRequestCloseReason = (typeof PAYMENT_REQUEST_CLOSE_REASONS)[number];
18
21
  /** Every close reason, in the engine's order (`OrderPaymentRequestCloseReason`). */
19
- export declare const PAYMENT_REQUEST_CLOSE_REASONS: readonly ["PAID", "EXPIRED", "CANCELLED", "ORDER_SETTLED", "ORDER_CANCELLED", "ORDER_CURRENCY_CHANGED"];
22
+ export declare const PAYMENT_REQUEST_CLOSE_REASONS: readonly ["PAID", "EXPIRED", "CANCELLED", "ORDER_SETTLED", "ORDER_CANCELLED", "ORDER_CURRENCY_CHANGED", "ORDER_CREDITED"];
20
23
  /**
21
24
  * How long a request's link works when `create` names no `expiresAt`: this many days from the
22
25
  * moment the engine creates it. The engine's own default, pinned to it by this package's spec.
@@ -11,6 +11,7 @@ export const PAYMENT_REQUEST_CLOSE_REASONS = [
11
11
  'ORDER_SETTLED',
12
12
  'ORDER_CANCELLED',
13
13
  'ORDER_CURRENCY_CHANGED',
14
+ 'ORDER_CREDITED',
14
15
  ];
15
16
  /**
16
17
  * How long a request's link works when `create` names no `expiresAt`: this many days from the
@@ -4,11 +4,13 @@ import type { Call } from '../types.js';
4
4
  * Store pickup (click & collect, POS C1/33): webshop orders a shopper collects at one of the
5
5
  * store's shops. Placing such an order writes its pickup (`preparing`); "ready" starts the hold
6
6
  * and emails the customer once; the shop's till hands it over (`collected`); a ready pickup not
7
- * collected within the location's hold days goes back to stock (`expired`), and the pickup of a
8
- * cancelled order is `cancelled`. A location's settings are `admin.locations.pickup/setPickup`.
7
+ * collected within the location's hold days goes back to stock (`expired`), an expired one the
8
+ * shop's till took off its queue is `archived` (its order is unchanged: cancel or refund it here;
9
+ * a late customer still collects it), and the pickup of a cancelled order is `cancelled`. A
10
+ * location's settings are `admin.locations.pickup/setPickup`.
9
11
  */
10
12
  /** The statuses a pickup has today. More may come: read any other value as itself. */
11
- export declare const STORE_PICKUP_STATUSES: readonly ["preparing", "ready", "collected", "expired", "cancelled"];
13
+ export declare const STORE_PICKUP_STATUSES: readonly ["preparing", "ready", "collected", "expired", "archived", "cancelled"];
12
14
  export type StorePickupStatus = (typeof STORE_PICKUP_STATUSES)[number];
13
15
  /**
14
16
  * Why the release at expiry moved nothing (D23): `invoice_locked`, the order is invoiced and
@@ -3,8 +3,10 @@ import { redactionWatcher } from '../customer-data-redaction.js';
3
3
  * Store pickup (click & collect, POS C1/33): webshop orders a shopper collects at one of the
4
4
  * store's shops. Placing such an order writes its pickup (`preparing`); "ready" starts the hold
5
5
  * and emails the customer once; the shop's till hands it over (`collected`); a ready pickup not
6
- * collected within the location's hold days goes back to stock (`expired`), and the pickup of a
7
- * cancelled order is `cancelled`. A location's settings are `admin.locations.pickup/setPickup`.
6
+ * collected within the location's hold days goes back to stock (`expired`), an expired one the
7
+ * shop's till took off its queue is `archived` (its order is unchanged: cancel or refund it here;
8
+ * a late customer still collects it), and the pickup of a cancelled order is `cancelled`. A
9
+ * location's settings are `admin.locations.pickup/setPickup`.
8
10
  */
9
11
  /** The statuses a pickup has today. More may come: read any other value as itself. */
10
12
  export const STORE_PICKUP_STATUSES = [
@@ -12,6 +14,7 @@ export const STORE_PICKUP_STATUSES = [
12
14
  'ready',
13
15
  'collected',
14
16
  'expired',
17
+ 'archived',
15
18
  'cancelled',
16
19
  ];
17
20
  /**