@sixtyninecommerce/admin 0.7.0 → 0.8.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/dist/index.d.ts +1 -1
- package/dist/payments/index.d.ts +141 -0
- package/dist/payments/index.js +48 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -65,7 +65,7 @@ export type { Metafield, MetafieldAttachment, MetafieldDefinition, MetafieldDefi
|
|
|
65
65
|
export { METAFIELD_OWNER_TYPES, METAFIELD_SCALAR_TYPES } from './metafields/index.js';
|
|
66
66
|
export type { OrderSettlement, OrdersModule } from './orders/index.js';
|
|
67
67
|
export type { SurchargeCall, SurchargedOrder, SurchargeInput, SurchargesModule, } from './orders/surcharges.js';
|
|
68
|
-
export type { OrderPaymentPosition, PaidOrder, PaymentsModule, ProviderConnection, ProviderCredentialPath, ProviderOnboardingStart, ProviderReadiness, ProvidersModule, ProviderTerminal, ProviderTerminalsModule, ProvisionTerminalInput, ReadinessOptions, RecordPaymentInput, } from './payments/index.js';
|
|
68
|
+
export type { IssuedRefund, OrderPaymentPosition, OrderRefundPosition, PaidOrder, PaymentsModule, ProviderConnection, ProviderCredentialPath, ProviderOnboardingStart, ProviderReadiness, ProvidersModule, ProviderTerminal, ProviderTerminalsModule, ProvisionTerminalInput, ReadinessOptions, RecordPaymentInput, RefundablePayment, RefundPaymentInput, } from './payments/index.js';
|
|
69
69
|
export type { AppKey, PlatformAppsModule, RegisterAppResult, RegisteredApp, } from './platform/apps.js';
|
|
70
70
|
export { requireHumanSession } from './platform/guard.js';
|
|
71
71
|
export type { PlatformModule, ProvisionProfile, ProvisionRun, ProvisionRunStatus, ProvisionStep, ProvisionStepStatus, ProvisionStoreInput, ProvisionStoreResult, } from './platform/provision-store.js';
|
package/dist/payments/index.d.ts
CHANGED
|
@@ -51,6 +51,92 @@ export interface RecordPaymentInput {
|
|
|
51
51
|
*/
|
|
52
52
|
metadata?: Record<string, unknown>;
|
|
53
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
* One payment's contribution to an order's refund position.
|
|
56
|
+
*/
|
|
57
|
+
export interface RefundablePayment {
|
|
58
|
+
paymentId: string;
|
|
59
|
+
/** Vendure's payment state. */
|
|
60
|
+
state: string;
|
|
61
|
+
/** The payment method code, or null when the payment carries no label. */
|
|
62
|
+
method: string | null;
|
|
63
|
+
/** Gross amount taken, minor units. */
|
|
64
|
+
amount: number;
|
|
65
|
+
/** Non-failed refunds already recorded against it. A failed refund never left. */
|
|
66
|
+
refunded: number;
|
|
67
|
+
/** `amount - refunded` when this payment took money, floored at zero; else zero. */
|
|
68
|
+
refundable: number;
|
|
69
|
+
/**
|
|
70
|
+
* Whether this payment took money at all.
|
|
71
|
+
*
|
|
72
|
+
* True for a settled payment and for an authorized one on a real gateway — a
|
|
73
|
+
* card sale at a terminal rests authorized until the webhook settles it, and
|
|
74
|
+
* that hold is real money. False for an authorized payment on an offline or
|
|
75
|
+
* net-terms method, where authorized means the money has NOT arrived.
|
|
76
|
+
*/
|
|
77
|
+
tookMoney: boolean;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* What an order may still hand back, in minor units of its own currency.
|
|
81
|
+
*
|
|
82
|
+
* A different question from {@link OrderPaymentPosition}, and the two disagree
|
|
83
|
+
* on purpose: that one nets refunds against every authorization because it
|
|
84
|
+
* answers "what is this order covered for", while this one counts only money
|
|
85
|
+
* that was actually TAKEN, because that is all a refund can return.
|
|
86
|
+
*/
|
|
87
|
+
export interface OrderRefundPosition {
|
|
88
|
+
/** The order's currency. Every amount here is in its minor units. */
|
|
89
|
+
currencyCode: string;
|
|
90
|
+
/** Money already given back out of money that was taken. */
|
|
91
|
+
refunded: number;
|
|
92
|
+
/**
|
|
93
|
+
* What may still be handed back for this order: the sum of every payment's
|
|
94
|
+
* own remaining headroom, each floored at zero.
|
|
95
|
+
*
|
|
96
|
+
* There is deliberately no credit-note deduction. A credit note that moved
|
|
97
|
+
* money already has its refund on the payment; one that moved none has
|
|
98
|
+
* nothing to deduct.
|
|
99
|
+
*/
|
|
100
|
+
refundable: number;
|
|
101
|
+
/** Every payment on the order, NEWEST FIRST, with its own headroom. */
|
|
102
|
+
perPayment: RefundablePayment[];
|
|
103
|
+
}
|
|
104
|
+
/** Money handed back to a customer. */
|
|
105
|
+
export interface RefundPaymentInput {
|
|
106
|
+
orderId: string;
|
|
107
|
+
/** Minor units of the order's currency. Greater than zero. */
|
|
108
|
+
amount: number;
|
|
109
|
+
/**
|
|
110
|
+
* The payment to return the money to.
|
|
111
|
+
*
|
|
112
|
+
* Omit it and the platform allocates across the order's paying payments
|
|
113
|
+
* NEWEST FIRST: it picks the most recent one whose remaining headroom can
|
|
114
|
+
* carry the WHOLE amount. A part-paid order settles its remainder last, so
|
|
115
|
+
* that is the money a merchant means by "give some of it back".
|
|
116
|
+
*
|
|
117
|
+
* **One call refunds against ONE payment.** When the order can return the
|
|
118
|
+
* amount but no single payment can, the call is refused with
|
|
119
|
+
* `REFUND_EXCEEDS_PAYMENT` and `perPayment` shows exactly how to split it —
|
|
120
|
+
* rather than the platform spilling silently onto a payment you did not name,
|
|
121
|
+
* which is what the engine would do.
|
|
122
|
+
*/
|
|
123
|
+
paymentId?: string;
|
|
124
|
+
/** Free text stored on the refund. Shown to nobody automatically. */
|
|
125
|
+
reason?: string;
|
|
126
|
+
}
|
|
127
|
+
/** A refund, as this surface projects it. */
|
|
128
|
+
export interface IssuedRefund {
|
|
129
|
+
id: string;
|
|
130
|
+
/** Minor units. */
|
|
131
|
+
total: number;
|
|
132
|
+
/** `Pending`, `Settled` or `Failed`. */
|
|
133
|
+
state: string;
|
|
134
|
+
/** The payment method the refund was booked against. */
|
|
135
|
+
method: string | null;
|
|
136
|
+
/** The gateway's own receipt, when it gave one. */
|
|
137
|
+
transactionId: string | null;
|
|
138
|
+
reason: string | null;
|
|
139
|
+
}
|
|
54
140
|
/** The order, as much of it as this surface projects. */
|
|
55
141
|
export interface PaidOrder {
|
|
56
142
|
id: string;
|
|
@@ -96,8 +182,63 @@ export interface PaymentsModule {
|
|
|
96
182
|
record(orderId: string, input: RecordPaymentInput, options?: Call): Promise<PaidOrder>;
|
|
97
183
|
/** Read an order's payment position. */
|
|
98
184
|
position(orderId: string, options?: Call): Promise<OrderPaymentPosition>;
|
|
185
|
+
/**
|
|
186
|
+
* Hand money back to a customer, never more than the order took.
|
|
187
|
+
*
|
|
188
|
+
* The platform's own refund ceiling, and the one the four surfaces that issue
|
|
189
|
+
* refunds — returns settlement, credit notes, the till and the order importer
|
|
190
|
+
* — are measured against. Refuses `REFUND_EXCEEDS_SETTLED` when the amount is
|
|
191
|
+
* more than the whole ORDER can return, which is the check no per-payment
|
|
192
|
+
* arithmetic can make: another surface may have refunded the rest of it ten
|
|
193
|
+
* seconds ago.
|
|
194
|
+
*
|
|
195
|
+
* `options.idempotencyKey` is honoured — the Admin API takes it as a mutation
|
|
196
|
+
* argument — so a retry under the same key returns the FIRST call's refund
|
|
197
|
+
* instead of raising a second one. Use a fresh key per intended refund.
|
|
198
|
+
*
|
|
199
|
+
* **`IDEMPOTENCY_OUTCOME_UNKNOWN` is neither success nor refusal.** The engine
|
|
200
|
+
* calls the payment gateway from inside the transaction that writes the refund
|
|
201
|
+
* row, so a failure after that call leaves an outcome nobody can read off the
|
|
202
|
+
* database: the money may be on its way back with no row to show for it. You
|
|
203
|
+
* get this code on the FIRST call when that happens, and on every repeat under
|
|
204
|
+
* 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.
|
|
208
|
+
*
|
|
209
|
+
* (The server also attaches the position to that error, but `PlatformError`
|
|
210
|
+
* carries only `code`, `message`, `details` and `traceId`, so an SDK caller
|
|
211
|
+
* reads it with `refundPosition(orderId)` rather than off the error.)
|
|
212
|
+
*
|
|
213
|
+
* Only money that was TAKEN can come back: a settled payment, or an
|
|
214
|
+
* authorized one on a real gateway. An offline or net-terms authorization
|
|
215
|
+
* took nothing and is refused with `REFUND_PAYMENT_HOLDS_NO_MONEY`.
|
|
216
|
+
*
|
|
217
|
+
* **The refund you get back is one that moved money.** On an OFFLINE method —
|
|
218
|
+
* bank transfer, invoice, cash, an imported order's historical tender — it
|
|
219
|
+
* comes back `Settled`, because there the money moves by hand and recording
|
|
220
|
+
* it is the settlement. On a live gateway it comes back `Pending` and settles
|
|
221
|
+
* when the gateway calls back. A method whose handler cannot be resolved at
|
|
222
|
+
* all, because it is disabled or no longer on this store, is refused
|
|
223
|
+
* `REFUND_METHOD_UNAVAILABLE` before anything is created, with the payment and
|
|
224
|
+
* the method in `extensions.details`.
|
|
225
|
+
*
|
|
226
|
+
* Other refusals: `REFUND_EXCEEDS_PAYMENT` (the order can return this much,
|
|
227
|
+
* but no single payment can — split it, using `perPayment`),
|
|
228
|
+
* `REFUND_PAYMENT_NOT_FOUND`, `REFUND_AMOUNT_NOT_POSITIVE`,
|
|
229
|
+
* `REFUND_ORDER_NOT_FOUND`, and `REFUND_REFUSED` when the money was there and
|
|
230
|
+
* the engine or the gateway said no anyway. Every refusal raised once the
|
|
231
|
+
* order has been read carries that order's position in
|
|
232
|
+
* `extensions.refundPosition`, so a till can correct itself without a second
|
|
233
|
+
* round trip.
|
|
234
|
+
*/
|
|
235
|
+
refund(input: RefundPaymentInput, options?: Call): Promise<IssuedRefund>;
|
|
236
|
+
/** Read what an order may still hand back. */
|
|
237
|
+
refundPosition(orderId: string, options?: Call): Promise<OrderRefundPosition>;
|
|
99
238
|
}
|
|
100
239
|
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
240
|
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
|
+
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
|
+
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";
|
|
102
243
|
export declare function createPaymentsModule(transport: Transport): PaymentsModule;
|
|
103
244
|
export type { ProviderConnection, ProviderCredentialPath, ProviderOnboardingStart, ProviderReadiness, ProvidersModule, ProviderTerminal, ProviderTerminalsModule, ProvisionTerminalInput, ReadinessOptions, } from './providers.js';
|
package/dist/payments/index.js
CHANGED
|
@@ -31,6 +31,39 @@ export const ORDER_PAYMENT_POSITION_QUERY = /* GraphQL */ `
|
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
`;
|
|
34
|
+
const REFUND_POSITION_FIELDS = /* GraphQL */ `
|
|
35
|
+
currencyCode
|
|
36
|
+
refunded
|
|
37
|
+
refundable
|
|
38
|
+
perPayment {
|
|
39
|
+
paymentId
|
|
40
|
+
state
|
|
41
|
+
method
|
|
42
|
+
amount
|
|
43
|
+
refunded
|
|
44
|
+
refundable
|
|
45
|
+
tookMoney
|
|
46
|
+
}
|
|
47
|
+
`;
|
|
48
|
+
export const ORDER_REFUND_POSITION_QUERY = /* GraphQL */ `
|
|
49
|
+
query OrderRefundPosition($orderId: ID!) {
|
|
50
|
+
orderRefundPosition(orderId: $orderId) {
|
|
51
|
+
${REFUND_POSITION_FIELDS}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
`;
|
|
55
|
+
export const REFUND_ORDER_PAYMENT_MUTATION = /* GraphQL */ `
|
|
56
|
+
mutation RefundOrderPayment($input: RefundPaymentInput!, $idempotencyKey: String) {
|
|
57
|
+
refundOrderPayment(input: $input, idempotencyKey: $idempotencyKey) {
|
|
58
|
+
id
|
|
59
|
+
total
|
|
60
|
+
state
|
|
61
|
+
method
|
|
62
|
+
transactionId
|
|
63
|
+
reason
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
`;
|
|
34
67
|
export function createPaymentsModule(transport) {
|
|
35
68
|
return {
|
|
36
69
|
providers: createProvidersModule(transport),
|
|
@@ -51,5 +84,20 @@ export function createPaymentsModule(transport) {
|
|
|
51
84
|
const data = await transport.graphql({ api: 'admin', query: ORDER_PAYMENT_POSITION_QUERY, variables: { orderId } }, options);
|
|
52
85
|
return data.orderPaymentPosition;
|
|
53
86
|
},
|
|
87
|
+
async refund(input, options) {
|
|
88
|
+
const data = await transport.graphql({
|
|
89
|
+
api: 'admin',
|
|
90
|
+
query: REFUND_ORDER_PAYMENT_MUTATION,
|
|
91
|
+
// Forwarded as a VARIABLE, not a header: the Admin API has no header
|
|
92
|
+
// for it. `undefined`, never an explicit null — `JSON.stringify` drops
|
|
93
|
+
// it, so an omitted key stays off the wire entirely.
|
|
94
|
+
variables: { input, idempotencyKey: options?.idempotencyKey },
|
|
95
|
+
}, options);
|
|
96
|
+
return data.refundOrderPayment;
|
|
97
|
+
},
|
|
98
|
+
async refundPosition(orderId, options) {
|
|
99
|
+
const data = await transport.graphql({ api: 'admin', query: ORDER_REFUND_POSITION_QUERY, variables: { orderId } }, options);
|
|
100
|
+
return data.orderRefundPosition;
|
|
101
|
+
},
|
|
54
102
|
};
|
|
55
103
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sixtyninecommerce/admin",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.0",
|
|
4
4
|
"description": "Back-office SDK for sixtynine-commerce: every capability of the platform as a method",
|
|
5
5
|
"homepage": "https://github.com/SIXTYNINE-digital/sixtynine-commerce-engine/tree/main/packages/admin-client#readme",
|
|
6
6
|
"repository": {
|