@sixtyninecommerce/admin 0.8.0 → 0.9.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 (161) hide show
  1. package/README.md +2445 -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 +489 -0
  28. package/dist/catalog/products.js +365 -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 +274 -0
  34. package/dist/catalog/variants.js +258 -0
  35. package/dist/catalog/visibility.d.ts +57 -0
  36. package/dist/catalog/visibility.js +59 -0
  37. package/dist/client.d.ts +171 -3
  38. package/dist/client.js +81 -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 +360 -0
  66. package/dist/fulfillments/index.js +425 -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 +84 -9
  74. package/dist/index.js +16 -1
  75. package/dist/jobs/bulk-action-run.d.ts +65 -0
  76. package/dist/jobs/bulk-action-run.js +70 -0
  77. package/dist/locations/index.d.ts +6 -2
  78. package/dist/meta/index.d.ts +32 -0
  79. package/dist/orders/commit-edit.d.ts +123 -0
  80. package/dist/orders/commit-edit.js +142 -0
  81. package/dist/orders/get.d.ts +722 -0
  82. package/dist/orders/get.js +530 -0
  83. package/dist/orders/index.d.ts +105 -20
  84. package/dist/orders/index.js +44 -0
  85. package/dist/orders/line-price-preview.d.ts +297 -0
  86. package/dist/orders/line-price-preview.js +50 -0
  87. package/dist/orders/manual-discounts.d.ts +132 -0
  88. package/dist/orders/manual-discounts.js +95 -0
  89. package/dist/orders/manual-pricing.d.ts +192 -0
  90. package/dist/orders/manual-pricing.js +72 -0
  91. package/dist/orders/order-entry.d.ts +566 -0
  92. package/dist/orders/order-entry.js +129 -0
  93. package/dist/orders/parcel-charge.d.ts +45 -0
  94. package/dist/orders/parcel-charge.js +55 -0
  95. package/dist/orders/plan-edit.d.ts +489 -0
  96. package/dist/orders/plan-edit.js +93 -0
  97. package/dist/orders/status.d.ts +235 -0
  98. package/dist/orders/status.js +96 -0
  99. package/dist/orders/surcharges.d.ts +75 -2
  100. package/dist/orders/surcharges.js +110 -4
  101. package/dist/payments/account-credit.d.ts +171 -0
  102. package/dist/payments/account-credit.js +107 -0
  103. package/dist/payments/index.d.ts +234 -9
  104. package/dist/payments/index.js +90 -0
  105. package/dist/platform/catalog.d.ts +148 -0
  106. package/dist/platform/catalog.js +74 -0
  107. package/dist/platform/entitlements.d.ts +111 -0
  108. package/dist/platform/entitlements.js +86 -0
  109. package/dist/platform/legal-entities.d.ts +139 -0
  110. package/dist/platform/legal-entities.js +126 -0
  111. package/dist/platform/legal-entity-numbering.d.ts +103 -0
  112. package/dist/platform/legal-entity-numbering.js +101 -0
  113. package/dist/platform/organization-membership.d.ts +80 -0
  114. package/dist/platform/organization-membership.js +71 -0
  115. package/dist/platform/organization-settings.d.ts +33 -0
  116. package/dist/platform/organization-settings.js +42 -0
  117. package/dist/platform/organization-sharing.d.ts +172 -0
  118. package/dist/platform/organization-sharing.js +120 -0
  119. package/dist/platform/organizations.d.ts +205 -0
  120. package/dist/platform/organizations.js +180 -0
  121. package/dist/platform/provision-store.d.ts +88 -8
  122. package/dist/platform/provision-store.js +12 -0
  123. package/dist/platform/reports.d.ts +46 -0
  124. package/dist/platform/reports.js +31 -0
  125. package/dist/platform/server-metrics.d.ts +58 -0
  126. package/dist/platform/server-metrics.js +11 -0
  127. package/dist/pos/index.d.ts +567 -0
  128. package/dist/pos/index.js +205 -0
  129. package/dist/pricing/index.d.ts +405 -0
  130. package/dist/pricing/index.js +351 -0
  131. package/dist/provenance/index.d.ts +93 -0
  132. package/dist/provenance/index.js +53 -0
  133. package/dist/reports/index.d.ts +199 -0
  134. package/dist/reports/index.js +154 -0
  135. package/dist/shipping/parcel-count-suggestion.d.ts +52 -0
  136. package/dist/shipping/parcel-count-suggestion.js +73 -0
  137. package/dist/shipping/parcel-rule.d.ts +48 -0
  138. package/dist/shipping/parcel-rule.js +91 -0
  139. package/dist/stock/index.d.ts +166 -0
  140. package/dist/stock/index.js +115 -0
  141. package/dist/stock/transfers.d.ts +520 -0
  142. package/dist/stock/transfers.js +437 -0
  143. package/dist/stored-value/index.d.ts +154 -0
  144. package/dist/stored-value/index.js +130 -0
  145. package/dist/tenant/capabilities.d.ts +10 -0
  146. package/dist/tenant/entitlements.d.ts +35 -0
  147. package/dist/tenant/entitlements.js +15 -0
  148. package/dist/tenant/field-groups.d.ts +64 -0
  149. package/dist/tenant/field-groups.js +34 -0
  150. package/dist/tenant/legal-entity.d.ts +32 -0
  151. package/dist/tenant/legal-entity.js +41 -0
  152. package/dist/tenant/notifications.d.ts +148 -0
  153. package/dist/tenant/notifications.js +79 -0
  154. package/dist/tenant/retention.d.ts +10 -4
  155. package/dist/tenant/settings-sources.d.ts +103 -0
  156. package/dist/tenant/settings-sources.js +92 -0
  157. package/dist/types.d.ts +86 -11
  158. package/dist/uploads/index.d.ts +11 -7
  159. package/dist/users/index.d.ts +104 -0
  160. package/dist/users/index.js +80 -0
  161. package/package.json +3 -2
