@sixtyninecommerce/admin 0.7.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.
- package/README.md +2445 -17
- package/dist/api-tokens/index.d.ts +15 -5
- package/dist/api-tokens/index.js +1 -0
- package/dist/apps/event-subscription.d.ts +59 -0
- package/dist/apps/event-subscription.js +32 -0
- package/dist/apps/hook-secret.d.ts +22 -0
- package/dist/apps/hook-secret.js +36 -0
- package/dist/apps/index.d.ts +54 -3
- package/dist/apps/index.js +17 -0
- package/dist/audit/index.d.ts +7 -0
- package/dist/auth/queries.d.ts +5 -1
- package/dist/auth/queries.js +6 -0
- package/dist/bulk/index.d.ts +323 -0
- package/dist/bulk/index.js +162 -0
- package/dist/catalog/assets.d.ts +147 -0
- package/dist/catalog/assets.js +164 -0
- package/dist/catalog/collections.d.ts +109 -0
- package/dist/catalog/collections.js +91 -0
- package/dist/catalog/facets.d.ts +103 -0
- package/dist/catalog/facets.js +100 -0
- package/dist/catalog/index.d.ts +115 -0
- package/dist/catalog/index.js +21 -0
- package/dist/catalog/options.d.ts +89 -0
- package/dist/catalog/options.js +88 -0
- package/dist/catalog/products-bulk.d.ts +21 -0
- package/dist/catalog/products-bulk.js +58 -0
- package/dist/catalog/products.d.ts +489 -0
- package/dist/catalog/products.js +365 -0
- package/dist/catalog/properties.d.ts +234 -0
- package/dist/catalog/properties.js +158 -0
- package/dist/catalog/types.d.ts +174 -0
- package/dist/catalog/types.js +141 -0
- package/dist/catalog/variants.d.ts +274 -0
- package/dist/catalog/variants.js +258 -0
- package/dist/catalog/visibility.d.ts +57 -0
- package/dist/catalog/visibility.js +59 -0
- package/dist/client.d.ts +171 -3
- package/dist/client.js +81 -12
- package/dist/compliance/index.d.ts +88 -0
- package/dist/compliance/index.js +88 -0
- package/dist/customer-data-redaction.d.ts +14 -0
- package/dist/customer-data-redaction.js +22 -0
- package/dist/customers/index.d.ts +428 -17
- package/dist/customers/index.js +322 -15
- package/dist/documents/index.d.ts +513 -16
- package/dist/documents/index.js +229 -3
- package/dist/events/index.d.ts +259 -0
- package/dist/events/index.js +147 -0
- package/dist/feeds/ai.d.ts +46 -0
- package/dist/feeds/ai.js +43 -0
- package/dist/feeds/categories.d.ts +50 -0
- package/dist/feeds/categories.js +56 -0
- package/dist/feeds/configs.d.ts +54 -0
- package/dist/feeds/configs.js +85 -0
- package/dist/feeds/identifier-fields.d.ts +25 -0
- package/dist/feeds/identifier-fields.js +29 -0
- package/dist/feeds/index.d.ts +54 -0
- package/dist/feeds/index.js +46 -0
- package/dist/feeds/preserve.d.ts +38 -0
- package/dist/feeds/preserve.js +74 -0
- package/dist/feeds/rules.d.ts +42 -0
- package/dist/feeds/rules.js +56 -0
- package/dist/feeds/types.d.ts +654 -0
- package/dist/feeds/types.js +135 -0
- package/dist/fulfillments/index.d.ts +360 -0
- package/dist/fulfillments/index.js +425 -0
- package/dist/heads/index.d.ts +60 -0
- package/dist/heads/index.js +45 -0
- package/dist/hooks/assignments.d.ts +90 -0
- package/dist/hooks/assignments.js +53 -0
- package/dist/hooks/index.d.ts +97 -0
- package/dist/hooks/index.js +76 -0
- package/dist/index.d.ts +84 -9
- package/dist/index.js +16 -1
- package/dist/jobs/bulk-action-run.d.ts +65 -0
- package/dist/jobs/bulk-action-run.js +70 -0
- package/dist/locations/index.d.ts +6 -2
- package/dist/meta/index.d.ts +32 -0
- package/dist/orders/commit-edit.d.ts +123 -0
- package/dist/orders/commit-edit.js +142 -0
- package/dist/orders/get.d.ts +722 -0
- package/dist/orders/get.js +530 -0
- package/dist/orders/index.d.ts +105 -20
- package/dist/orders/index.js +44 -0
- package/dist/orders/line-price-preview.d.ts +297 -0
- package/dist/orders/line-price-preview.js +50 -0
- package/dist/orders/manual-discounts.d.ts +132 -0
- package/dist/orders/manual-discounts.js +95 -0
- package/dist/orders/manual-pricing.d.ts +192 -0
- package/dist/orders/manual-pricing.js +72 -0
- package/dist/orders/order-entry.d.ts +566 -0
- package/dist/orders/order-entry.js +129 -0
- package/dist/orders/parcel-charge.d.ts +45 -0
- package/dist/orders/parcel-charge.js +55 -0
- package/dist/orders/plan-edit.d.ts +489 -0
- package/dist/orders/plan-edit.js +93 -0
- package/dist/orders/status.d.ts +235 -0
- package/dist/orders/status.js +96 -0
- package/dist/orders/surcharges.d.ts +75 -2
- package/dist/orders/surcharges.js +110 -4
- package/dist/payments/account-credit.d.ts +171 -0
- package/dist/payments/account-credit.js +107 -0
- package/dist/payments/index.d.ts +368 -2
- package/dist/payments/index.js +138 -0
- package/dist/platform/catalog.d.ts +148 -0
- package/dist/platform/catalog.js +74 -0
- package/dist/platform/entitlements.d.ts +111 -0
- package/dist/platform/entitlements.js +86 -0
- package/dist/platform/legal-entities.d.ts +139 -0
- package/dist/platform/legal-entities.js +126 -0
- package/dist/platform/legal-entity-numbering.d.ts +103 -0
- package/dist/platform/legal-entity-numbering.js +101 -0
- package/dist/platform/organization-membership.d.ts +80 -0
- package/dist/platform/organization-membership.js +71 -0
- package/dist/platform/organization-settings.d.ts +33 -0
- package/dist/platform/organization-settings.js +42 -0
- package/dist/platform/organization-sharing.d.ts +172 -0
- package/dist/platform/organization-sharing.js +120 -0
- package/dist/platform/organizations.d.ts +205 -0
- package/dist/platform/organizations.js +180 -0
- package/dist/platform/provision-store.d.ts +88 -8
- package/dist/platform/provision-store.js +12 -0
- package/dist/platform/reports.d.ts +46 -0
- package/dist/platform/reports.js +31 -0
- package/dist/platform/server-metrics.d.ts +58 -0
- package/dist/platform/server-metrics.js +11 -0
- package/dist/pos/index.d.ts +567 -0
- package/dist/pos/index.js +205 -0
- package/dist/pricing/index.d.ts +405 -0
- package/dist/pricing/index.js +351 -0
- package/dist/provenance/index.d.ts +93 -0
- package/dist/provenance/index.js +53 -0
- package/dist/reports/index.d.ts +199 -0
- package/dist/reports/index.js +154 -0
- package/dist/shipping/parcel-count-suggestion.d.ts +52 -0
- package/dist/shipping/parcel-count-suggestion.js +73 -0
- package/dist/shipping/parcel-rule.d.ts +48 -0
- package/dist/shipping/parcel-rule.js +91 -0
- package/dist/stock/index.d.ts +166 -0
- package/dist/stock/index.js +115 -0
- package/dist/stock/transfers.d.ts +520 -0
- package/dist/stock/transfers.js +437 -0
- package/dist/stored-value/index.d.ts +154 -0
- package/dist/stored-value/index.js +130 -0
- package/dist/tenant/capabilities.d.ts +10 -0
- package/dist/tenant/entitlements.d.ts +35 -0
- package/dist/tenant/entitlements.js +15 -0
- package/dist/tenant/field-groups.d.ts +64 -0
- package/dist/tenant/field-groups.js +34 -0
- package/dist/tenant/legal-entity.d.ts +32 -0
- package/dist/tenant/legal-entity.js +41 -0
- package/dist/tenant/notifications.d.ts +148 -0
- package/dist/tenant/notifications.js +79 -0
- package/dist/tenant/retention.d.ts +10 -4
- package/dist/tenant/settings-sources.d.ts +103 -0
- package/dist/tenant/settings-sources.js +92 -0
- package/dist/types.d.ts +86 -11
- package/dist/uploads/index.d.ts +11 -7
- package/dist/users/index.d.ts +104 -0
- package/dist/users/index.js +80 -0
- package/package.json +3 -2
package/dist/payments/index.d.ts
CHANGED
|
@@ -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,
|
|
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. */
|
|
@@ -51,6 +59,139 @@ export interface RecordPaymentInput {
|
|
|
51
59
|
*/
|
|
52
60
|
metadata?: Record<string, unknown>;
|
|
53
61
|
}
|
|
62
|
+
/**
|
|
63
|
+
* One payment's contribution to an order's refund position.
|
|
64
|
+
*/
|
|
65
|
+
export interface RefundablePayment {
|
|
66
|
+
paymentId: string;
|
|
67
|
+
/** Vendure's payment state. */
|
|
68
|
+
state: string;
|
|
69
|
+
/** The payment method code, or null when the payment carries no label. */
|
|
70
|
+
method: string | null;
|
|
71
|
+
/** Gross amount taken, minor units. */
|
|
72
|
+
amount: number;
|
|
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
|
+
*/
|
|
79
|
+
refunded: number;
|
|
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
|
+
*/
|
|
85
|
+
refundable: number;
|
|
86
|
+
/**
|
|
87
|
+
* Whether this payment took money at all.
|
|
88
|
+
*
|
|
89
|
+
* True for a settled payment and for an authorized one on a real gateway — a
|
|
90
|
+
* card sale at a terminal rests authorized until the webhook settles it, and
|
|
91
|
+
* that hold is real money. False for an authorized payment on an offline or
|
|
92
|
+
* net-terms method, where authorized means the money has NOT arrived.
|
|
93
|
+
*/
|
|
94
|
+
tookMoney: boolean;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* What an order may still hand back, in minor units of its own currency.
|
|
98
|
+
*
|
|
99
|
+
* A different question from {@link OrderPaymentPosition}, and the two disagree
|
|
100
|
+
* on purpose: that one nets refunds against every authorization because it
|
|
101
|
+
* answers "what is this order covered for", while this one counts only money
|
|
102
|
+
* that was actually TAKEN, because that is all a refund can return.
|
|
103
|
+
*/
|
|
104
|
+
export interface OrderRefundPosition {
|
|
105
|
+
/** The order's currency. Every amount here is in its minor units. */
|
|
106
|
+
currencyCode: string;
|
|
107
|
+
/** Money already given back out of money that was taken. */
|
|
108
|
+
refunded: number;
|
|
109
|
+
/**
|
|
110
|
+
* What may still be handed back for this order: the sum of every payment's
|
|
111
|
+
* own remaining headroom, each floored at zero.
|
|
112
|
+
*
|
|
113
|
+
* There is deliberately no credit-note deduction. A credit note that moved
|
|
114
|
+
* money already has its refund on the payment; one that moved none has
|
|
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.
|
|
120
|
+
*/
|
|
121
|
+
refundable: number;
|
|
122
|
+
/** Every payment on the order, NEWEST FIRST, with its own headroom. */
|
|
123
|
+
perPayment: RefundablePayment[];
|
|
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
|
+
}
|
|
159
|
+
/** Money handed back to a customer. */
|
|
160
|
+
export interface RefundPaymentInput {
|
|
161
|
+
orderId: string;
|
|
162
|
+
/** Minor units of the order's currency. Greater than zero. */
|
|
163
|
+
amount: number;
|
|
164
|
+
/**
|
|
165
|
+
* The payment to return the money to.
|
|
166
|
+
*
|
|
167
|
+
* Omit it and the platform allocates across the order's paying payments
|
|
168
|
+
* NEWEST FIRST: it picks the most recent one whose remaining headroom can
|
|
169
|
+
* carry the WHOLE amount. A part-paid order settles its remainder last, so
|
|
170
|
+
* that is the money a merchant means by "give some of it back".
|
|
171
|
+
*
|
|
172
|
+
* **One call refunds against ONE payment.** When the order can return the
|
|
173
|
+
* amount but no single payment can, the call is refused with
|
|
174
|
+
* `REFUND_EXCEEDS_PAYMENT` and `perPayment` shows exactly how to split it —
|
|
175
|
+
* rather than the platform spilling silently onto a payment you did not name,
|
|
176
|
+
* which is what the engine would do.
|
|
177
|
+
*/
|
|
178
|
+
paymentId?: string;
|
|
179
|
+
/** Free text stored on the refund. Shown to nobody automatically. */
|
|
180
|
+
reason?: string;
|
|
181
|
+
}
|
|
182
|
+
/** A refund, as this surface projects it. */
|
|
183
|
+
export interface IssuedRefund {
|
|
184
|
+
id: string;
|
|
185
|
+
/** Minor units. */
|
|
186
|
+
total: number;
|
|
187
|
+
/** `Pending`, `Settled` or `Failed`. */
|
|
188
|
+
state: string;
|
|
189
|
+
/** The payment method the refund was booked against. */
|
|
190
|
+
method: string | null;
|
|
191
|
+
/** The gateway's own receipt, when it gave one. */
|
|
192
|
+
transactionId: string | null;
|
|
193
|
+
reason: string | null;
|
|
194
|
+
}
|
|
54
195
|
/** The order, as much of it as this surface projects. */
|
|
55
196
|
export interface PaidOrder {
|
|
56
197
|
id: string;
|
|
@@ -60,6 +201,65 @@ export interface PaidOrder {
|
|
|
60
201
|
total: number;
|
|
61
202
|
totalWithTax: number;
|
|
62
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
|
+
}
|
|
63
263
|
/**
|
|
64
264
|
* Payments: money against an order (spec §8.2), and the provider accounts
|
|
65
265
|
* it runs through (spec §8.9).
|
|
@@ -79,6 +279,11 @@ export interface PaidOrder {
|
|
|
79
279
|
export interface PaymentsModule {
|
|
80
280
|
/** Provider onboarding, terminals and readiness (spec §8.9). */
|
|
81
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;
|
|
82
287
|
/**
|
|
83
288
|
* Record part (or all) of what an order owes, and return the order.
|
|
84
289
|
*
|
|
@@ -96,8 +301,169 @@ export interface PaymentsModule {
|
|
|
96
301
|
record(orderId: string, input: RecordPaymentInput, options?: Call): Promise<PaidOrder>;
|
|
97
302
|
/** Read an order's payment position. */
|
|
98
303
|
position(orderId: string, options?: Call): Promise<OrderPaymentPosition>;
|
|
304
|
+
/**
|
|
305
|
+
* Hand money back to a customer, never more than the order took.
|
|
306
|
+
*
|
|
307
|
+
* The platform's own refund ceiling, and the one the four surfaces that issue
|
|
308
|
+
* refunds — returns settlement, credit notes, the till and the order importer
|
|
309
|
+
* — are measured against. Refuses `REFUND_EXCEEDS_SETTLED` when the amount is
|
|
310
|
+
* more than the whole ORDER can return, which is the check no per-payment
|
|
311
|
+
* arithmetic can make: another surface may have refunded the rest of it ten
|
|
312
|
+
* seconds ago.
|
|
313
|
+
*
|
|
314
|
+
* `options.idempotencyKey` is honoured — the Admin API takes it as a mutation
|
|
315
|
+
* argument — so a retry under the same key returns the FIRST call's refund
|
|
316
|
+
* instead of raising a second one. Use a fresh key per intended refund.
|
|
317
|
+
*
|
|
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
|
|
335
|
+
* row, so a failure after that call leaves an outcome nobody can read off the
|
|
336
|
+
* database: the money may be on its way back with no row to show for it. You
|
|
337
|
+
* get this code on the FIRST call when that happens, and on every repeat under
|
|
338
|
+
* the same key — the key is spent rather than released, so the refund never
|
|
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.
|
|
350
|
+
*
|
|
351
|
+
* (The server also attaches the position to that error, but `PlatformError`
|
|
352
|
+
* carries only `code`, `message`, `details` and `traceId`, so an SDK caller
|
|
353
|
+
* reads it with `refundPosition(orderId)` rather than off the error.)
|
|
354
|
+
*
|
|
355
|
+
* Only money that was TAKEN can come back: a settled payment, or an
|
|
356
|
+
* authorized one on a real gateway. An offline or net-terms authorization
|
|
357
|
+
* took nothing and is refused with `REFUND_PAYMENT_HOLDS_NO_MONEY`.
|
|
358
|
+
*
|
|
359
|
+
* **The refund you get back is one that moved money.** On an OFFLINE method —
|
|
360
|
+
* bank transfer, invoice, cash, an imported order's historical tender — it
|
|
361
|
+
* comes back `Settled`, because there the money moves by hand and recording
|
|
362
|
+
* it is the settlement. On a live gateway it comes back `Pending` and settles
|
|
363
|
+
* when the gateway calls back. A method whose handler cannot be resolved at
|
|
364
|
+
* all, because it is disabled or no longer on this store, is refused
|
|
365
|
+
* `REFUND_METHOD_UNAVAILABLE` before anything is created, with the payment and
|
|
366
|
+
* the method in `extensions.details`.
|
|
367
|
+
*
|
|
368
|
+
* Other refusals: `REFUND_EXCEEDS_PAYMENT` (the order can return this much,
|
|
369
|
+
* but no single payment can — split it, using `perPayment`),
|
|
370
|
+
* `REFUND_PAYMENT_NOT_FOUND`, `REFUND_AMOUNT_NOT_POSITIVE`,
|
|
371
|
+
* `REFUND_ORDER_NOT_FOUND`, and `REFUND_REFUSED` when the money was there and
|
|
372
|
+
* the engine or the gateway said no anyway. Every refusal raised once the
|
|
373
|
+
* order has been read carries that order's position in
|
|
374
|
+
* `extensions.refundPosition`, so a till can correct itself without a second
|
|
375
|
+
* round trip.
|
|
376
|
+
*/
|
|
377
|
+
refund(input: RefundPaymentInput, options?: Call): Promise<IssuedRefund>;
|
|
378
|
+
/** Read what an order may still hand back. */
|
|
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[]>;
|
|
99
458
|
}
|
|
100
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";
|
|
101
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";
|
|
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";
|
|
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";
|
|
102
467
|
export declare function createPaymentsModule(transport: Transport): PaymentsModule;
|
|
468
|
+
export type { AccountCreditModule, ApplyUnappliedCashInput, CreditOverpaymentInput, OrderMoneyOnAccount, RefundUnappliedCashInput, UnappliedCash, UnappliedCashRefund, } from './account-credit.js';
|
|
103
469
|
export type { ProviderConnection, ProviderCredentialPath, ProviderOnboardingStart, ProviderReadiness, ProvidersModule, ProviderTerminal, ProviderTerminalsModule, ProvisionTerminalInput, ReadinessOptions, } from './providers.js';
|
package/dist/payments/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { createAccountCreditModule } from './account-credit.js';
|
|
1
2
|
import { createProvidersModule } from './providers.js';
|
|
2
3
|
const PAID_ORDER_FIELDS = /* GraphQL */ `
|
|
3
4
|
id
|
|
@@ -31,9 +32,98 @@ export const ORDER_PAYMENT_POSITION_QUERY = /* GraphQL */ `
|
|
|
31
32
|
}
|
|
32
33
|
}
|
|
33
34
|
`;
|
|
35
|
+
const REFUND_POSITION_FIELDS = /* GraphQL */ `
|
|
36
|
+
currencyCode
|
|
37
|
+
refunded
|
|
38
|
+
refundable
|
|
39
|
+
perPayment {
|
|
40
|
+
paymentId
|
|
41
|
+
state
|
|
42
|
+
method
|
|
43
|
+
amount
|
|
44
|
+
refunded
|
|
45
|
+
refundable
|
|
46
|
+
tookMoney
|
|
47
|
+
}
|
|
48
|
+
`;
|
|
49
|
+
export const ORDER_REFUND_POSITION_QUERY = /* GraphQL */ `
|
|
50
|
+
query OrderRefundPosition($orderId: ID!) {
|
|
51
|
+
orderRefundPosition(orderId: $orderId) {
|
|
52
|
+
${REFUND_POSITION_FIELDS}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
`;
|
|
56
|
+
export const REFUND_ORDER_PAYMENT_MUTATION = /* GraphQL */ `
|
|
57
|
+
mutation RefundOrderPayment($input: RefundPaymentInput!, $idempotencyKey: String) {
|
|
58
|
+
refundOrderPayment(input: $input, idempotencyKey: $idempotencyKey) {
|
|
59
|
+
id
|
|
60
|
+
total
|
|
61
|
+
state
|
|
62
|
+
method
|
|
63
|
+
transactionId
|
|
64
|
+
reason
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
`;
|
|
68
|
+
export const UNRECONCILED_REFUNDS_QUERY = /* GraphQL */ `
|
|
69
|
+
query UnreconciledRefunds($orderId: ID!) {
|
|
70
|
+
orderRefundPosition(orderId: $orderId) {
|
|
71
|
+
unreconciled {
|
|
72
|
+
refundId
|
|
73
|
+
paymentId
|
|
74
|
+
amount
|
|
75
|
+
createdAt
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
`;
|
|
80
|
+
export const RECONCILE_REFUND_OUTCOME_MUTATION = /* GraphQL */ `
|
|
81
|
+
mutation ReconcileRefundOutcome($input: ReconcileRefundOutcomeInput!, $idempotencyKey: String) {
|
|
82
|
+
reconcileRefundOutcome(input: $input, idempotencyKey: $idempotencyKey) {
|
|
83
|
+
id
|
|
84
|
+
total
|
|
85
|
+
state
|
|
86
|
+
method
|
|
87
|
+
transactionId
|
|
88
|
+
reason
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
`;
|
|
92
|
+
export const REPORT_APP_PAYMENT_MUTATION = /* GraphQL */ `
|
|
93
|
+
mutation ReportAppPayment(
|
|
94
|
+
$paymentId: ID!
|
|
95
|
+
$input: ReportAppPaymentInput!
|
|
96
|
+
$idempotencyKey: String!
|
|
97
|
+
) {
|
|
98
|
+
reportAppPayment(paymentId: $paymentId, input: $input, idempotencyKey: $idempotencyKey) {
|
|
99
|
+
id
|
|
100
|
+
state
|
|
101
|
+
amount
|
|
102
|
+
method
|
|
103
|
+
transactionId
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
`;
|
|
107
|
+
export const APP_PAYMENTS_QUERY = /* GraphQL */ `
|
|
108
|
+
query AppPayments($orderId: ID!) {
|
|
109
|
+
appPayments(orderId: $orderId) {
|
|
110
|
+
id
|
|
111
|
+
orderId
|
|
112
|
+
orderCode
|
|
113
|
+
state
|
|
114
|
+
amount
|
|
115
|
+
currencyCode
|
|
116
|
+
providerReference
|
|
117
|
+
methodCode
|
|
118
|
+
outcomeUnknown
|
|
119
|
+
createdAt
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
`;
|
|
34
123
|
export function createPaymentsModule(transport) {
|
|
35
124
|
return {
|
|
36
125
|
providers: createProvidersModule(transport),
|
|
126
|
+
accountCredit: createAccountCreditModule(transport),
|
|
37
127
|
async record(orderId, input, options) {
|
|
38
128
|
const data = await transport.graphql({
|
|
39
129
|
api: 'admin',
|
|
@@ -51,5 +141,53 @@ export function createPaymentsModule(transport) {
|
|
|
51
141
|
const data = await transport.graphql({ api: 'admin', query: ORDER_PAYMENT_POSITION_QUERY, variables: { orderId } }, options);
|
|
52
142
|
return data.orderPaymentPosition;
|
|
53
143
|
},
|
|
144
|
+
async refund(input, options) {
|
|
145
|
+
const data = await transport.graphql({
|
|
146
|
+
api: 'admin',
|
|
147
|
+
query: REFUND_ORDER_PAYMENT_MUTATION,
|
|
148
|
+
// Forwarded as a VARIABLE, not a header: the Admin API has no header
|
|
149
|
+
// for it. `undefined`, never an explicit null — `JSON.stringify` drops
|
|
150
|
+
// it, so an omitted key stays off the wire entirely.
|
|
151
|
+
variables: { input, idempotencyKey: options?.idempotencyKey },
|
|
152
|
+
}, options);
|
|
153
|
+
return data.refundOrderPayment;
|
|
154
|
+
},
|
|
155
|
+
async refundPosition(orderId, options) {
|
|
156
|
+
const data = await transport.graphql({ api: 'admin', query: ORDER_REFUND_POSITION_QUERY, variables: { orderId } }, options);
|
|
157
|
+
return data.orderRefundPosition;
|
|
158
|
+
},
|
|
159
|
+
// Its own query rather than a field on `refundPosition`'s: an SDK released
|
|
160
|
+
// ahead of a server without `unreconciled` must not break that read.
|
|
161
|
+
async unreconciledRefunds(orderId, options) {
|
|
162
|
+
const data = await transport.graphql({ api: 'admin', query: UNRECONCILED_REFUNDS_QUERY, variables: { orderId } }, options);
|
|
163
|
+
return data.orderRefundPosition.unreconciled;
|
|
164
|
+
},
|
|
165
|
+
async reconcileRefund(input, options) {
|
|
166
|
+
const data = await transport.graphql({
|
|
167
|
+
api: 'admin',
|
|
168
|
+
query: RECONCILE_REFUND_OUTCOME_MUTATION,
|
|
169
|
+
// A variable, not a header: the Admin API takes the key as an argument.
|
|
170
|
+
variables: { input, idempotencyKey: options?.idempotencyKey },
|
|
171
|
+
}, options);
|
|
172
|
+
return data.reconcileRefundOutcome;
|
|
173
|
+
},
|
|
174
|
+
async reportAppPayment(paymentId, input, options) {
|
|
175
|
+
// Refused here rather than sent: the argument is non-null on the wire, and
|
|
176
|
+
// a report without a key could never be safely repeated.
|
|
177
|
+
if (typeof options?.idempotencyKey !== 'string' || options.idempotencyKey.trim() === '') {
|
|
178
|
+
throw new TypeError('reportAppPayment needs options.idempotencyKey: one key per provider event.');
|
|
179
|
+
}
|
|
180
|
+
const data = await transport.graphql({
|
|
181
|
+
api: 'admin',
|
|
182
|
+
query: REPORT_APP_PAYMENT_MUTATION,
|
|
183
|
+
// A variable, not a header: the Admin API takes the key as an argument.
|
|
184
|
+
variables: { paymentId, input, idempotencyKey: options.idempotencyKey },
|
|
185
|
+
}, options);
|
|
186
|
+
return data.reportAppPayment;
|
|
187
|
+
},
|
|
188
|
+
async appPayments(orderId, options) {
|
|
189
|
+
const data = await transport.graphql({ api: 'admin', query: APP_PAYMENTS_QUERY, variables: { orderId } }, options);
|
|
190
|
+
return data.appPayments;
|
|
191
|
+
},
|
|
54
192
|
};
|
|
55
193
|
}
|