@sixtyninecommerce/admin 0.9.0 → 0.11.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 +4598 -128
- package/dist/catalog/assets.d.ts +120 -8
- package/dist/catalog/assets.js +98 -12
- package/dist/catalog/collections.d.ts +279 -14
- package/dist/catalog/collections.js +246 -15
- package/dist/catalog/index.d.ts +9 -2
- package/dist/catalog/index.js +4 -0
- package/dist/catalog/products.d.ts +318 -17
- package/dist/catalog/products.js +182 -14
- package/dist/catalog/properties.d.ts +102 -14
- package/dist/catalog/properties.js +13 -0
- package/dist/catalog/recommendations.d.ts +261 -0
- package/dist/catalog/recommendations.js +145 -0
- package/dist/catalog/reviews.d.ts +368 -0
- package/dist/catalog/reviews.js +318 -0
- package/dist/catalog/types.d.ts +17 -1
- package/dist/catalog/types.js +10 -0
- package/dist/catalog/variant-find.d.ts +136 -0
- package/dist/catalog/variant-find.js +239 -0
- package/dist/catalog/variants.d.ts +282 -25
- package/dist/catalog/variants.js +173 -25
- package/dist/catalog/visibility.d.ts +20 -5
- package/dist/catalog/visibility.js +19 -1
- package/dist/client.d.ts +116 -9
- package/dist/client.js +41 -7
- package/dist/content/assets.d.ts +286 -0
- package/dist/content/assets.js +181 -0
- package/dist/content/items.d.ts +269 -0
- package/dist/content/items.js +170 -0
- package/dist/content/types.d.ts +282 -0
- package/dist/content/types.js +100 -0
- package/dist/customers/age-verification.d.ts +66 -0
- package/dist/customers/age-verification.js +79 -0
- package/dist/customers/credit.d.ts +263 -0
- package/dist/customers/credit.js +244 -0
- package/dist/customers/delivery-preferences.d.ts +120 -0
- package/dist/customers/delivery-preferences.js +97 -0
- package/dist/customers/groups.d.ts +207 -0
- package/dist/customers/groups.js +438 -0
- package/dist/customers/index.d.ts +447 -37
- package/dist/customers/index.js +313 -40
- package/dist/customers/invitation-status.d.ts +57 -0
- package/dist/customers/invitation-status.js +21 -0
- package/dist/customers/notes.d.ts +67 -0
- package/dist/customers/notes.js +51 -0
- package/dist/customers/notification-recipients.d.ts +97 -0
- package/dist/customers/notification-recipients.js +84 -0
- package/dist/customers/saved-lists.d.ts +42 -0
- package/dist/customers/saved-lists.js +61 -0
- package/dist/customers/vat.d.ts +83 -0
- package/dist/customers/vat.js +46 -0
- package/dist/customers/wire.d.ts +20 -0
- package/dist/customers/wire.js +35 -0
- package/dist/documents/ar.d.ts +307 -0
- package/dist/documents/ar.js +254 -0
- package/dist/documents/index.d.ts +731 -21
- package/dist/documents/index.js +436 -24
- package/dist/documents/pdf.d.ts +2 -0
- package/dist/documents/pdf.js +11 -0
- package/dist/fulfillments/create.d.ts +167 -0
- package/dist/fulfillments/create.js +216 -0
- package/dist/fulfillments/index.d.ts +121 -10
- package/dist/fulfillments/index.js +120 -2
- package/dist/fulfillments/payment-policy.d.ts +64 -0
- package/dist/fulfillments/payment-policy.js +140 -0
- package/dist/fulfillments/warehouse.d.ts +724 -0
- package/dist/fulfillments/warehouse.js +914 -0
- package/dist/geo/index.d.ts +119 -0
- package/dist/geo/index.js +107 -0
- package/dist/index.d.ts +129 -30
- package/dist/index.js +47 -9
- package/dist/integrations/afas-actions.d.ts +234 -0
- package/dist/integrations/afas-actions.js +310 -0
- package/dist/integrations/afas-types.d.ts +483 -0
- package/dist/integrations/afas-types.js +5 -0
- package/dist/integrations/afas.d.ts +234 -0
- package/dist/integrations/afas.js +290 -0
- package/dist/integrations/connections.d.ts +103 -0
- package/dist/integrations/connections.js +55 -0
- package/dist/integrations/esp.d.ts +313 -0
- package/dist/integrations/esp.js +169 -0
- package/dist/integrations/exact-online-types.d.ts +423 -0
- package/dist/integrations/exact-online-types.js +6 -0
- package/dist/integrations/exact-online.d.ts +248 -0
- package/dist/integrations/exact-online.js +376 -0
- package/dist/integrations/index.d.ts +40 -0
- package/dist/integrations/index.js +24 -0
- package/dist/integrations/pipeline-keys.d.ts +13 -0
- package/dist/integrations/pipeline-keys.js +22 -0
- package/dist/integrations/pipelines.d.ts +114 -0
- package/dist/integrations/pipelines.js +46 -0
- package/dist/integrations/types.d.ts +322 -0
- package/dist/integrations/types.js +8 -0
- package/dist/jobs/bulk-action-run.d.ts +11 -2
- package/dist/jobs/bulk-action-run.js +4 -5
- package/dist/locations/index.d.ts +66 -0
- package/dist/locations/index.js +31 -0
- package/dist/meta/index.d.ts +162 -0
- package/dist/orders/bulk.d.ts +75 -0
- package/dist/orders/bulk.js +150 -0
- package/dist/orders/cancel-with-money.d.ts +227 -0
- package/dist/orders/cancel-with-money.js +153 -0
- package/dist/orders/commit-edit.d.ts +7 -1
- package/dist/orders/commit-edit.js +5 -1
- package/dist/orders/deposit-policy.d.ts +103 -0
- package/dist/orders/deposit-policy.js +202 -0
- package/dist/orders/drafts.d.ts +800 -0
- package/dist/orders/drafts.js +771 -0
- package/dist/orders/fields.d.ts +245 -0
- package/dist/orders/fields.js +188 -0
- package/dist/orders/get.d.ts +29 -19
- package/dist/orders/get.js +17 -8
- package/dist/orders/index.d.ts +125 -5
- package/dist/orders/index.js +35 -2
- package/dist/orders/lifecycle.d.ts +128 -0
- package/dist/orders/lifecycle.js +158 -0
- package/dist/orders/line-price-preview.d.ts +7 -2
- package/dist/orders/list.d.ts +222 -0
- package/dist/orders/list.js +377 -0
- package/dist/orders/manual-discounts.d.ts +11 -2
- package/dist/orders/manual-discounts.js +2 -0
- package/dist/orders/manual-pricing.d.ts +5 -0
- package/dist/orders/order-entry.d.ts +20 -7
- package/dist/orders/plan-edit.d.ts +1 -1
- package/dist/orders/plan-edit.js +4 -1
- package/dist/orders/settings.d.ts +201 -0
- package/dist/orders/settings.js +325 -0
- package/dist/orders/status.d.ts +159 -13
- package/dist/orders/status.js +21 -0
- package/dist/orders/surcharges.d.ts +8 -1
- package/dist/orders/surcharges.js +3 -2
- package/dist/payments/account-credit.d.ts +30 -0
- package/dist/payments/account-credit.js +19 -0
- package/dist/payments/ar.d.ts +292 -0
- package/dist/payments/ar.js +223 -0
- package/dist/payments/connected-account.d.ts +47 -0
- package/dist/payments/connected-account.js +61 -0
- package/dist/payments/credit-noted-fields.d.ts +12 -0
- package/dist/payments/credit-noted-fields.js +37 -0
- package/dist/payments/index.d.ts +263 -10
- package/dist/payments/index.js +133 -1
- package/dist/payments/methods.d.ts +332 -0
- package/dist/payments/methods.js +363 -0
- package/dist/payments/mollie-methods.d.ts +159 -0
- package/dist/payments/mollie-methods.js +141 -0
- package/dist/payments/payment-links.d.ts +180 -0
- package/dist/payments/payment-links.js +97 -0
- package/dist/payments/provider-keys.d.ts +150 -0
- package/dist/payments/provider-keys.js +118 -0
- package/dist/payments/providers.d.ts +86 -11
- package/dist/payments/providers.js +29 -0
- package/dist/payments/requests.d.ts +144 -0
- package/dist/payments/requests.js +92 -0
- package/dist/payments/store-credit-fields.d.ts +15 -0
- package/dist/payments/store-credit-fields.js +51 -0
- package/dist/pickups/index.d.ts +104 -0
- package/dist/pickups/index.js +105 -0
- package/dist/platform/channels.d.ts +132 -0
- package/dist/platform/channels.js +128 -0
- package/dist/platform/geo.d.ts +123 -0
- package/dist/platform/geo.js +144 -0
- package/dist/platform/tax.d.ts +154 -0
- package/dist/platform/tax.js +139 -0
- package/dist/pos/anomalies.d.ts +158 -0
- package/dist/pos/anomalies.js +64 -0
- package/dist/pos/assisted-selling.d.ts +79 -0
- package/dist/pos/assisted-selling.js +38 -0
- package/dist/pos/exchanges.d.ts +103 -0
- package/dist/pos/exchanges.js +22 -0
- package/dist/pos/gift-cards.d.ts +135 -0
- package/dist/pos/gift-cards.js +47 -0
- package/dist/pos/index.d.ts +2125 -32
- package/dist/pos/index.js +742 -4
- package/dist/pos/no-receipt.d.ts +94 -0
- package/dist/pos/no-receipt.js +25 -0
- package/dist/pos/offline-sales.d.ts +187 -0
- package/dist/pos/offline-sales.js +116 -0
- package/dist/pos/pay-by-link.d.ts +143 -0
- package/dist/pos/pay-by-link.js +57 -0
- package/dist/pos/quick-keys.d.ts +103 -0
- package/dist/pos/quick-keys.js +45 -0
- package/dist/pos/reports.d.ts +360 -0
- package/dist/pos/reports.js +62 -0
- package/dist/pos/returns.d.ts +217 -0
- package/dist/pos/returns.js +53 -0
- package/dist/pricing/bulk-coupons.d.ts +139 -0
- package/dist/pricing/bulk-coupons.js +112 -0
- package/dist/pricing/index.d.ts +177 -4
- package/dist/pricing/index.js +176 -1
- package/dist/pricing/price-lists.d.ts +604 -0
- package/dist/pricing/price-lists.js +600 -0
- package/dist/pricing/vouchers.d.ts +103 -0
- package/dist/pricing/vouchers.js +69 -0
- package/dist/purchasing/alerts.d.ts +89 -0
- package/dist/purchasing/alerts.js +62 -0
- package/dist/purchasing/cost.d.ts +110 -0
- package/dist/purchasing/cost.js +86 -0
- package/dist/purchasing/index.d.ts +36 -0
- package/dist/purchasing/index.js +16 -0
- package/dist/purchasing/purchase-orders.d.ts +548 -0
- package/dist/purchasing/purchase-orders.js +491 -0
- package/dist/purchasing/replenishment.d.ts +281 -0
- package/dist/purchasing/replenishment.js +240 -0
- package/dist/purchasing/settings.d.ts +152 -0
- package/dist/purchasing/settings.js +181 -0
- package/dist/purchasing/suppliers.d.ts +476 -0
- package/dist/purchasing/suppliers.js +438 -0
- package/dist/quotes/index.d.ts +501 -0
- package/dist/quotes/index.js +439 -0
- package/dist/reports/index.d.ts +71 -8
- package/dist/reports/index.js +74 -11
- package/dist/returns/index.d.ts +818 -0
- package/dist/returns/index.js +844 -0
- package/dist/search/index.d.ts +174 -0
- package/dist/search/index.js +125 -0
- package/dist/shipping/definitions.d.ts +29 -0
- package/dist/shipping/definitions.js +47 -0
- package/dist/shipping/fulfillment-profiles.d.ts +174 -0
- package/dist/shipping/fulfillment-profiles.js +104 -0
- package/dist/shipping/hendriks.d.ts +97 -0
- package/dist/shipping/hendriks.js +50 -0
- package/dist/shipping/index.d.ts +48 -0
- package/dist/shipping/index.js +25 -0
- package/dist/shipping/methods.d.ts +198 -0
- package/dist/shipping/methods.js +240 -0
- package/dist/shipping/myparcel.d.ts +254 -0
- package/dist/shipping/myparcel.js +178 -0
- package/dist/shipping/parcel-count-suggestion.d.ts +2 -0
- package/dist/shipping/parcel-rule.d.ts +6 -5
- package/dist/shipping/parcel-rule.js +21 -23
- package/dist/shipping/rate-tables.d.ts +179 -0
- package/dist/shipping/rate-tables.js +184 -0
- package/dist/stock/index.d.ts +10 -3
- package/dist/stock/index.js +3 -0
- package/dist/stock/locations.d.ts +144 -0
- package/dist/stock/locations.js +168 -0
- package/dist/stock/transfers.d.ts +216 -43
- package/dist/stock/transfers.js +140 -13
- package/dist/stored-value/index.d.ts +214 -4
- package/dist/stored-value/index.js +152 -0
- package/dist/subscriptions/index.d.ts +682 -0
- package/dist/subscriptions/index.js +815 -0
- package/dist/tax/index.d.ts +76 -1
- package/dist/tax/index.js +50 -0
- package/dist/tenant/email-style.d.ts +102 -0
- package/dist/tenant/email-style.js +72 -0
- package/dist/tenant/email-templates.d.ts +66 -0
- package/dist/tenant/email-templates.js +54 -0
- package/dist/tenant/notifications.d.ts +23 -17
- package/dist/tenant/settings-sources.d.ts +1 -1
- package/dist/tenant/time-zone.d.ts +17 -0
- package/dist/tenant/time-zone.js +11 -0
- package/dist/types.d.ts +51 -4
- package/dist/users/index.d.ts +3 -0
- package/dist/users/index.js +2 -0
- package/dist/users/warehouses.d.ts +50 -0
- package/dist/users/warehouses.js +51 -0
- package/package.json +2 -2
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import { type Page, type Transport } from '@sixtyninecommerce/core';
|
|
2
|
+
import type { Call, ListOptions } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* Money on the store's accounts-receivable ledger (`admin.payments.ar`, headless W10-30): the
|
|
5
|
+
* payments customers make against their AR invoices, the ledger itself, prepaid drawdowns, and
|
|
6
|
+
* collecting an invoice by SEPA direct debit. Unapplied cash (an order's overpayment kept on the
|
|
7
|
+
* account) is `payments.accountCredit`.
|
|
8
|
+
*
|
|
9
|
+
* Every write needs `UpdateOrder` and a store that keeps its AR ledger (else
|
|
10
|
+
* `AR_LEDGER_NOT_ENABLED`, → `BusinessRuleError`, 422); every read `ReadOrder`. A customer the
|
|
11
|
+
* store does not hold is `CUSTOMER_NOT_FOUND` (→ `NotFoundError`). Money is in integer minor units
|
|
12
|
+
* of the currency named beside it.
|
|
13
|
+
*
|
|
14
|
+
* **Keys.** `recordPayment`, `recordPrepaidDrawdown` and `directDebit.collectNow` take
|
|
15
|
+
* `options.idempotencyKey`: a repeat under the same key answers the first call's outcome instead
|
|
16
|
+
* of moving the money again; another request under the key is `IDEMPOTENCY_CONFLICT`
|
|
17
|
+
* (→ `ConflictError`, 409), one that arrives while the first still runs
|
|
18
|
+
* `IDEMPOTENCY_IN_PROGRESS`. **Without a key `recordPayment` is NOT de-duplicated**: a double
|
|
19
|
+
* submit records two payments. Use a fresh key per intended payment and reuse it only to retry
|
|
20
|
+
* that payment.
|
|
21
|
+
*/
|
|
22
|
+
/** A customer payment received on the AR ledger, with what it settled. */
|
|
23
|
+
export interface ArPayment {
|
|
24
|
+
id: string;
|
|
25
|
+
customerId: string;
|
|
26
|
+
amount: number;
|
|
27
|
+
currencyCode: string;
|
|
28
|
+
/** `bank_transfer`, `cash`, `card`, `direct_debit` or `other`. */
|
|
29
|
+
method: string;
|
|
30
|
+
receivedOn: string;
|
|
31
|
+
reference: string | null;
|
|
32
|
+
notes: string | null;
|
|
33
|
+
allocations: Array<{
|
|
34
|
+
id: string;
|
|
35
|
+
invoiceId: string;
|
|
36
|
+
amount: number;
|
|
37
|
+
}>;
|
|
38
|
+
createdAt: string;
|
|
39
|
+
}
|
|
40
|
+
export type ArPaymentMethod = 'bank_transfer' | 'cash' | 'card' | 'direct_debit' | 'other';
|
|
41
|
+
export interface RecordArPaymentInput {
|
|
42
|
+
customerId: string;
|
|
43
|
+
/** Minor units of `currencyCode`, above zero. */
|
|
44
|
+
amount: number;
|
|
45
|
+
method: ArPaymentMethod;
|
|
46
|
+
/** `YYYY-MM-DD`; defaults to today in the store's zone. */
|
|
47
|
+
receivedOn?: string;
|
|
48
|
+
reference?: string;
|
|
49
|
+
notes?: string;
|
|
50
|
+
/** One the store sells in; defaults to the account's currency. It settles only invoices in it. */
|
|
51
|
+
currencyCode?: string;
|
|
52
|
+
/**
|
|
53
|
+
* Where the money goes, each at most what the invoice still owes. Omitted, it is allocated
|
|
54
|
+
* oldest invoice first and the rest stays on the account.
|
|
55
|
+
*/
|
|
56
|
+
allocations?: Array<{
|
|
57
|
+
invoiceId: string;
|
|
58
|
+
amount: number;
|
|
59
|
+
}>;
|
|
60
|
+
}
|
|
61
|
+
/** One ledger posting. */
|
|
62
|
+
export interface ArLedgerEntry {
|
|
63
|
+
id: string;
|
|
64
|
+
/** `invoice_debit`, `payment_credit`, `credit_note_credit`, `prepaid_drawdown`, … */
|
|
65
|
+
entryType: string;
|
|
66
|
+
/** Signed minor units of `currencyCode`. */
|
|
67
|
+
amount: number;
|
|
68
|
+
currencyCode: string;
|
|
69
|
+
sourceType: string;
|
|
70
|
+
sourceId: string | null;
|
|
71
|
+
occurredOn: string;
|
|
72
|
+
metadata: Record<string, unknown> | null;
|
|
73
|
+
createdAt: string;
|
|
74
|
+
}
|
|
75
|
+
/** The drawdown already posted for an order. */
|
|
76
|
+
export interface ArOrderPrepaidDrawdown {
|
|
77
|
+
entryId: string;
|
|
78
|
+
orderId: string;
|
|
79
|
+
amount: number;
|
|
80
|
+
currencyCode: string;
|
|
81
|
+
occurredOn: string;
|
|
82
|
+
}
|
|
83
|
+
export interface ArPrepaidDrawdownResult {
|
|
84
|
+
entryId: string;
|
|
85
|
+
customerId: string;
|
|
86
|
+
amount: number;
|
|
87
|
+
currencyCode: string;
|
|
88
|
+
occurredOn: string;
|
|
89
|
+
/** The customer's signed balance after it, in `currencyCode` only. */
|
|
90
|
+
balanceAfter: number;
|
|
91
|
+
/** True when the order had been drawn down already: nothing new was posted. */
|
|
92
|
+
alreadyRecorded: boolean;
|
|
93
|
+
}
|
|
94
|
+
export interface RecordArPrepaidDrawdownInput {
|
|
95
|
+
orderId: string;
|
|
96
|
+
/** `YYYY-MM-DD`; defaults to today in the store's zone. */
|
|
97
|
+
occurredOn?: string;
|
|
98
|
+
}
|
|
99
|
+
/** A customer's SEPA direct debit set-up. */
|
|
100
|
+
export interface ArDirectDebitSettings {
|
|
101
|
+
customerId: string;
|
|
102
|
+
enabled: boolean;
|
|
103
|
+
/** Set: every collection is blocked until a person clears it. */
|
|
104
|
+
suspendedReason: string | null;
|
|
105
|
+
hasValidMandate: boolean;
|
|
106
|
+
mandateId: string | null;
|
|
107
|
+
providerMandateId: string | null;
|
|
108
|
+
/** False when the platform has no mandate provider at all. */
|
|
109
|
+
available: boolean;
|
|
110
|
+
}
|
|
111
|
+
export interface UpdateArDirectDebitSettingsInput {
|
|
112
|
+
enabled?: boolean;
|
|
113
|
+
/** Null lifts a suspension. */
|
|
114
|
+
suspendedReason?: string | null;
|
|
115
|
+
}
|
|
116
|
+
/** One attempt to collect an invoice by direct debit. */
|
|
117
|
+
export interface ArCollectionAttempt {
|
|
118
|
+
id: string;
|
|
119
|
+
invoiceId: string;
|
|
120
|
+
customerId: string;
|
|
121
|
+
attemptNumber: number;
|
|
122
|
+
amount: number;
|
|
123
|
+
currencyCode: string;
|
|
124
|
+
/** `pending`, `paid`, `failed`, `reversed` or `cancelled`. */
|
|
125
|
+
status: string;
|
|
126
|
+
provider: string;
|
|
127
|
+
providerPaymentId: string | null;
|
|
128
|
+
/** The SEPA R-code when the provider gave one (`AM04`, `MD06`, …). */
|
|
129
|
+
failureCode: string | null;
|
|
130
|
+
failureReason: string | null;
|
|
131
|
+
settledAt: string | null;
|
|
132
|
+
reversedAt: string | null;
|
|
133
|
+
orderSettlementState: string;
|
|
134
|
+
lastCheckedAt: string | null;
|
|
135
|
+
createdAt: string;
|
|
136
|
+
}
|
|
137
|
+
/** The recorded pre-notification and the wording the merchant must send the debtor. */
|
|
138
|
+
export interface ArPreNotification {
|
|
139
|
+
invoiceId: string;
|
|
140
|
+
/** The first day the collection may be taken. */
|
|
141
|
+
collectOn: string;
|
|
142
|
+
amount: number;
|
|
143
|
+
noticeTitle: string;
|
|
144
|
+
noticeBody: string;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* What asking to collect an invoice now answered. A refusal is an ANSWER, not an error:
|
|
148
|
+
* `{ result: 'refused', refusal, message }` says why the invoice cannot be collected now (not
|
|
149
|
+
* pre-notified, no mandate, suspended, nothing outstanding, …), and nothing was asked of the
|
|
150
|
+
* bank. `declined`: the provider refused the charge at once. `already-in-flight`: a collection
|
|
151
|
+
* of the invoice is running; `attempt` is it.
|
|
152
|
+
*/
|
|
153
|
+
export type ArCollectResult = {
|
|
154
|
+
result: 'charged' | 'declined' | 'already-in-flight';
|
|
155
|
+
refusal: null;
|
|
156
|
+
message: null;
|
|
157
|
+
attempt: ArCollectionAttempt;
|
|
158
|
+
} | {
|
|
159
|
+
result: 'refused';
|
|
160
|
+
refusal: string;
|
|
161
|
+
message: string;
|
|
162
|
+
attempt: null;
|
|
163
|
+
};
|
|
164
|
+
export interface ArDirectDebitModule {
|
|
165
|
+
/**
|
|
166
|
+
* A customer's direct debit settings and mandate state.
|
|
167
|
+
*
|
|
168
|
+
* @effect read
|
|
169
|
+
* @permission ReadOrder
|
|
170
|
+
*/
|
|
171
|
+
settings(customerId: string, options?: Call): Promise<ArDirectDebitSettings>;
|
|
172
|
+
/**
|
|
173
|
+
* Turn direct debit on or off for a customer, or lift a suspension. Turning it on needs a valid
|
|
174
|
+
* SEPA mandate (`AR_DIRECT_DEBIT_MANDATE_REQUIRED`; an older engine answered
|
|
175
|
+
* `USER_INPUT_ERROR`). Moves no money.
|
|
176
|
+
*
|
|
177
|
+
* @effect write
|
|
178
|
+
* @permission UpdateOrder
|
|
179
|
+
*/
|
|
180
|
+
update(customerId: string, input: UpdateArDirectDebitSettingsInput, options?: Call): Promise<ArDirectDebitSettings>;
|
|
181
|
+
/**
|
|
182
|
+
* Every collection attempt of one invoice, newest first (the last 50).
|
|
183
|
+
*
|
|
184
|
+
* @effect read
|
|
185
|
+
* @permission ReadOrder
|
|
186
|
+
*/
|
|
187
|
+
attempts(invoiceId: string, options?: Call): Promise<ArCollectionAttempt[]>;
|
|
188
|
+
/**
|
|
189
|
+
* The newest attempt of each invoice named, in one call.
|
|
190
|
+
*
|
|
191
|
+
* @effect read
|
|
192
|
+
* @permission ReadOrder
|
|
193
|
+
*/
|
|
194
|
+
latestAttempts(invoiceIds: string[], options?: Call): Promise<ArCollectionAttempt[]>;
|
|
195
|
+
/**
|
|
196
|
+
* Record that the debtor has been told the invoice will be collected, and get the exact
|
|
197
|
+
* wording to send them. It sends nothing itself: sending the notice is the merchant's legal
|
|
198
|
+
* duty, and recording it is what allows the collection. Run it again when the outstanding
|
|
199
|
+
* amount changes.
|
|
200
|
+
*
|
|
201
|
+
* Refused, coded (an older engine answered each `USER_INPUT_ERROR` with the same sentence):
|
|
202
|
+
* `AR_INVOICE_NOT_FOUND`, `AR_INVOICE_NOT_OPEN` (voided, or nothing outstanding),
|
|
203
|
+
* `AR_DIRECT_DEBIT_NOT_ENABLED`, `AR_DIRECT_DEBIT_SUSPENDED`, `AR_ACCOUNT_IN_ERP`,
|
|
204
|
+
* `AR_INVOICE_DIRECT_DEBIT_IN_FLIGHT`.
|
|
205
|
+
*
|
|
206
|
+
* @effect money
|
|
207
|
+
* @permission UpdateOrder
|
|
208
|
+
*/
|
|
209
|
+
sendPreNotification(invoiceId: string, options?: Call): Promise<ArPreNotification>;
|
|
210
|
+
/**
|
|
211
|
+
* Collect a pre-notified invoice now, from the customer's SEPA mandate. A refusal is answered
|
|
212
|
+
* as `{ result: 'refused', refusal }`, NOT thrown (see {@link ArCollectResult}). Thrown:
|
|
213
|
+
* `AR_INVOICE_NOT_FOUND`, and `AR_DIRECT_DEBIT_UNAVAILABLE` (a platform fault, 500: the
|
|
214
|
+
* platform has no webhook address or charge provider for the collection; nothing is reserved).
|
|
215
|
+
*
|
|
216
|
+
* Pass `options.idempotencyKey`: a repeat under it answers the first outcome (the attempt as it
|
|
217
|
+
* is now). Once the provider was asked, a failure spends the key: a repeat answers
|
|
218
|
+
* `IDEMPOTENCY_OUTCOME_UNKNOWN` (`error.outcomeUnknown`) and asks the bank nothing; read
|
|
219
|
+
* {@link attempts} for what happened. The engine also keeps one live attempt per invoice
|
|
220
|
+
* whatever the key does.
|
|
221
|
+
*
|
|
222
|
+
* @effect money
|
|
223
|
+
* @permission UpdateOrder
|
|
224
|
+
*/
|
|
225
|
+
collectNow(invoiceId: string, options?: Call): Promise<ArCollectResult>;
|
|
226
|
+
}
|
|
227
|
+
export interface ArPaymentsModule {
|
|
228
|
+
/**
|
|
229
|
+
* AR payments, newest first, one customer's or the store's, paged (`limit` up to 100).
|
|
230
|
+
*
|
|
231
|
+
* @effect read
|
|
232
|
+
* @permission ReadOrder
|
|
233
|
+
*/
|
|
234
|
+
payments(options?: ListOptions & {
|
|
235
|
+
customerId?: string;
|
|
236
|
+
}): Promise<Page<ArPayment>>;
|
|
237
|
+
/**
|
|
238
|
+
* A customer's ledger postings, newest first, paged (`limit` up to 100).
|
|
239
|
+
*
|
|
240
|
+
* @effect read
|
|
241
|
+
* @permission ReadOrder
|
|
242
|
+
*/
|
|
243
|
+
ledger(customerId: string, options?: ListOptions): Promise<Page<ArLedgerEntry>>;
|
|
244
|
+
/**
|
|
245
|
+
* Record a payment a customer made against their AR invoices: the receipt, its allocations and
|
|
246
|
+
* the ledger credit, in one transaction. **Pass `options.idempotencyKey`**: without one a
|
|
247
|
+
* repeat (a double click, a retry after a timeout) records a second payment. With one, the
|
|
248
|
+
* repeat answers the first payment as it is now.
|
|
249
|
+
*
|
|
250
|
+
* Refusals: `AR_LEDGER_NOT_ENABLED`, `CUSTOMER_NOT_FOUND`, `CURRENCY_NOT_AVAILABLE` (a currency
|
|
251
|
+
* the store does not sell in), `AR_CURRENCY_MISMATCH` (an allocation to an invoice in another
|
|
252
|
+
* currency), `AR_INVOICE_NOT_FOUND` (an allocation to an invoice not this customer's),
|
|
253
|
+
* `AR_INVOICE_NOT_OPEN` (to a voided one), `AR_ALLOCATION_EXCEEDS_OUTSTANDING` (more than the
|
|
254
|
+
* invoice still owes) and `AR_ALLOCATION_EXCEEDS_PAYMENT` (more than the payment), each a
|
|
255
|
+
* `USER_INPUT_ERROR` on an older engine; and a field refusal (`USER_INPUT_ERROR`) for an amount,
|
|
256
|
+
* a method or an allocation that is not one (a duplicate).
|
|
257
|
+
*
|
|
258
|
+
* @effect money
|
|
259
|
+
* @permission UpdateOrder
|
|
260
|
+
*/
|
|
261
|
+
recordPayment(input: RecordArPaymentInput, options?: Call): Promise<ArPayment>;
|
|
262
|
+
/**
|
|
263
|
+
* The prepaid drawdown already posted for an order, or null.
|
|
264
|
+
*
|
|
265
|
+
* @effect read
|
|
266
|
+
* @permission ReadOrder
|
|
267
|
+
*/
|
|
268
|
+
prepaidDrawdown(orderId: string, options?: Call): Promise<ArOrderPrepaidDrawdown | null>;
|
|
269
|
+
/**
|
|
270
|
+
* Draw a delivered order's gross total off the customer's prepaid credit. Once per order
|
|
271
|
+
* whatever happens (`alreadyRecorded` on a repeat without a key); with a key, a repeat answers
|
|
272
|
+
* the first result. Refused `ORDER_NOT_FOUND`, `AR_ORDER_HAS_NO_CUSTOMER` and
|
|
273
|
+
* `AR_ORDER_STATE_BLOCKS_DRAWDOWN` (each `USER_INPUT_ERROR` on an older engine).
|
|
274
|
+
*
|
|
275
|
+
* @effect money
|
|
276
|
+
* @permission UpdateOrder
|
|
277
|
+
*/
|
|
278
|
+
recordPrepaidDrawdown(input: RecordArPrepaidDrawdownInput, options?: Call): Promise<ArPrepaidDrawdownResult>;
|
|
279
|
+
directDebit: ArDirectDebitModule;
|
|
280
|
+
}
|
|
281
|
+
export declare const AR_PAYMENTS_QUERY = "\n query ArPayments($options: ArListOptions) {\n arPayments(options: $options) {\n items { \n id\n customerId\n amount\n currencyCode\n method\n receivedOn\n reference\n notes\n allocations {\n id\n invoiceId\n amount\n }\n createdAt\n }\n totalItems\n }\n }\n";
|
|
282
|
+
export declare const AR_LEDGER_QUERY = "\n query ArLedgerEntries($customerId: ID!, $options: ArListOptions) {\n arLedgerEntries(customerId: $customerId, options: $options) {\n items {\n id\n entryType\n amount\n currencyCode\n sourceType\n sourceId\n occurredOn\n metadata\n createdAt\n }\n totalItems\n }\n }\n";
|
|
283
|
+
export declare const RECORD_AR_PAYMENT_MUTATION = "\n mutation RecordArPayment($input: RecordArPaymentInput!, $idempotencyKey: String) {\n recordArPayment(input: $input, idempotencyKey: $idempotencyKey) { \n id\n customerId\n amount\n currencyCode\n method\n receivedOn\n reference\n notes\n allocations {\n id\n invoiceId\n amount\n }\n createdAt\n }\n }\n";
|
|
284
|
+
export declare const AR_ORDER_PREPAID_DRAWDOWN_QUERY = "\n query ArOrderPrepaidDrawdown($orderId: ID!) {\n arOrderPrepaidDrawdown(orderId: $orderId) {\n entryId\n orderId\n amount\n currencyCode\n occurredOn\n }\n }\n";
|
|
285
|
+
export declare const RECORD_AR_PREPAID_DRAWDOWN_MUTATION = "\n mutation RecordArPrepaidDrawdown($input: RecordArPrepaidDrawdownInput!, $idempotencyKey: String) {\n recordArPrepaidDrawdown(input: $input, idempotencyKey: $idempotencyKey) {\n entryId\n customerId\n amount\n currencyCode\n occurredOn\n balanceAfter\n alreadyRecorded\n }\n }\n";
|
|
286
|
+
export declare const AR_DIRECT_DEBIT_SETTINGS_QUERY = "\n query ArDirectDebitSettings($customerId: ID!) {\n arDirectDebitSettings(customerId: $customerId) { \n customerId\n enabled\n suspendedReason\n hasValidMandate\n mandateId\n providerMandateId\n available\n }\n }\n";
|
|
287
|
+
export declare const UPDATE_AR_DIRECT_DEBIT_SETTINGS_MUTATION = "\n mutation UpdateArDirectDebitSettings($customerId: ID!, $input: UpdateArDirectDebitSettingsInput!) {\n updateArDirectDebitSettings(customerId: $customerId, input: $input) {\n \n customerId\n enabled\n suspendedReason\n hasValidMandate\n mandateId\n providerMandateId\n available\n\n }\n }\n";
|
|
288
|
+
export declare const AR_COLLECTION_ATTEMPTS_QUERY = "\n query ArCollectionAttempts($invoiceId: ID!) {\n arCollectionAttempts(invoiceId: $invoiceId) { \n id\n invoiceId\n customerId\n attemptNumber\n amount\n currencyCode\n status\n provider\n providerPaymentId\n failureCode\n failureReason\n settledAt\n reversedAt\n orderSettlementState\n lastCheckedAt\n createdAt\n }\n }\n";
|
|
289
|
+
export declare const AR_LATEST_COLLECTION_ATTEMPTS_QUERY = "\n query ArLatestCollectionAttempts($invoiceIds: [ID!]!) {\n arLatestCollectionAttempts(invoiceIds: $invoiceIds) { \n id\n invoiceId\n customerId\n attemptNumber\n amount\n currencyCode\n status\n provider\n providerPaymentId\n failureCode\n failureReason\n settledAt\n reversedAt\n orderSettlementState\n lastCheckedAt\n createdAt\n }\n }\n";
|
|
290
|
+
export declare const SEND_AR_PRE_NOTIFICATION_MUTATION = "\n mutation SendArDirectDebitPreNotification($invoiceId: ID!) {\n sendArDirectDebitPreNotification(invoiceId: $invoiceId) {\n invoiceId\n collectOn\n amount\n noticeTitle\n noticeBody\n }\n }\n";
|
|
291
|
+
export declare const COLLECT_AR_INVOICE_NOW_MUTATION = "\n mutation CollectArInvoiceNow($invoiceId: ID!, $idempotencyKey: String) {\n collectArInvoiceNow(invoiceId: $invoiceId, idempotencyKey: $idempotencyKey) {\n result\n refusal\n message\n attempt { \n id\n invoiceId\n customerId\n attemptNumber\n amount\n currencyCode\n status\n provider\n providerPaymentId\n failureCode\n failureReason\n settledAt\n reversedAt\n orderSettlementState\n lastCheckedAt\n createdAt\n }\n }\n }\n";
|
|
292
|
+
export declare function createArPaymentsModule(transport: Transport): ArPaymentsModule;
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
import { pageFromVendureList, readOffsetCursor, } from '@sixtyninecommerce/core';
|
|
2
|
+
import { arPageWindow } from '../documents/ar.js';
|
|
3
|
+
const PAYMENT_FIELDS = /* GraphQL */ `
|
|
4
|
+
id
|
|
5
|
+
customerId
|
|
6
|
+
amount
|
|
7
|
+
currencyCode
|
|
8
|
+
method
|
|
9
|
+
receivedOn
|
|
10
|
+
reference
|
|
11
|
+
notes
|
|
12
|
+
allocations {
|
|
13
|
+
id
|
|
14
|
+
invoiceId
|
|
15
|
+
amount
|
|
16
|
+
}
|
|
17
|
+
createdAt
|
|
18
|
+
`;
|
|
19
|
+
const ATTEMPT_FIELDS = /* GraphQL */ `
|
|
20
|
+
id
|
|
21
|
+
invoiceId
|
|
22
|
+
customerId
|
|
23
|
+
attemptNumber
|
|
24
|
+
amount
|
|
25
|
+
currencyCode
|
|
26
|
+
status
|
|
27
|
+
provider
|
|
28
|
+
providerPaymentId
|
|
29
|
+
failureCode
|
|
30
|
+
failureReason
|
|
31
|
+
settledAt
|
|
32
|
+
reversedAt
|
|
33
|
+
orderSettlementState
|
|
34
|
+
lastCheckedAt
|
|
35
|
+
createdAt
|
|
36
|
+
`;
|
|
37
|
+
const DIRECT_DEBIT_SETTINGS_FIELDS = /* GraphQL */ `
|
|
38
|
+
customerId
|
|
39
|
+
enabled
|
|
40
|
+
suspendedReason
|
|
41
|
+
hasValidMandate
|
|
42
|
+
mandateId
|
|
43
|
+
providerMandateId
|
|
44
|
+
available
|
|
45
|
+
`;
|
|
46
|
+
export const AR_PAYMENTS_QUERY = /* GraphQL */ `
|
|
47
|
+
query ArPayments($options: ArListOptions) {
|
|
48
|
+
arPayments(options: $options) {
|
|
49
|
+
items { ${PAYMENT_FIELDS} }
|
|
50
|
+
totalItems
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
`;
|
|
54
|
+
export const AR_LEDGER_QUERY = /* GraphQL */ `
|
|
55
|
+
query ArLedgerEntries($customerId: ID!, $options: ArListOptions) {
|
|
56
|
+
arLedgerEntries(customerId: $customerId, options: $options) {
|
|
57
|
+
items {
|
|
58
|
+
id
|
|
59
|
+
entryType
|
|
60
|
+
amount
|
|
61
|
+
currencyCode
|
|
62
|
+
sourceType
|
|
63
|
+
sourceId
|
|
64
|
+
occurredOn
|
|
65
|
+
metadata
|
|
66
|
+
createdAt
|
|
67
|
+
}
|
|
68
|
+
totalItems
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
`;
|
|
72
|
+
export const RECORD_AR_PAYMENT_MUTATION = /* GraphQL */ `
|
|
73
|
+
mutation RecordArPayment($input: RecordArPaymentInput!, $idempotencyKey: String) {
|
|
74
|
+
recordArPayment(input: $input, idempotencyKey: $idempotencyKey) { ${PAYMENT_FIELDS} }
|
|
75
|
+
}
|
|
76
|
+
`;
|
|
77
|
+
export const AR_ORDER_PREPAID_DRAWDOWN_QUERY = /* GraphQL */ `
|
|
78
|
+
query ArOrderPrepaidDrawdown($orderId: ID!) {
|
|
79
|
+
arOrderPrepaidDrawdown(orderId: $orderId) {
|
|
80
|
+
entryId
|
|
81
|
+
orderId
|
|
82
|
+
amount
|
|
83
|
+
currencyCode
|
|
84
|
+
occurredOn
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
`;
|
|
88
|
+
export const RECORD_AR_PREPAID_DRAWDOWN_MUTATION = /* GraphQL */ `
|
|
89
|
+
mutation RecordArPrepaidDrawdown($input: RecordArPrepaidDrawdownInput!, $idempotencyKey: String) {
|
|
90
|
+
recordArPrepaidDrawdown(input: $input, idempotencyKey: $idempotencyKey) {
|
|
91
|
+
entryId
|
|
92
|
+
customerId
|
|
93
|
+
amount
|
|
94
|
+
currencyCode
|
|
95
|
+
occurredOn
|
|
96
|
+
balanceAfter
|
|
97
|
+
alreadyRecorded
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
`;
|
|
101
|
+
export const AR_DIRECT_DEBIT_SETTINGS_QUERY = /* GraphQL */ `
|
|
102
|
+
query ArDirectDebitSettings($customerId: ID!) {
|
|
103
|
+
arDirectDebitSettings(customerId: $customerId) { ${DIRECT_DEBIT_SETTINGS_FIELDS} }
|
|
104
|
+
}
|
|
105
|
+
`;
|
|
106
|
+
export const UPDATE_AR_DIRECT_DEBIT_SETTINGS_MUTATION = /* GraphQL */ `
|
|
107
|
+
mutation UpdateArDirectDebitSettings($customerId: ID!, $input: UpdateArDirectDebitSettingsInput!) {
|
|
108
|
+
updateArDirectDebitSettings(customerId: $customerId, input: $input) {
|
|
109
|
+
${DIRECT_DEBIT_SETTINGS_FIELDS}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
`;
|
|
113
|
+
export const AR_COLLECTION_ATTEMPTS_QUERY = /* GraphQL */ `
|
|
114
|
+
query ArCollectionAttempts($invoiceId: ID!) {
|
|
115
|
+
arCollectionAttempts(invoiceId: $invoiceId) { ${ATTEMPT_FIELDS} }
|
|
116
|
+
}
|
|
117
|
+
`;
|
|
118
|
+
export const AR_LATEST_COLLECTION_ATTEMPTS_QUERY = /* GraphQL */ `
|
|
119
|
+
query ArLatestCollectionAttempts($invoiceIds: [ID!]!) {
|
|
120
|
+
arLatestCollectionAttempts(invoiceIds: $invoiceIds) { ${ATTEMPT_FIELDS} }
|
|
121
|
+
}
|
|
122
|
+
`;
|
|
123
|
+
export const SEND_AR_PRE_NOTIFICATION_MUTATION = /* GraphQL */ `
|
|
124
|
+
mutation SendArDirectDebitPreNotification($invoiceId: ID!) {
|
|
125
|
+
sendArDirectDebitPreNotification(invoiceId: $invoiceId) {
|
|
126
|
+
invoiceId
|
|
127
|
+
collectOn
|
|
128
|
+
amount
|
|
129
|
+
noticeTitle
|
|
130
|
+
noticeBody
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
`;
|
|
134
|
+
export const COLLECT_AR_INVOICE_NOW_MUTATION = /* GraphQL */ `
|
|
135
|
+
mutation CollectArInvoiceNow($invoiceId: ID!, $idempotencyKey: String) {
|
|
136
|
+
collectArInvoiceNow(invoiceId: $invoiceId, idempotencyKey: $idempotencyKey) {
|
|
137
|
+
result
|
|
138
|
+
refusal
|
|
139
|
+
message
|
|
140
|
+
attempt { ${ATTEMPT_FIELDS} }
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
`;
|
|
144
|
+
/** `undefined`, never null: `JSON.stringify` drops it, so an omitted key stays off the wire. */
|
|
145
|
+
const keyOf = (options) => options?.idempotencyKey;
|
|
146
|
+
export function createArPaymentsModule(transport) {
|
|
147
|
+
const paymentsPage = async (customerId, skip, take, options) => {
|
|
148
|
+
const data = await transport.graphql({
|
|
149
|
+
api: 'admin',
|
|
150
|
+
query: AR_PAYMENTS_QUERY,
|
|
151
|
+
variables: { options: { customerId, skip, take } },
|
|
152
|
+
}, options);
|
|
153
|
+
return pageFromVendureList(data.arPayments, skip, take, (cursor) => paymentsPage(customerId, readOffsetCursor(cursor), take, options));
|
|
154
|
+
};
|
|
155
|
+
const ledgerPage = async (customerId, skip, take, options) => {
|
|
156
|
+
const data = await transport.graphql({ api: 'admin', query: AR_LEDGER_QUERY, variables: { customerId, options: { skip, take } } }, options);
|
|
157
|
+
return pageFromVendureList(data.arLedgerEntries, skip, take, (cursor) => ledgerPage(customerId, readOffsetCursor(cursor), take, options));
|
|
158
|
+
};
|
|
159
|
+
return {
|
|
160
|
+
payments(options) {
|
|
161
|
+
const { skip, take } = arPageWindow(options);
|
|
162
|
+
return paymentsPage(options?.customerId, skip, take, options);
|
|
163
|
+
},
|
|
164
|
+
ledger(customerId, options) {
|
|
165
|
+
const { skip, take } = arPageWindow(options);
|
|
166
|
+
return ledgerPage(customerId, skip, take, options);
|
|
167
|
+
},
|
|
168
|
+
async recordPayment(input, options) {
|
|
169
|
+
const data = await transport.graphql({
|
|
170
|
+
api: 'admin',
|
|
171
|
+
query: RECORD_AR_PAYMENT_MUTATION,
|
|
172
|
+
variables: { input, idempotencyKey: keyOf(options) },
|
|
173
|
+
}, options);
|
|
174
|
+
return data.recordArPayment;
|
|
175
|
+
},
|
|
176
|
+
async prepaidDrawdown(orderId, options) {
|
|
177
|
+
const data = await transport.graphql({ api: 'admin', query: AR_ORDER_PREPAID_DRAWDOWN_QUERY, variables: { orderId } }, options);
|
|
178
|
+
return data.arOrderPrepaidDrawdown;
|
|
179
|
+
},
|
|
180
|
+
async recordPrepaidDrawdown(input, options) {
|
|
181
|
+
const data = await transport.graphql({
|
|
182
|
+
api: 'admin',
|
|
183
|
+
query: RECORD_AR_PREPAID_DRAWDOWN_MUTATION,
|
|
184
|
+
variables: { input, idempotencyKey: keyOf(options) },
|
|
185
|
+
}, options);
|
|
186
|
+
return data.recordArPrepaidDrawdown;
|
|
187
|
+
},
|
|
188
|
+
directDebit: {
|
|
189
|
+
async settings(customerId, options) {
|
|
190
|
+
const data = await transport.graphql({ api: 'admin', query: AR_DIRECT_DEBIT_SETTINGS_QUERY, variables: { customerId } }, options);
|
|
191
|
+
return data.arDirectDebitSettings;
|
|
192
|
+
},
|
|
193
|
+
async update(customerId, input, options) {
|
|
194
|
+
const data = await transport.graphql({
|
|
195
|
+
api: 'admin',
|
|
196
|
+
query: UPDATE_AR_DIRECT_DEBIT_SETTINGS_MUTATION,
|
|
197
|
+
variables: { customerId, input },
|
|
198
|
+
}, options);
|
|
199
|
+
return data.updateArDirectDebitSettings;
|
|
200
|
+
},
|
|
201
|
+
async attempts(invoiceId, options) {
|
|
202
|
+
const data = await transport.graphql({ api: 'admin', query: AR_COLLECTION_ATTEMPTS_QUERY, variables: { invoiceId } }, options);
|
|
203
|
+
return data.arCollectionAttempts;
|
|
204
|
+
},
|
|
205
|
+
async latestAttempts(invoiceIds, options) {
|
|
206
|
+
const data = await transport.graphql({ api: 'admin', query: AR_LATEST_COLLECTION_ATTEMPTS_QUERY, variables: { invoiceIds } }, options);
|
|
207
|
+
return data.arLatestCollectionAttempts;
|
|
208
|
+
},
|
|
209
|
+
async sendPreNotification(invoiceId, options) {
|
|
210
|
+
const data = await transport.graphql({ api: 'admin', query: SEND_AR_PRE_NOTIFICATION_MUTATION, variables: { invoiceId } }, options);
|
|
211
|
+
return data.sendArDirectDebitPreNotification;
|
|
212
|
+
},
|
|
213
|
+
async collectNow(invoiceId, options) {
|
|
214
|
+
const data = await transport.graphql({
|
|
215
|
+
api: 'admin',
|
|
216
|
+
query: COLLECT_AR_INVOICE_NOW_MUTATION,
|
|
217
|
+
variables: { invoiceId, idempotencyKey: keyOf(options) },
|
|
218
|
+
}, options);
|
|
219
|
+
return data.collectArInvoiceNow;
|
|
220
|
+
},
|
|
221
|
+
},
|
|
222
|
+
};
|
|
223
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { type Transport } from '@sixtyninecommerce/core';
|
|
2
|
+
import type { Call } from '../types.js';
|
|
3
|
+
/**
|
|
4
|
+
* The Stripe Connect account saved for the legal entity (the seller) of the store the client is
|
|
5
|
+
* on. Every store of that legal entity shares it.
|
|
6
|
+
*/
|
|
7
|
+
export interface StripeConnectedAccount {
|
|
8
|
+
/** The engine's id of the store's seller (its legal entity). */
|
|
9
|
+
sellerId: string;
|
|
10
|
+
/** The saved Stripe account id (`acct_…`), or null when none is saved. */
|
|
11
|
+
accountId: string | null;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* The store's Stripe Connect account id, saved on its legal entity (the seller).
|
|
15
|
+
*
|
|
16
|
+
* **Saved, not yet used.** The engine keeps the id, but charges route to it only once Stripe
|
|
17
|
+
* Connect routing is switched on (decision B0c); until then a Stripe payment runs on the
|
|
18
|
+
* account of the method's own API key (`payments.methods.providerKeys`).
|
|
19
|
+
*
|
|
20
|
+
* The engine does not check the value's format: what is sent is stored. A head that wants the
|
|
21
|
+
* `acct_…` shape checks it itself until the engine does.
|
|
22
|
+
*/
|
|
23
|
+
export interface ConnectedAccountModule {
|
|
24
|
+
/**
|
|
25
|
+
* The account saved for the store's legal entity. Any signed-in caller of the store may read
|
|
26
|
+
* it (the id is not a secret).
|
|
27
|
+
*
|
|
28
|
+
* @effect read
|
|
29
|
+
*/
|
|
30
|
+
get(options?: Call): Promise<StripeConnectedAccount>;
|
|
31
|
+
/**
|
|
32
|
+
* Save the account id (`null` removes it) on the store's legal entity, and answer what it then
|
|
33
|
+
* holds. Every store of that legal entity is changed with it, so the caller needs
|
|
34
|
+
* `UpdateSeller` on each of them: one they may not change refuses the whole call
|
|
35
|
+
* `SHARED_SELLER_NOT_ALLOWED` (`PermissionDeniedError`, 403), and without `UpdateSeller`
|
|
36
|
+
* here it is `FORBIDDEN` (403). `SELLER_REQUIRED` (`BusinessRuleError`, 422): the store has no
|
|
37
|
+
* seller to save it on. An empty string is refused before sending
|
|
38
|
+
* (`INVALID_CONNECTED_ACCOUNT_INPUT`, 400): `null` removes the account.
|
|
39
|
+
*
|
|
40
|
+
* @effect write
|
|
41
|
+
* @permission UpdateSeller
|
|
42
|
+
*/
|
|
43
|
+
set(accountId: string | null, options?: Call): Promise<StripeConnectedAccount>;
|
|
44
|
+
}
|
|
45
|
+
export declare const STRIPE_CONNECTED_ACCOUNT_QUERY = "\n query StripeConnectedAccount {\n activeChannel {\n id\n seller {\n id\n customFields {\n stripeConnectedAccountId\n }\n }\n }\n }\n";
|
|
46
|
+
export declare const SET_STRIPE_CONNECTED_ACCOUNT_MUTATION = "\n mutation SetStripeConnectedAccount($input: UpdateSellerInput!) {\n updateSeller(input: $input) {\n id\n customFields {\n stripeConnectedAccountId\n }\n }\n }\n";
|
|
47
|
+
export declare function createConnectedAccountModule(transport: Transport): ConnectedAccountModule;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { BusinessRuleError, ValidationError } from '@sixtyninecommerce/core';
|
|
2
|
+
import { fieldOf } from '../catalog/types.js';
|
|
3
|
+
export const STRIPE_CONNECTED_ACCOUNT_QUERY = /* GraphQL */ `
|
|
4
|
+
query StripeConnectedAccount {
|
|
5
|
+
activeChannel {
|
|
6
|
+
id
|
|
7
|
+
seller {
|
|
8
|
+
id
|
|
9
|
+
customFields {
|
|
10
|
+
stripeConnectedAccountId
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
`;
|
|
16
|
+
export const SET_STRIPE_CONNECTED_ACCOUNT_MUTATION = /* GraphQL */ `
|
|
17
|
+
mutation SetStripeConnectedAccount($input: UpdateSellerInput!) {
|
|
18
|
+
updateSeller(input: $input) {
|
|
19
|
+
id
|
|
20
|
+
customFields {
|
|
21
|
+
stripeConnectedAccountId
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
`;
|
|
26
|
+
const toAccount = (seller) => ({
|
|
27
|
+
sellerId: seller.id,
|
|
28
|
+
accountId: seller.customFields?.stripeConnectedAccountId ?? null,
|
|
29
|
+
});
|
|
30
|
+
export function createConnectedAccountModule(transport) {
|
|
31
|
+
// Hoisted, as `createProvidersModule`'s functions are: a destructured method keeps working.
|
|
32
|
+
const read = async (options) => {
|
|
33
|
+
const channel = await fieldOf(transport, STRIPE_CONNECTED_ACCOUNT_QUERY, 'activeChannel', {}, options);
|
|
34
|
+
if (!channel.seller) {
|
|
35
|
+
throw new BusinessRuleError({
|
|
36
|
+
code: 'SELLER_REQUIRED',
|
|
37
|
+
message: 'This store has no seller (legal entity) to hold a Stripe account.',
|
|
38
|
+
status: 422,
|
|
39
|
+
service: 'vendure',
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
return toAccount(channel.seller);
|
|
43
|
+
};
|
|
44
|
+
return {
|
|
45
|
+
get: read,
|
|
46
|
+
async set(accountId, options) {
|
|
47
|
+
if (accountId !== null && (typeof accountId !== 'string' || accountId === '')) {
|
|
48
|
+
throw new ValidationError({
|
|
49
|
+
code: 'INVALID_CONNECTED_ACCOUNT_INPUT',
|
|
50
|
+
message: 'accountId must be a Stripe account id, or null to remove it.',
|
|
51
|
+
status: 400,
|
|
52
|
+
service: 'vendure',
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
// The seller is the store's own, read in the same tenant as the write: the id is never
|
|
56
|
+
// the caller's to name, so a head cannot save onto another legal entity by mistake.
|
|
57
|
+
const { sellerId } = await read(options);
|
|
58
|
+
return toAccount(await fieldOf(transport, SET_STRIPE_CONNECTED_ACCOUNT_MUTATION, 'updateSeller', { input: { id: sellerId, customFields: { stripeConnectedAccountId: accountId } } }, options));
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Transport } from '@sixtyninecommerce/core';
|
|
2
|
+
/** `document` without the fields above: what an engine before them accepts. */
|
|
3
|
+
export declare function withoutCreditNotedFields(document: string): string;
|
|
4
|
+
/**
|
|
5
|
+
* The transport, sending a document that names the credit fields once more without them when the
|
|
6
|
+
* engine refused it as unknown. Safe for a mutation too: a refused document never ran. A refusal
|
|
7
|
+
* at HTTP 400 does not name the field, so a document that also carries the older store-credit
|
|
8
|
+
* fields goes through `storeCreditAware(creditNotedAware(transport))`: the newest fields fall away
|
|
9
|
+
* first (one resend on an engine that has store credit and not these), and both on an engine
|
|
10
|
+
* that knows neither (four sends at most).
|
|
11
|
+
*/
|
|
12
|
+
export declare function creditNotedAware(transport: Pick<Transport, 'graphql'>): Pick<Transport, 'graphql'>;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { isUnknownFieldRejection } from './store-credit-fields.js';
|
|
2
|
+
/**
|
|
3
|
+
* The payment position's credit fields (branch `murat/order-outstanding-ignores-credit-refunds`):
|
|
4
|
+
* `creditNoted`, what an invoiced order's credit notes took off its bill, and `owed`, what the
|
|
5
|
+
* customer still owes after them. An engine before them refuses a document naming either as a
|
|
6
|
+
* whole, before it runs; the same document without them reads as it did then (both absent: nothing
|
|
7
|
+
* credited, the customer owes `outstanding`). So the position reads keep working on an older
|
|
8
|
+
* engine, as `storeCreditAware` keeps the "credit the customer" answers working.
|
|
9
|
+
*/
|
|
10
|
+
const CREDIT_NOTED_FIELDS = [/\bcreditNoted\b/g, /\bowed\b/g];
|
|
11
|
+
/** `document` without the fields above: what an engine before them accepts. */
|
|
12
|
+
export function withoutCreditNotedFields(document) {
|
|
13
|
+
return CREDIT_NOTED_FIELDS.reduce((text, field) => text.replace(field, ''), document);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* The transport, sending a document that names the credit fields once more without them when the
|
|
17
|
+
* engine refused it as unknown. Safe for a mutation too: a refused document never ran. A refusal
|
|
18
|
+
* at HTTP 400 does not name the field, so a document that also carries the older store-credit
|
|
19
|
+
* fields goes through `storeCreditAware(creditNotedAware(transport))`: the newest fields fall away
|
|
20
|
+
* first (one resend on an engine that has store credit and not these), and both on an engine
|
|
21
|
+
* that knows neither (four sends at most).
|
|
22
|
+
*/
|
|
23
|
+
export function creditNotedAware(transport) {
|
|
24
|
+
return {
|
|
25
|
+
async graphql(call, options) {
|
|
26
|
+
try {
|
|
27
|
+
return await transport.graphql(call, options);
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
const legacy = withoutCreditNotedFields(call.query);
|
|
31
|
+
if (legacy === call.query || !isUnknownFieldRejection(error))
|
|
32
|
+
throw error;
|
|
33
|
+
return transport.graphql({ ...call, query: legacy }, options);
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
}
|