@@ -0,0 +1,171 @@
1
+ import type { Transport } from '@sixtyninecommerce/core';
2
+ import type { Call } from '../types.js';
3
+ /**
4
+ * Unapplied cash: money a customer paid on an order OVER what the order bills,
5
+ * moved to their account and held there until it pays an invoice or is paid
6
+ * back. Never a credit note: nothing that was billed is credited.
7
+ *
8
+ * Every amount is in minor units of `currencyCode`, and
9
+ * `amount = applied + refunded + remaining`.
10
+ */
11
+ export interface UnappliedCash {
12
+ id: string;
13
+ customerId: string;
14
+ /** The currency of the payment the money came from: its order's. */
15
+ currencyCode: string;
16
+ /** What was moved to the account. */
17
+ amount: number;
18
+ /** What of it has paid invoices. */
19
+ applied: number;
20
+ /** What of it was paid back to the customer. */
21
+ refunded: number;
22
+ /** What is still on the account, applied to nothing. */
23
+ remaining: number;
24
+ /** The order the money was paid on. */
25
+ orderId: string;
26
+ /** The payment of that order it was taken from. */
27
+ paymentId: string;
28
+ /** Date only (`YYYY-MM-DD`). */
29
+ receivedOn: string;
30
+ reference: string | null;
31
+ /** The reason given when the money was moved. */
32
+ notes: string | null;
33
+ /** ISO-8601 with offset. */
34
+ createdAt: string;
35
+ }
36
+ export interface CreditOverpaymentInput {
37
+ orderId: string;
38
+ /**
39
+ * Minor units of the order's currency. Omit it to move everything the order
40
+ * holds over what it bills.
41
+ */
42
+ amount?: number;
43
+ /** Why, in your own words: shown on the receipt and in the order's history. */
44
+ reason?: string;
45
+ }
46
+ export interface ApplyUnappliedCashInput {
47
+ unappliedCashId: string;
48
+ /** The AR invoice to pay. Give exactly one of `invoiceId` and `orderId`. */
49
+ invoiceId?: string;
50
+ /** An order, paid through the live AR invoice that bills it. */
51
+ orderId?: string;
52
+ /**
53
+ * Minor units. Omit it to apply as much as fits: the lesser of what the cash
54
+ * still holds and what the invoice still owes.
55
+ */
56
+ amount?: number;
57
+ }
58
+ export interface RefundUnappliedCashInput {
59
+ unappliedCashId: string;
60
+ /** Minor units. Omit it to pay back everything the cash still holds. */
61
+ amount?: number;
62
+ /** Free text stored on the refund. Shown to nobody automatically. */
63
+ reason?: string;
64
+ }
65
+ /** A payout's refund, as this surface projects it. */
66
+ export interface UnappliedCashRefund {
67
+ id: string;
68
+ /** Minor units. */
69
+ total: number;
70
+ /** `Pending`, `Settled` or `Failed`. */
71
+ state: string;
72
+ method: string | null;
73
+ transactionId: string | null;
74
+ reason: string | null;
75
+ }
76
+ /** What of an order's money is on its customer's account now. */
77
+ export interface OrderMoneyOnAccount {
78
+ /** The order's currency. Every amount here is in its minor units. */
79
+ currencyCode: string;
80
+ /**
81
+ * Money that left the order for the customer's account and was not paid back
82
+ * since. Already taken off the order's `refundable` and `overpaid`.
83
+ */
84
+ creditedToAccount: number;
85
+ /** The same figure per payment of the order, newest first. */
86
+ perPayment: Array<{
87
+ paymentId: string;
88
+ creditedToAccount: number;
89
+ }>;
90
+ }
91
+ /**
92
+ * An order's overpayment on the customer's account (`admin.payments.accountCredit`).
93
+ *
94
+ * For a store that keeps its own accounts-receivable ledger and a customer with
95
+ * a credit account in it. Anywhere else an overpayment is refunded: the calls
96
+ * here are refused `AR_LEDGER_NOT_ENABLED`, `AR_ACCOUNT_REQUIRED` or
97
+ * `AR_ACCOUNT_IN_ERP`. The last one covers every customer of a store whose ERP
98
+ * integration is on, and any ERP-linked account: balances are kept in the ERP
99
+ * there, where a credit recorded here would not show.
100
+ *
101
+ * Needs `UpdateOrder` to write, `ReadOrder` to read. Every write honours
102
+ * `options.idempotencyKey`: a repeat under the same key answers the first
103
+ * call's result instead of running again.
104
+ */
105
+ export interface AccountCreditModule {
106
+ /**
107
+ * Move money a customer paid on an order over what it bills onto their
108
+ * account. Answers one {@link UnappliedCash} per payment the money came from,
109
+ * newest payment first.
110
+ *
111
+ * Only money a settled payment still holds can move, net of every refund and
112
+ * of what was moved before, and at most what the order holds over its
113
+ * billable total. From then on that money is no longer the order's:
114
+ * `payments.refundPosition` takes it off `refundable` and `payments.position`
115
+ * no longer reports it as `overpaid` (read it with {@link onOrder}).
116
+ *
117
+ * An order that is already on a live AR invoice is refused
118
+ * `AR_ORDER_ALREADY_INVOICED`: refund its overpayment with `payments.refund`.
119
+ *
120
+ * Other refusals: `ACCOUNT_CREDIT_NOTHING_OVERPAID`,
121
+ * `ACCOUNT_CREDIT_EXCEEDS_OVERPAYMENT`, `ACCOUNT_CREDIT_AMOUNT_INVALID`,
122
+ * `ACCOUNT_CREDIT_NO_CUSTOMER`, `ACCOUNT_CREDIT_ORDER_NOT_FOUND`, and the three
123
+ * account refusals above.
124
+ */
125
+ creditOverpayment(input: CreditOverpaymentInput, options?: Call): Promise<UnappliedCash[]>;
126
+ /** A customer's unapplied cash in this store, oldest first. */
127
+ list(customerId: string, options?: Call): Promise<UnappliedCash[]>;
128
+ /**
129
+ * Pay an AR invoice with unapplied cash. The customer's balance does not
130
+ * move: the cash was already theirs.
131
+ *
132
+ * The invoice must be the same customer's, in the same currency, live and
133
+ * still owing. Refusals: `AR_INVOICE_NOT_FOUND`, `AR_CURRENCY_MISMATCH`,
134
+ * `AR_INVOICE_NOT_OPEN`, `AR_ORDER_NOT_INVOICED` (an order with no live
135
+ * invoice: invoice it first), `UNAPPLIED_CASH_EXCEEDED`,
136
+ * `UNAPPLIED_CASH_NOT_FOUND`, `UNAPPLIED_CASH_REFUND_UNRECONCILED` (a payout
137
+ * of the same cash has an unknown outcome), `AR_LEDGER_NOT_ENABLED`.
138
+ */
139
+ apply(input: ApplyUnappliedCashInput, options?: Call): Promise<UnappliedCash>;
140
+ /**
141
+ * Pay unapplied cash back to the customer: a refund of the payment it was
142
+ * taken from, with `payments.refund`'s rules and refusals. When one refuses,
143
+ * nothing has changed.
144
+ *
145
+ * At most what the cash still holds, and at most what the customer's account
146
+ * is in credit by in that currency (`UNAPPLIED_CASH_EXCEEDED`): cash is
147
+ * applied to what a customer owes before it is paid out.
148
+ *
149
+ * **`IDEMPOTENCY_OUTCOME_UNKNOWN`** means the payment provider was asked and
150
+ * never confirmed. The cash STAYS on the account and is frozen
151
+ * (`UNAPPLIED_CASH_REFUND_UNRECONCILED`). Find the attempt with
152
+ * `payments.unreconciledRefunds(orderId)`, check the provider, and record its
153
+ * answer with `payments.reconcileRefund(...)`: `MADE` takes the cash off the
154
+ * account then, `NOT_MADE` unfreezes it. Never pay out again on the
155
+ * assumption that nothing happened.
156
+ */
157
+ refund(input: RefundUnappliedCashInput, options?: Call): Promise<UnappliedCashRefund>;
158
+ /** What of an order's money is on its customer's account now. Needs `ReadOrder`. */
159
+ onOrder(orderId: string, options?: Call): Promise<OrderMoneyOnAccount>;
160
+ }
161
+ export declare const CREDIT_ORDER_OVERPAYMENT_MUTATION = "\n mutation CreditOrderOverpaymentToAccount(\n $input: CreditOrderOverpaymentInput!\n $idempotencyKey: String\n ) {\n creditOrderOverpaymentToAccount(input: $input, idempotencyKey: $idempotencyKey) {\n \n id\n customerId\n currencyCode\n amount\n applied\n refunded\n remaining\n orderId\n paymentId\n receivedOn\n reference\n notes\n createdAt\n\n }\n }\n";
162
+ export declare const UNAPPLIED_CASH_QUERY = "\n query ArUnappliedCash($customerId: ID!) {\n arUnappliedCash(customerId: $customerId) {\n \n id\n customerId\n currencyCode\n amount\n applied\n refunded\n remaining\n orderId\n paymentId\n receivedOn\n reference\n notes\n createdAt\n\n }\n }\n";
163
+ export declare const APPLY_UNAPPLIED_CASH_MUTATION = "\n mutation ApplyArUnappliedCash($input: ApplyArUnappliedCashInput!, $idempotencyKey: String) {\n applyArUnappliedCash(input: $input, idempotencyKey: $idempotencyKey) {\n \n id\n customerId\n currencyCode\n amount\n applied\n refunded\n remaining\n orderId\n paymentId\n receivedOn\n reference\n notes\n createdAt\n\n }\n }\n";
164
+ export declare const REFUND_UNAPPLIED_CASH_MUTATION = "\n mutation RefundArUnappliedCash($input: RefundArUnappliedCashInput!, $idempotencyKey: String) {\n refundArUnappliedCash(input: $input, idempotencyKey: $idempotencyKey) {\n id\n total\n state\n method\n transactionId\n reason\n }\n }\n";
165
+ /**
166
+ * Its own query, never a field added to `payments.refundPosition`'s: an SDK
167
+ * released ahead of a server without `creditedToAccount` must not break that
168
+ * read.
169
+ */
170
+ export declare const ORDER_MONEY_ON_ACCOUNT_QUERY = "\n query OrderMoneyOnAccount($orderId: ID!) {\n orderRefundPosition(orderId: $orderId) {\n currencyCode\n creditedToAccount\n perPayment {\n paymentId\n creditedToAccount\n }\n }\n }\n";
171
+ export declare function createAccountCreditModule(transport: Transport): AccountCreditModule;
@@ -0,0 +1,107 @@
1
+ const UNAPPLIED_CASH_FIELDS = /* GraphQL */ `
2
+ id
3
+ customerId
4
+ currencyCode
5
+ amount
6
+ applied
7
+ refunded
8
+ remaining
9
+ orderId
10
+ paymentId
11
+ receivedOn
12
+ reference
13
+ notes
14
+ createdAt
15
+ `;
16
+ export const CREDIT_ORDER_OVERPAYMENT_MUTATION = /* GraphQL */ `
17
+ mutation CreditOrderOverpaymentToAccount(
18
+ $input: CreditOrderOverpaymentInput!
19
+ $idempotencyKey: String
20
+ ) {
21
+ creditOrderOverpaymentToAccount(input: $input, idempotencyKey: $idempotencyKey) {
22
+ ${UNAPPLIED_CASH_FIELDS}
23
+ }
24
+ }
25
+ `;
26
+ export const UNAPPLIED_CASH_QUERY = /* GraphQL */ `
27
+ query ArUnappliedCash($customerId: ID!) {
28
+ arUnappliedCash(customerId: $customerId) {
29
+ ${UNAPPLIED_CASH_FIELDS}
30
+ }
31
+ }
32
+ `;
33
+ export const APPLY_UNAPPLIED_CASH_MUTATION = /* GraphQL */ `
34
+ mutation ApplyArUnappliedCash($input: ApplyArUnappliedCashInput!, $idempotencyKey: String) {
35
+ applyArUnappliedCash(input: $input, idempotencyKey: $idempotencyKey) {
36
+ ${UNAPPLIED_CASH_FIELDS}
37
+ }
38
+ }
39
+ `;
40
+ export const REFUND_UNAPPLIED_CASH_MUTATION = /* GraphQL */ `
41
+ mutation RefundArUnappliedCash($input: RefundArUnappliedCashInput!, $idempotencyKey: String) {
42
+ refundArUnappliedCash(input: $input, idempotencyKey: $idempotencyKey) {
43
+ id
44
+ total
45
+ state
46
+ method
47
+ transactionId
48
+ reason
49
+ }
50
+ }
51
+ `;
52
+ /**
53
+ * Its own query, never a field added to `payments.refundPosition`'s: an SDK
54
+ * released ahead of a server without `creditedToAccount` must not break that
55
+ * read.
56
+ */
57
+ export const ORDER_MONEY_ON_ACCOUNT_QUERY = /* GraphQL */ `
58
+ query OrderMoneyOnAccount($orderId: ID!) {
59
+ orderRefundPosition(orderId: $orderId) {
60
+ currencyCode
61
+ creditedToAccount
62
+ perPayment {
63
+ paymentId
64
+ creditedToAccount
65
+ }
66
+ }
67
+ }
68
+ `;
69
+ export function createAccountCreditModule(transport) {
70
+ return {
71
+ async creditOverpayment(input, options) {
72
+ const data = await transport.graphql({
73
+ api: 'admin',
74
+ query: CREDIT_ORDER_OVERPAYMENT_MUTATION,
75
+ // A variable, not a header: the Admin API takes the key as an argument.
76
+ // `undefined`, never an explicit null: `JSON.stringify` drops it, so an
77
+ // omitted key stays off the wire entirely.
78
+ variables: { input, idempotencyKey: options?.idempotencyKey },
79
+ }, options);
80
+ return data.creditOrderOverpaymentToAccount;
81
+ },
82
+ async list(customerId, options) {
83
+ const data = await transport.graphql({ api: 'admin', query: UNAPPLIED_CASH_QUERY, variables: { customerId } }, options);
84
+ return data.arUnappliedCash;
85
+ },
86
+ async apply(input, options) {
87
+ const data = await transport.graphql({
88
+ api: 'admin',
89
+ query: APPLY_UNAPPLIED_CASH_MUTATION,
90
+ variables: { input, idempotencyKey: options?.idempotencyKey },
91
+ }, options);
92
+ return data.applyArUnappliedCash;
93
+ },
94
+ async refund(input, options) {
95
+ const data = await transport.graphql({
96
+ api: 'admin',
97
+ query: REFUND_UNAPPLIED_CASH_MUTATION,
98
+ variables: { input, idempotencyKey: options?.idempotencyKey },
99
+ }, options);
100
+ return data.refundArUnappliedCash;
101
+ },
102
+ async onOrder(orderId, options) {
103
+ const data = await transport.graphql({ api: 'admin', query: ORDER_MONEY_ON_ACCOUNT_QUERY, variables: { orderId } }, options);
104
+ return data.orderRefundPosition;
105
+ },
106
+ };
107
+ }
@@ -1,5 +1,6 @@
1
1
  import type { Transport } from '@sixtyninecommerce/core';
2
2
  import type { Call } from '../types.js';
3
+ import { type AccountCreditModule } from './account-credit.js';
3
4
  import { type ProvidersModule } from './providers.js';
4
5
  /**
5
6
  * What an order has actually been paid, in minor units of its own currency.
@@ -16,13 +17,20 @@ export interface OrderPaymentPosition {
16
17
  settled: number;
17
18
  /** Money a payment handler may take and has not. */
18
19
  authorized: number;
20
+ /**
21
+ * Refunds recorded against the order's payments. Money moved to the
22
+ * customer's account (`payments.accountCredit`) is NOT a refund and is not
23
+ * counted here, though it is taken off `settled` like one.
24
+ */
19
25
  refunded: number;
20
26
  /** `total - covered`, floored at zero. */
21
27
  outstanding: number;
22
28
  /**
23
29
  * `covered - total`, floored at zero. Over-payment is refused at the door, so
24
- * this is non-zero only for imported history, rows predating the guard, or a
25
- * refund that landed after a second payment.
30
+ * this is non-zero only for imported history, rows predating the guard, a
31
+ * refund that landed after a second payment, or an edit that lowered the
32
+ * total of a paid order. Money moved to the customer's account
33
+ * (`payments.accountCredit.creditOverpayment`) no longer counts here.
26
34
  */
27
35
  overpaid: number;
28
36
  /** What a further payment may take. */
@@ -62,9 +70,18 @@ export interface RefundablePayment {
62
70
  method: string | null;
63
71
  /** Gross amount taken, minor units. */
64
72
  amount: number;
65
- /** Non-failed refunds already recorded against it. A failed refund never left. */
73
+ /**
74
+ * Refunds already recorded against it that did not fail, plus failed ones
75
+ * whose outcome is unknown — reserved until the provider's answer is recorded
76
+ * (see {@link PaymentsModule.unreconciledRefunds}). A plainly failed refund
77
+ * never left.
78
+ */
66
79
  refunded: number;
67
- /** `amount - refunded` when this payment took money, floored at zero; else zero. */
80
+ /**
81
+ * `amount - refunded`, less what of this payment is on the customer's account
82
+ * (`payments.accountCredit.onOrder`), when this payment took money; floored
83
+ * at zero, else zero.
84
+ */
68
85
  refundable: number;
69
86
  /**
70
87
  * Whether this payment took money at all.
@@ -96,11 +113,49 @@ export interface OrderRefundPosition {
96
113
  * There is deliberately no credit-note deduction. A credit note that moved
97
114
  * money already has its refund on the payment; one that moved none has
98
115
  * nothing to deduct.
116
+ *
117
+ * Money moved to the customer's account as unapplied cash IS deducted: it is
118
+ * paid back from the account (`payments.accountCredit.refund`), never from
119
+ * the order a second time.
99
120
  */
100
121
  refundable: number;
101
122
  /** Every payment on the order, NEWEST FIRST, with its own headroom. */
102
123
  perPayment: RefundablePayment[];
103
124
  }
125
+ /**
126
+ * A refund whose outcome is unknown: it reached its payment provider and was
127
+ * never confirmed (a timeout, a dropped connection, a server error), so the
128
+ * platform cannot say whether the money moved. Its amount is reserved — counted
129
+ * in the refund position's `refunded` — until
130
+ * {@link PaymentsModule.reconcileRefund} records the provider's answer.
131
+ */
132
+ export interface UnreconciledRefund {
133
+ /** The refund to pass to `reconcileRefund`. */
134
+ refundId: string;
135
+ paymentId: string;
136
+ /** Minor units of the order's currency. */
137
+ amount: number;
138
+ /** ISO-8601 with offset. */
139
+ createdAt: string | null;
140
+ }
141
+ /** What the payment provider says happened to a refund whose outcome was unknown. */
142
+ export type RefundProviderOutcome = 'MADE' | 'NOT_MADE';
143
+ /** The provider's answer for a refund whose outcome is unknown. */
144
+ export interface ReconcileRefundInput {
145
+ refundId: string;
146
+ /**
147
+ * `MADE`: the money went back. `NOT_MADE`: nothing moved. Checked with the
148
+ * provider — never guessed.
149
+ */
150
+ outcome: RefundProviderOutcome;
151
+ /**
152
+ * The provider's reference for its answer: its refund id when it made one, or
153
+ * where the answer was checked. Required, at most 200 characters.
154
+ */
155
+ providerReference: string;
156
+ /** Optional context for the order's history, at most 1000 characters. */
157
+ note?: string;
158
+ }
104
159
  /** Money handed back to a customer. */
105
160
  export interface RefundPaymentInput {
106
161
  orderId: string;
@@ -146,6 +201,65 @@ export interface PaidOrder {
146
201
  total: number;
147
202
  totalWithTax: number;
148
203
  }
204
+ /** What a payment app reports happened to a payment it took (`reportAppPayment`). */
205
+ export type AppPaymentReportState = 'Authorized' | 'Settled' | 'Declined' | 'Cancelled';
206
+ /** An app's report on one of its payments. */
207
+ export interface ReportAppPaymentInput {
208
+ /**
209
+ * What the provider did. An authorized payment can be reported `Settled`,
210
+ * `Declined` or `Cancelled`; a payment whose outcome is unknown (see
211
+ * {@link AppPayment}) only `Settled` or `Declined` — the provider knows
212
+ * whether it took the money.
213
+ *
214
+ * `Authorized` is for ONE case: you answered `create` `Authorized` with a
215
+ * `redirect_url`, and the buyer finished your hosted page with the money
216
+ * authorized, to be captured later (pay later, capture at shipment). Until
217
+ * you report, the order stays the buyer's unplaced cart; this report places
218
+ * it (`PaymentAuthorized`) when the payment covers it. A later `Settled`
219
+ * report, or the store capturing it (your `capture` hook), settles it. Any
220
+ * other payment reported `Authorized` is `PAYMENT_STATE_NOT_REPORTABLE`.
221
+ */
222
+ state: AppPaymentReportState;
223
+ /**
224
+ * The provider's reference for the payment, at most 255 characters. When the
225
+ * app answered `create` with one, it must be that one.
226
+ */
227
+ providerReference: string;
228
+ /** Minor units of the order's currency. Must equal the payment's amount. */
229
+ amount: number;
230
+ }
231
+ /** A payment an app took, as the installation that took it reads it. */
232
+ export interface AppPayment {
233
+ id: string;
234
+ orderId: string;
235
+ orderCode: string;
236
+ /** Vendure's payment state: `Authorized`, `Settled`, `Declined`, `Error`, `Cancelled`. */
237
+ state: string;
238
+ /** Minor units. */
239
+ amount: number;
240
+ currencyCode: string;
241
+ /** The provider's reference — the payment's `transactionId` — once the app gave one. */
242
+ providerReference: string | null;
243
+ methodCode: string;
244
+ /**
245
+ * The platform asked the app (create, or capture) and never heard back, so
246
+ * whether the money moved is unknown. The platform does NOT ask again (a
247
+ * second request could be a second charge): report the outcome with
248
+ * {@link PaymentsModule.reportAppPayment}.
249
+ */
250
+ outcomeUnknown: boolean;
251
+ /** ISO-8601 with offset. */
252
+ createdAt: string;
253
+ }
254
+ /** The payment as it stands after an app's report. */
255
+ export interface ReportedAppPayment {
256
+ id: string;
257
+ state: string;
258
+ /** Minor units. */
259
+ amount: number;
260
+ method: string;
261
+ transactionId: string | null;
262
+ }
149
263
  /**
150
264
  * Payments: money against an order (spec §8.2), and the provider accounts
151
265
  * it runs through (spec §8.9).
@@ -165,6 +279,11 @@ export interface PaidOrder {
165
279
  export interface PaymentsModule {
166
280
  /** Provider onboarding, terminals and readiness (spec §8.9). */
167
281
  providers: ProvidersModule;
282
+ /**
283
+ * An order's overpayment on the customer's account: move it there, apply it
284
+ * to an invoice, pay it back.
285
+ */
286
+ accountCredit: AccountCreditModule;
168
287
  /**
169
288
  * Record part (or all) of what an order owes, and return the order.
170
289
  *
@@ -196,15 +315,38 @@ export interface PaymentsModule {
196
315
  * argument — so a retry under the same key returns the FIRST call's refund
197
316
  * instead of raising a second one. Use a fresh key per intended refund.
198
317
  *
199
- * **`IDEMPOTENCY_OUTCOME_UNKNOWN` is neither success nor refusal.** The engine
200
- * calls the payment gateway from inside the transaction that writes the refund
318
+ * **`error.outcomeUnknown` has two causes here, and they recover differently.**
319
+ *
320
+ * 1. **No answer came back** (a timeout, your own signal aborting the call
321
+ * after it was sent, a dropped connection, a proxy's 502/504). The first
322
+ * call may still be running on the server and its key is NOT spent, so
323
+ * repeat the call under the SAME key, never a new one. The
324
+ * platform then answers with the first call's refund, with
325
+ * `IDEMPOTENCY_IN_PROGRESS` (wait, then repeat again under that key), or
326
+ * with `IDEMPOTENCY_OUTCOME_UNKNOWN` (case 2). A NEW key here can refund
327
+ * twice: the second request waits on the order lock until the first one
328
+ * commits, and then both fit under the ceiling. A call made without a key
329
+ * has no safe repeat: once the first call can have finished, read
330
+ * `payments.refundPosition(orderId)` and reconcile against the gateway.
331
+ * 2. **`IDEMPOTENCY_OUTCOME_UNKNOWN`** is neither success nor refusal. It
332
+ * arrives as a `ConflictError` (409) because the key is spent, but the class
333
+ * is not the message: branch on the code, or on `error.outcomeUnknown`. The
334
+ * engine calls the payment gateway from inside the transaction that writes the refund
201
335
  * row, so a failure after that call leaves an outcome nobody can read off the
202
336
  * database: the money may be on its way back with no row to show for it. You
203
337
  * get this code on the FIRST call when that happens, and on every repeat under
204
338
  * the same key — the key is spent rather than released, so the refund never
205
- * runs again. Do NOT treat it as `REFUND_REFUSED`: read
206
- * `payments.refundPosition(orderId)`, reconcile against the gateway, and only
207
- * then decide. If the money did not move, issue a new request under a NEW key.
339
+ * runs again. Do NOT treat it as `REFUND_REFUSED`: the attempt is recorded as
340
+ * a refund whose outcome is unknown, and its amount stays RESERVED in the
341
+ * position — this call, the till, credit notes, returns and core's own
342
+ * `refundOrder` mutation (the dashboard's Refund button) no longer refund
343
+ * the order or that payment past what they took. The reservation does NOT
344
+ * stop a new request for the same
345
+ * partial amount while headroom remains, so never retry under a new key
346
+ * blindly. Find the attempt with `payments.unreconciledRefunds(orderId)`,
347
+ * check the gateway, and record the answer with `payments.reconcileRefund(...)`.
348
+ * After `MADE` the spent key replays that refund; after `NOT_MADE` it may run
349
+ * again, and the amount is refundable again.
208
350
  *
209
351
  * (The server also attaches the position to that error, but `PlatformError`
210
352
  * carries only `code`, `message`, `details` and `traceId`, so an SDK caller
@@ -235,10 +377,93 @@ export interface PaymentsModule {
235
377
  refund(input: RefundPaymentInput, options?: Call): Promise<IssuedRefund>;
236
378
  /** Read what an order may still hand back. */
237
379
  refundPosition(orderId: string, options?: Call): Promise<OrderRefundPosition>;
380
+ /**
381
+ * The order's refunds whose outcome is unknown, oldest first — the ones
382
+ * {@link reconcileRefund} resolves. Each one's amount is already reserved in
383
+ * {@link refundPosition}.
384
+ *
385
+ * A refund lands here when its payment provider was asked and never
386
+ * confirmed: `refund` answered `IDEMPOTENCY_OUTCOME_UNKNOWN`, or a till card
387
+ * refund, a credit note or a return settlement did. Needs `ReadOrder`.
388
+ */
389
+ unreconciledRefunds(orderId: string, options?: Call): Promise<UnreconciledRefund[]>;
390
+ /**
391
+ * Record the payment provider's answer for a refund whose outcome is unknown.
392
+ * Needs `UpdateOrder` — the permission refunds take.
393
+ *
394
+ * - `MADE`: the money went back. The refund becomes `Settled` as if the
395
+ * provider had confirmed it at the time: it counts as returned, a return
396
+ * parked on it completes its settlement, and `payment.refunded` is
397
+ * announced. The key that spent itself on the attempt now replays it.
398
+ * - `NOT_MADE`: nothing moved. The refund stays `Failed`, its reservation is
399
+ * released and a retry is allowed — the spent key, a till refund, the credit
400
+ * note, or settling the parked return again.
401
+ *
402
+ * The outcome is kept on the refund's metadata, which the Shop API serves, so
403
+ * nothing else goes there: `providerReference`, `note` and who recorded it go
404
+ * to a private order note and the audit trail.
405
+ *
406
+ * Refusals: `REFUND_NOT_FOUND`, `REFUND_OUTCOME_NOT_UNKNOWN` (the outcome is
407
+ * already known — never unknown, or reconciled already),
408
+ * `REFUND_RECONCILIATION_INVALID` (a blank or oversized `providerReference`,
409
+ * an oversized `note`), and `REFUND_EXCEEDS_PAYMENT` when `MADE` would have
410
+ * the payment return more than it took (another refund on record against it
411
+ * cannot be right).
412
+ *
413
+ * `options.idempotencyKey` is honoured: a repeat under the same key returns
414
+ * the first call's refund.
415
+ */
416
+ reconcileRefund(input: ReconcileRefundInput, options?: Call): Promise<IssuedRefund>;
417
+ /**
418
+ * **For a payment app, with its installation token.** Report what happened to
419
+ * a payment your app took (spec §8.14 `payment.provider`): the asynchronous
420
+ * pattern — you answered `create` `Authorized`, and the money lands later —
421
+ * and the reconciliation of a payment whose outcome is unknown (you were
422
+ * asked and the platform never received your answer; it will not ask again).
423
+ *
424
+ * The platform moves the payment through its own payment processes, exactly
425
+ * as for any provider callback: a covered order is settled and placed, money
426
+ * for a held (parked) order lands where the order stands, and
427
+ * `payment.settled` is published with your installation as its actor. A
428
+ * hosted page that only authorized is reported `Authorized` (see
429
+ * {@link ReportAppPaymentInput.state}): the order is placed on it.
430
+ *
431
+ * `options.idempotencyKey` is REQUIRED: a repeat of the same report under it
432
+ * answers the payment as it now is, for as long as the payment exists; a
433
+ * DIFFERENT report under it is refused `IDEMPOTENCY_CONFLICT` (409). Use one
434
+ * key per event you received from your provider.
435
+ *
436
+ * Refusals: `PAYMENT_NOT_OWNED_BY_INSTALLATION` (a `PermissionDeniedError`,
437
+ * 403: not a payment this installation took on this store — one answer
438
+ * whatever the reason),
439
+ * `PAYMENT_AMOUNT_MISMATCH`, `PAYMENT_STATE_NOT_REPORTABLE` (the payment
440
+ * cannot move to that state from where it is, `extensions.details.state`),
441
+ * `APP_PAYMENT_REPORT_INVALID` (a malformed report, or a reference other than
442
+ * the one `create` answered), `APP_PAYMENT_METHOD_DISABLED` (the store took
443
+ * your app off as its payment provider; a decline is still recorded),
444
+ * `IDEMPOTENCY_KEY_INVALID`.
445
+ */
446
+ reportAppPayment(paymentId: string, input: ReportAppPaymentInput, options: Call & {
447
+ idempotencyKey: string;
448
+ }): Promise<ReportedAppPayment>;
449
+ /**
450
+ * **For a payment app, with its installation token.** Your installation's
451
+ * payments on one order of this store, oldest first: how you find a
452
+ * payment's id, which the `create` call cannot carry because the payment
453
+ * does not exist until you answer. Match on `providerReference`. An order the
454
+ * store does not have answers `[]`; any caller but an installation is refused
455
+ * `PAYMENT_NOT_OWNED_BY_INSTALLATION`.
456
+ */
457
+ appPayments(orderId: string, options?: Call): Promise<AppPayment[]>;
238
458
  }
239
459
  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";
240
460
  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 outstanding\n overpaid\n availableToCharge\n\n }\n }\n";
241
461
  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";
242
462
  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";
463
+ 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";
464
+ 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";
465
+ 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";
466
+ 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";
243
467
  export declare function createPaymentsModule(transport: Transport): PaymentsModule;
468
+ export type { AccountCreditModule, ApplyUnappliedCashInput, CreditOverpaymentInput, OrderMoneyOnAccount, RefundUnappliedCashInput, UnappliedCash, UnappliedCashRefund, } from './account-credit.js';
244
469
  export type { ProviderConnection, ProviderCredentialPath, ProviderOnboardingStart, ProviderReadiness, ProvidersModule, ProviderTerminal, ProviderTerminalsModule, ProvisionTerminalInput, ReadinessOptions, } from './providers.js';