@sixtyninecommerce/admin 0.10.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 +4347 -171
- 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 +159 -19
- package/dist/catalog/products.js +88 -13
- 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 +233 -26
- package/dist/catalog/variants.js +125 -7
- package/dist/catalog/visibility.d.ts +20 -5
- package/dist/catalog/visibility.js +19 -1
- package/dist/client.d.ts +95 -9
- package/dist/client.js +35 -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 +44 -10
- package/dist/fulfillments/index.js +11 -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 +123 -35
- package/dist/index.js +45 -12
- 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 +29 -3
- package/dist/integrations/index.js +18 -3
- package/dist/integrations/pipeline-keys.d.ts +13 -0
- package/dist/integrations/pipeline-keys.js +22 -0
- package/dist/integrations/pipelines.d.ts +15 -14
- package/dist/integrations/pipelines.js +6 -22
- package/dist/integrations/types.d.ts +146 -0
- 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/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/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 +49 -9
- package/dist/orders/index.js +22 -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-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 +257 -11
- package/dist/payments/index.js +131 -1
- package/dist/payments/methods.d.ts +303 -8
- package/dist/payments/methods.js +337 -7
- 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 +174 -4
- package/dist/pricing/index.js +174 -1
- package/dist/pricing/price-lists.d.ts +604 -0
- package/dist/pricing/price-lists.js +600 -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 +614 -21
- package/dist/returns/index.js +695 -11
- package/dist/search/index.d.ts +76 -1
- package/dist/search/index.js +63 -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 +50 -3
- 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,815 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `admin.subscriptions`: subscription plans and the subscriptions sold on them (headless spec
|
|
3
|
+
* §9.2 `subscriptions`; plans W10-36, lifecycle W10-114). It reads subscriptions, manages plans,
|
|
4
|
+
* and runs the lifecycle and billing commands (purchase, pause/resume/cancel, payment recovery
|
|
5
|
+
* and reconciliation, renewal and settlement retries, price changes), each command that can
|
|
6
|
+
* charge, refund or change what a customer pays under one idempotency key per attempt (see
|
|
7
|
+
* `SubscriptionLifecycleCommands`).
|
|
8
|
+
*
|
|
9
|
+
* A plan is a store's template: a price per billing interval, the products each cycle ships, and
|
|
10
|
+
* the commitment rules. Changing or deleting a plan never changes a subscription already sold on
|
|
11
|
+
* it: each subscription keeps its own `recurringPrice` and products.
|
|
12
|
+
*
|
|
13
|
+
* **Money** is an integer in minor units of `currencyCode`. A plan's `price` and a subscription's
|
|
14
|
+
* `recurringPrice` are on the store's price basis (`readiness().pricesIncludeTax`: gross with VAT
|
|
15
|
+
* and shipping on a tax-inclusive store, net with net shipping otherwise). What a cycle actually
|
|
16
|
+
* charged (`billingCycles[].amount`, `upcomingPayment.amount`) is always gross.
|
|
17
|
+
*
|
|
18
|
+
* **Status words** are the meta catalog's `labels.subscription_status` keys (`active`,
|
|
19
|
+
* `past_due`, …): the SDK lower-cases the engine's enum, as it does a mandate's status. Every
|
|
20
|
+
* value set grows over time: treat a word this version does not name as one with no action.
|
|
21
|
+
*
|
|
22
|
+
* **Refusals** (`PlatformError`, by `code`) pass through as the engine sent them:
|
|
23
|
+
* `SUBSCRIPTION_PLAN_NOT_FOUND` (404), `SUBSCRIPTION_INPUT_INVALID` (400, the sentence names the
|
|
24
|
+
* value), `SUBSCRIPTION_PLAN_IN_USE` (422), `SUBSCRIPTION_PRODUCT_UNAVAILABLE` (422),
|
|
25
|
+
* `PLUGIN_ACCESS_DENIED` (403, the store has no subscriptions entitlement), and
|
|
26
|
+
* `HUB_HAS_NO_ORDERS` / `ORGANIZATION_WORKSPACE_NOT_A_STORE`. Another store's plan, subscription
|
|
27
|
+
* or customer is not found (a read answers null or an empty list), never served.
|
|
28
|
+
*/
|
|
29
|
+
import { idempotencyKey as mintIdempotencyKey, UpstreamError, ValidationError, } from '@sixtyninecommerce/core';
|
|
30
|
+
import { assertDeleted, assertInstant, fieldOf } from '../catalog/types.js';
|
|
31
|
+
import { redactionWatcher } from '../customer-data-redaction.js';
|
|
32
|
+
/** The meta catalog's `labels.subscription_status` keys. */
|
|
33
|
+
export const SUBSCRIPTION_STATUSES = [
|
|
34
|
+
'incomplete',
|
|
35
|
+
'trial',
|
|
36
|
+
'active',
|
|
37
|
+
'paused',
|
|
38
|
+
'past_due',
|
|
39
|
+
'cancelled',
|
|
40
|
+
'expired',
|
|
41
|
+
'completed',
|
|
42
|
+
];
|
|
43
|
+
const PLAN_FIELDS = /* GraphQL */ `
|
|
44
|
+
id
|
|
45
|
+
channelId
|
|
46
|
+
name
|
|
47
|
+
description
|
|
48
|
+
billingInterval
|
|
49
|
+
billingIntervalCount
|
|
50
|
+
currencyCode
|
|
51
|
+
price
|
|
52
|
+
trialDays
|
|
53
|
+
firstChargeTiming
|
|
54
|
+
customerChangeCutoffHours
|
|
55
|
+
minCycles
|
|
56
|
+
maxCycles
|
|
57
|
+
enabled
|
|
58
|
+
fulfillmentMode
|
|
59
|
+
shippingMethodId
|
|
60
|
+
activeSubscriptionCount
|
|
61
|
+
createdAt
|
|
62
|
+
updatedAt
|
|
63
|
+
variants {
|
|
64
|
+
id
|
|
65
|
+
variantId
|
|
66
|
+
quantity
|
|
67
|
+
position
|
|
68
|
+
}
|
|
69
|
+
`;
|
|
70
|
+
const LIST_FIELDS = /* GraphQL */ `
|
|
71
|
+
id
|
|
72
|
+
channelId
|
|
73
|
+
customerId
|
|
74
|
+
customerName
|
|
75
|
+
paidCycleCount
|
|
76
|
+
currencyCode
|
|
77
|
+
recurringPrice
|
|
78
|
+
billingInterval
|
|
79
|
+
billingIntervalCount
|
|
80
|
+
currentStatus
|
|
81
|
+
currentCycle
|
|
82
|
+
currentPeriodStart
|
|
83
|
+
currentPeriodEnd
|
|
84
|
+
nextRenewalAt
|
|
85
|
+
lastRenewedAt
|
|
86
|
+
cancelAtPeriodEnd
|
|
87
|
+
createdAt
|
|
88
|
+
attentionSummary
|
|
89
|
+
plan {
|
|
90
|
+
id
|
|
91
|
+
name
|
|
92
|
+
price
|
|
93
|
+
maxCycles
|
|
94
|
+
}
|
|
95
|
+
mandate {
|
|
96
|
+
id
|
|
97
|
+
provider
|
|
98
|
+
mandateMethod
|
|
99
|
+
mandateStatus
|
|
100
|
+
}
|
|
101
|
+
`;
|
|
102
|
+
const MANDATE_FIELDS = /* GraphQL */ `
|
|
103
|
+
id
|
|
104
|
+
channelId
|
|
105
|
+
customerId
|
|
106
|
+
provider
|
|
107
|
+
mandateMethod
|
|
108
|
+
mandateStatus
|
|
109
|
+
isDefault
|
|
110
|
+
createdAt
|
|
111
|
+
updatedAt
|
|
112
|
+
`;
|
|
113
|
+
export const SUBSCRIPTION_PLANS_QUERY = /* GraphQL */ `
|
|
114
|
+
query SubscriptionsPlansList($options: SubscriptionPlanListOptions) {
|
|
115
|
+
subscriptionPlans(options: $options) {
|
|
116
|
+
items {
|
|
117
|
+
${PLAN_FIELDS}
|
|
118
|
+
}
|
|
119
|
+
totalItems
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
`;
|
|
123
|
+
export const SUBSCRIPTION_PLAN_QUERY = /* GraphQL */ `
|
|
124
|
+
query SubscriptionsPlansGet($id: ID!) {
|
|
125
|
+
subscriptionPlan(id: $id) {
|
|
126
|
+
${PLAN_FIELDS}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
`;
|
|
130
|
+
export const CREATE_SUBSCRIPTION_PLAN_MUTATION = /* GraphQL */ `
|
|
131
|
+
mutation SubscriptionsPlansCreate($input: CreateSubscriptionPlanInput!) {
|
|
132
|
+
createSubscriptionPlan(input: $input) {
|
|
133
|
+
${PLAN_FIELDS}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
`;
|
|
137
|
+
export const UPDATE_SUBSCRIPTION_PLAN_MUTATION = /* GraphQL */ `
|
|
138
|
+
mutation SubscriptionsPlansUpdate($id: ID!, $input: UpdateSubscriptionPlanInput!) {
|
|
139
|
+
updateSubscriptionPlan(id: $id, input: $input) {
|
|
140
|
+
${PLAN_FIELDS}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
`;
|
|
144
|
+
export const SET_SUBSCRIPTION_PLAN_VARIANTS_MUTATION = /* GraphQL */ `
|
|
145
|
+
mutation SubscriptionsPlansSetVariants(
|
|
146
|
+
$planId: ID!
|
|
147
|
+
$variants: [SubscriptionPlanVariantInput!]!
|
|
148
|
+
) {
|
|
149
|
+
setSubscriptionPlanVariants(planId: $planId, variants: $variants) {
|
|
150
|
+
${PLAN_FIELDS}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
`;
|
|
154
|
+
export const DELETE_SUBSCRIPTION_PLAN_MUTATION = /* GraphQL */ `
|
|
155
|
+
mutation SubscriptionsPlansDelete($id: ID!) {
|
|
156
|
+
deleteSubscriptionPlan(id: $id) {
|
|
157
|
+
result
|
|
158
|
+
message
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
`;
|
|
162
|
+
export const SUBSCRIPTION_PLAN_PRICE_BREAKDOWN_QUERY = /* GraphQL */ `
|
|
163
|
+
query SubscriptionsPlansPriceBreakdown($input: SubscriptionPlanPriceBreakdownInput!) {
|
|
164
|
+
subscriptionPlanPriceBreakdown(input: $input) {
|
|
165
|
+
pricesIncludeTax
|
|
166
|
+
netAmount
|
|
167
|
+
taxAmount
|
|
168
|
+
grossAmount
|
|
169
|
+
currencyCode
|
|
170
|
+
zoneName
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
`;
|
|
174
|
+
export const SUBSCRIPTIONS_QUERY = /* GraphQL */ `
|
|
175
|
+
query SubscriptionsList($options: SubscriptionListOptions) {
|
|
176
|
+
subscriptions(options: $options) {
|
|
177
|
+
items {
|
|
178
|
+
${LIST_FIELDS}
|
|
179
|
+
}
|
|
180
|
+
totalItems
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
`;
|
|
184
|
+
/** A billing cycle with its attempts, as `get` and the cycle commands answer it. */
|
|
185
|
+
const CYCLE_FIELDS = /* GraphQL */ `
|
|
186
|
+
id cycleNumber dueAt periodStart periodEnd amount currencyCode paymentState settlementState
|
|
187
|
+
attentionReason orderId orderCode paidAt settledAt nextRetryAt
|
|
188
|
+
attempts {
|
|
189
|
+
id attemptNumber paymentState paymentProvider providerPaymentId providerSessionId
|
|
190
|
+
failureReason checkoutUrl nextRetryAt createdAt
|
|
191
|
+
}
|
|
192
|
+
`;
|
|
193
|
+
/** One subscription, as `get` and every lifecycle command that answers the subscription do. */
|
|
194
|
+
const SUBSCRIPTION_FIELDS = /* GraphQL */ `
|
|
195
|
+
id
|
|
196
|
+
channelId
|
|
197
|
+
customerId
|
|
198
|
+
customerName
|
|
199
|
+
paidCycleCount
|
|
200
|
+
currencyCode
|
|
201
|
+
recurringPrice
|
|
202
|
+
billingInterval
|
|
203
|
+
billingIntervalCount
|
|
204
|
+
currentStatus
|
|
205
|
+
trialEndsAt
|
|
206
|
+
customerChangeCutoffHours
|
|
207
|
+
cutoffAt
|
|
208
|
+
cancellationRequested
|
|
209
|
+
cancellationEffectiveAt
|
|
210
|
+
earliestCancellationAt
|
|
211
|
+
remainingPaidCycles
|
|
212
|
+
committedPayment
|
|
213
|
+
resumeAt
|
|
214
|
+
retainedResumeAt
|
|
215
|
+
earliestResumeAt
|
|
216
|
+
paymentActionRequired
|
|
217
|
+
allowedActions { action allowed reason }
|
|
218
|
+
products { variantId quantity name sku }
|
|
219
|
+
upcomingPayment { purchaseId dueAt amount currencyCode state nextRetryAt checkoutUrl }
|
|
220
|
+
activity { id action actor reason createdAt }
|
|
221
|
+
billingCycles {
|
|
222
|
+
${CYCLE_FIELDS}
|
|
223
|
+
}
|
|
224
|
+
notifications {
|
|
225
|
+
id event dueAt dispatchedAt failureCount lastError nextAttemptAt parkedAt parkedReason
|
|
226
|
+
}
|
|
227
|
+
currentCycle
|
|
228
|
+
minCycles
|
|
229
|
+
maxCycles
|
|
230
|
+
currentPeriodStart
|
|
231
|
+
currentPeriodEnd
|
|
232
|
+
nextRenewalAt
|
|
233
|
+
lastRenewedAt
|
|
234
|
+
cancelAtPeriodEnd
|
|
235
|
+
cancelAt
|
|
236
|
+
externalId
|
|
237
|
+
externalPlatform
|
|
238
|
+
createdAt
|
|
239
|
+
updatedAt
|
|
240
|
+
plan {
|
|
241
|
+
id
|
|
242
|
+
name
|
|
243
|
+
description
|
|
244
|
+
billingInterval
|
|
245
|
+
billingIntervalCount
|
|
246
|
+
currencyCode
|
|
247
|
+
price
|
|
248
|
+
trialDays
|
|
249
|
+
firstChargeTiming
|
|
250
|
+
customerChangeCutoffHours
|
|
251
|
+
enabled
|
|
252
|
+
}
|
|
253
|
+
mandate {
|
|
254
|
+
id
|
|
255
|
+
provider
|
|
256
|
+
mandateMethod
|
|
257
|
+
mandateStatus
|
|
258
|
+
isDefault
|
|
259
|
+
}
|
|
260
|
+
renewalHistory {
|
|
261
|
+
id
|
|
262
|
+
cycleNumber
|
|
263
|
+
cycleId
|
|
264
|
+
attemptNumber
|
|
265
|
+
paymentState
|
|
266
|
+
orderId
|
|
267
|
+
paymentProvider
|
|
268
|
+
providerPaymentId
|
|
269
|
+
amount
|
|
270
|
+
currencyCode
|
|
271
|
+
result
|
|
272
|
+
failureReason
|
|
273
|
+
retryCount
|
|
274
|
+
createdAt
|
|
275
|
+
}
|
|
276
|
+
`;
|
|
277
|
+
export const SUBSCRIPTION_QUERY = /* GraphQL */ `
|
|
278
|
+
query SubscriptionsGet($id: ID!) {
|
|
279
|
+
subscription(id: $id) {
|
|
280
|
+
${SUBSCRIPTION_FIELDS}
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
`;
|
|
284
|
+
export const CUSTOMER_SUBSCRIPTIONS_QUERY = /* GraphQL */ `
|
|
285
|
+
query SubscriptionsForCustomer($customerId: ID!) {
|
|
286
|
+
customerSubscriptions(customerId: $customerId) {
|
|
287
|
+
${LIST_FIELDS}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
`;
|
|
291
|
+
export const CUSTOMER_MANDATES_QUERY = /* GraphQL */ `
|
|
292
|
+
query SubscriptionsMandates($customerId: ID!) {
|
|
293
|
+
customerMandates(customerId: $customerId) {
|
|
294
|
+
${MANDATE_FIELDS}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
`;
|
|
298
|
+
export const SUBSCRIPTION_CHANNEL_READINESS_QUERY = /* GraphQL */ `
|
|
299
|
+
query SubscriptionsReadiness {
|
|
300
|
+
subscriptionChannelReadiness {
|
|
301
|
+
pricesIncludeTax
|
|
302
|
+
storefrontUrlConfigured
|
|
303
|
+
managementUrlConfigured
|
|
304
|
+
providers {
|
|
305
|
+
code
|
|
306
|
+
configured
|
|
307
|
+
enabled
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
`;
|
|
312
|
+
const PURCHASE_FIELDS = /* GraphQL */ `
|
|
313
|
+
id
|
|
314
|
+
subscriptionId
|
|
315
|
+
state
|
|
316
|
+
checkoutUrl
|
|
317
|
+
expiresAt
|
|
318
|
+
currentStatus
|
|
319
|
+
paymentActionRequired
|
|
320
|
+
nextRenewalAt
|
|
321
|
+
`;
|
|
322
|
+
const RENEWAL_FIELDS = /* GraphQL */ `
|
|
323
|
+
id
|
|
324
|
+
cycleNumber
|
|
325
|
+
cycleId
|
|
326
|
+
attemptNumber
|
|
327
|
+
paymentState
|
|
328
|
+
orderId
|
|
329
|
+
paymentProvider
|
|
330
|
+
providerPaymentId
|
|
331
|
+
amount
|
|
332
|
+
currencyCode
|
|
333
|
+
result
|
|
334
|
+
failureReason
|
|
335
|
+
retryCount
|
|
336
|
+
createdAt
|
|
337
|
+
`;
|
|
338
|
+
export const SUBSCRIPTION_PURCHASE_PREVIEW_QUERY = /* GraphQL */ `
|
|
339
|
+
query SubscriptionsPurchasePreview(
|
|
340
|
+
$planId: ID!
|
|
341
|
+
$customerId: ID
|
|
342
|
+
$provider: String
|
|
343
|
+
$mandateId: ID
|
|
344
|
+
) {
|
|
345
|
+
subscriptionPurchasePreview(
|
|
346
|
+
planId: $planId
|
|
347
|
+
customerId: $customerId
|
|
348
|
+
provider: $provider
|
|
349
|
+
mandateId: $mandateId
|
|
350
|
+
) {
|
|
351
|
+
planId
|
|
352
|
+
planName
|
|
353
|
+
amount
|
|
354
|
+
pricesIncludeTax
|
|
355
|
+
netAmount
|
|
356
|
+
taxAmount
|
|
357
|
+
currencyCode
|
|
358
|
+
firstPaymentAt
|
|
359
|
+
firstChargeTiming
|
|
360
|
+
billingInterval
|
|
361
|
+
billingIntervalCount
|
|
362
|
+
trialDays
|
|
363
|
+
trialEndsAt
|
|
364
|
+
minCycles
|
|
365
|
+
maxCycles
|
|
366
|
+
customerChangeCutoffHours
|
|
367
|
+
cutoffAt
|
|
368
|
+
mandateVerificationAmount
|
|
369
|
+
products {
|
|
370
|
+
variantId
|
|
371
|
+
name
|
|
372
|
+
quantity
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
`;
|
|
377
|
+
export const START_SUBSCRIPTION_PURCHASE_MUTATION = /* GraphQL */ `
|
|
378
|
+
mutation SubscriptionsPurchaseStart($input: SubscriptionPurchaseInput!) {
|
|
379
|
+
startSubscriptionPurchase(input: $input) {
|
|
380
|
+
${PURCHASE_FIELDS}
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
`;
|
|
384
|
+
export const SUBSCRIPTION_PURCHASE_STATUS_QUERY = /* GraphQL */ `
|
|
385
|
+
query SubscriptionsPurchaseStatus($id: ID!) {
|
|
386
|
+
subscriptionPurchaseStatus(id: $id) {
|
|
387
|
+
${PURCHASE_FIELDS}
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
`;
|
|
391
|
+
export const RECONCILE_SUBSCRIPTION_PURCHASE_MUTATION = /* GraphQL */ `
|
|
392
|
+
mutation SubscriptionsPurchaseReconcile(
|
|
393
|
+
$id: ID!
|
|
394
|
+
$requestKey: String!
|
|
395
|
+
$investigationReason: String!
|
|
396
|
+
$providerReference: String
|
|
397
|
+
$reopen: Boolean
|
|
398
|
+
) {
|
|
399
|
+
reconcileSubscriptionPurchase(
|
|
400
|
+
id: $id
|
|
401
|
+
requestKey: $requestKey
|
|
402
|
+
investigationReason: $investigationReason
|
|
403
|
+
providerReference: $providerReference
|
|
404
|
+
reopen: $reopen
|
|
405
|
+
)
|
|
406
|
+
}
|
|
407
|
+
`;
|
|
408
|
+
export const PREVIEW_SUBSCRIPTION_CHANGE_QUERY = /* GraphQL */ `
|
|
409
|
+
query SubscriptionsPreviewChange($id: ID!, $input: SubscriptionLifecycleCommand!) {
|
|
410
|
+
previewSubscriptionChange(id: $id, input: $input) {
|
|
411
|
+
allowed
|
|
412
|
+
reason
|
|
413
|
+
nextRenewalAt
|
|
414
|
+
cancellationEffectiveAt
|
|
415
|
+
committedPayment
|
|
416
|
+
remainingPaidCycles
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
`;
|
|
420
|
+
export const MANAGE_SUBSCRIPTION_MUTATION = /* GraphQL */ `
|
|
421
|
+
mutation SubscriptionsManage($id: ID!, $input: SubscriptionLifecycleCommand!) {
|
|
422
|
+
manageSubscription(id: $id, input: $input) {
|
|
423
|
+
${SUBSCRIPTION_FIELDS}
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
`;
|
|
427
|
+
export const REPLACE_SUBSCRIPTION_MANDATE_MUTATION = /* GraphQL */ `
|
|
428
|
+
mutation SubscriptionsReplaceMandate($id: ID!, $input: SubscriptionPaymentActionInput!) {
|
|
429
|
+
replaceSubscriptionMandate(id: $id, input: $input) {
|
|
430
|
+
${PURCHASE_FIELDS}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
`;
|
|
434
|
+
export const RECOVER_SUBSCRIPTION_PAYMENT_MUTATION = /* GraphQL */ `
|
|
435
|
+
mutation SubscriptionsRecoverPayment($id: ID!, $input: SubscriptionPaymentActionInput!) {
|
|
436
|
+
recoverSubscriptionPayment(id: $id, input: $input) {
|
|
437
|
+
${PURCHASE_FIELDS}
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
`;
|
|
441
|
+
export const RECONCILE_SUBSCRIPTION_PAYMENT_MUTATION = /* GraphQL */ `
|
|
442
|
+
mutation SubscriptionsReconcilePayment(
|
|
443
|
+
$id: ID!
|
|
444
|
+
$attemptId: ID!
|
|
445
|
+
$providerReference: String!
|
|
446
|
+
$requestKey: String!
|
|
447
|
+
$investigationReason: String!
|
|
448
|
+
) {
|
|
449
|
+
reconcileSubscriptionPayment(
|
|
450
|
+
id: $id
|
|
451
|
+
attemptId: $attemptId
|
|
452
|
+
providerReference: $providerReference
|
|
453
|
+
requestKey: $requestKey
|
|
454
|
+
investigationReason: $investigationReason
|
|
455
|
+
) {
|
|
456
|
+
${SUBSCRIPTION_FIELDS}
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
`;
|
|
460
|
+
export const REOPEN_UNKNOWN_SUBSCRIPTION_PAYMENT_MUTATION = /* GraphQL */ `
|
|
461
|
+
mutation SubscriptionsReopenUnknownPayment(
|
|
462
|
+
$id: ID!
|
|
463
|
+
$attemptId: ID!
|
|
464
|
+
$requestKey: String!
|
|
465
|
+
$investigationReason: String!
|
|
466
|
+
) {
|
|
467
|
+
reopenUnknownSubscriptionPayment(
|
|
468
|
+
id: $id
|
|
469
|
+
attemptId: $attemptId
|
|
470
|
+
requestKey: $requestKey
|
|
471
|
+
investigationReason: $investigationReason
|
|
472
|
+
) {
|
|
473
|
+
${SUBSCRIPTION_FIELDS}
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
`;
|
|
477
|
+
export const RETRY_SUBSCRIPTION_RENEWAL_MUTATION = /* GraphQL */ `
|
|
478
|
+
mutation SubscriptionsRetryRenewal($subscriptionId: ID!, $requestKey: String) {
|
|
479
|
+
retrySubscriptionRenewal(subscriptionId: $subscriptionId, requestKey: $requestKey) {
|
|
480
|
+
${RENEWAL_FIELDS}
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
`;
|
|
484
|
+
export const RETRY_SUBSCRIPTION_SETTLEMENT_MUTATION = /* GraphQL */ `
|
|
485
|
+
mutation SubscriptionsRetrySettlement($subscriptionId: ID!, $requestKey: String) {
|
|
486
|
+
retrySubscriptionSettlement(subscriptionId: $subscriptionId, requestKey: $requestKey) {
|
|
487
|
+
${CYCLE_FIELDS}
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
`;
|
|
491
|
+
export const CLEAR_SUBSCRIPTION_CYCLE_ATTENTION_MUTATION = /* GraphQL */ `
|
|
492
|
+
mutation SubscriptionsClearAttention($cycleId: ID!, $reason: String!, $requestKey: String) {
|
|
493
|
+
clearSubscriptionCycleAttention(cycleId: $cycleId, reason: $reason, requestKey: $requestKey) {
|
|
494
|
+
${CYCLE_FIELDS}
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
`;
|
|
498
|
+
export const UPDATE_SUBSCRIPTION_PRICE_MUTATION = /* GraphQL */ `
|
|
499
|
+
mutation SubscriptionsUpdatePrice($id: ID!, $newPrice: Int!, $requestKey: String) {
|
|
500
|
+
updateSubscriptionPrice(id: $id, newPrice: $newPrice, requestKey: $requestKey) {
|
|
501
|
+
${SUBSCRIPTION_FIELDS}
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
`;
|
|
505
|
+
function unexpected(field) {
|
|
506
|
+
return new UpstreamError({
|
|
507
|
+
code: 'UNEXPECTED_RESPONSE',
|
|
508
|
+
message: `The engine answered without "${field}".`,
|
|
509
|
+
status: 502,
|
|
510
|
+
service: 'vendure',
|
|
511
|
+
});
|
|
512
|
+
}
|
|
513
|
+
function invalid(message) {
|
|
514
|
+
return new ValidationError({
|
|
515
|
+
code: 'SUBSCRIPTION_INPUT_INVALID',
|
|
516
|
+
message,
|
|
517
|
+
status: 400,
|
|
518
|
+
service: 'vendure',
|
|
519
|
+
});
|
|
520
|
+
}
|
|
521
|
+
/** The engine's enums are upper-case; the SDK answers the meta catalog's lower-case words. */
|
|
522
|
+
function lower(value) {
|
|
523
|
+
return typeof value === 'string' ? value.toLowerCase() : null;
|
|
524
|
+
}
|
|
525
|
+
function mandateOf(mandate) {
|
|
526
|
+
if (mandate === null)
|
|
527
|
+
return mandate;
|
|
528
|
+
return { ...mandate, mandateStatus: lower(mandate.mandateStatus) };
|
|
529
|
+
}
|
|
530
|
+
function subscriptionOf(wire) {
|
|
531
|
+
return {
|
|
532
|
+
...wire,
|
|
533
|
+
currentStatus: lower(wire.currentStatus),
|
|
534
|
+
mandate: mandateOf(wire.mandate),
|
|
535
|
+
};
|
|
536
|
+
}
|
|
537
|
+
/** The caller's key for this attempt, or a fresh one (one key per attempt, never per call). */
|
|
538
|
+
function keyOf(options) {
|
|
539
|
+
return options?.idempotencyKey ?? mintIdempotencyKey();
|
|
540
|
+
}
|
|
541
|
+
const CHANGE_ACTIONS = [
|
|
542
|
+
'pause',
|
|
543
|
+
'resume',
|
|
544
|
+
'skip',
|
|
545
|
+
'reschedule',
|
|
546
|
+
'undoCancellation',
|
|
547
|
+
'cancel',
|
|
548
|
+
'cancelImmediately',
|
|
549
|
+
];
|
|
550
|
+
/** The engine's `SubscriptionLifecycleCommand`, checked before anything is sent. */
|
|
551
|
+
function commandOf(change, requestKey) {
|
|
552
|
+
if (!CHANGE_ACTIONS.includes(change.action)) {
|
|
553
|
+
throw invalid(`action must be one of ${CHANGE_ACTIONS.join(', ')}; got "${String(change.action)}".`);
|
|
554
|
+
}
|
|
555
|
+
assertInstant('date', change.date);
|
|
556
|
+
return {
|
|
557
|
+
action: change.action,
|
|
558
|
+
requestKey,
|
|
559
|
+
date: change.date ?? null,
|
|
560
|
+
reason: change.reason ?? null,
|
|
561
|
+
overrideReason: change.overrideReason ?? null,
|
|
562
|
+
};
|
|
563
|
+
}
|
|
564
|
+
function purchaseOf(wire) {
|
|
565
|
+
return { ...wire, currentStatus: lower(wire.currentStatus) };
|
|
566
|
+
}
|
|
567
|
+
export function createSubscriptionsModule(transport) {
|
|
568
|
+
/** A command that answers the subscription: mapped and marked like `get`. */
|
|
569
|
+
async function subscriptionAnswer(query, field, variables, call) {
|
|
570
|
+
const redaction = redactionWatcher();
|
|
571
|
+
const data = await transport.graphql({ api: 'admin', query, variables, onExtensions: redaction.onExtensions }, call);
|
|
572
|
+
const subscription = data?.[field];
|
|
573
|
+
if (subscription == null)
|
|
574
|
+
throw unexpected(field);
|
|
575
|
+
return redaction.mark(subscriptionOf(subscription));
|
|
576
|
+
}
|
|
577
|
+
const plans = {
|
|
578
|
+
async list(options) {
|
|
579
|
+
const { take, skip, enabled, ...call } = options ?? {};
|
|
580
|
+
const page = await fieldOf(transport, SUBSCRIPTION_PLANS_QUERY, 'subscriptionPlans', { options: { take, skip, enabled } }, call);
|
|
581
|
+
if (page == null)
|
|
582
|
+
throw unexpected('subscriptionPlans');
|
|
583
|
+
return page;
|
|
584
|
+
},
|
|
585
|
+
get: (planId, options) => fieldOf(transport, SUBSCRIPTION_PLAN_QUERY, 'subscriptionPlan', { id: planId }, options),
|
|
586
|
+
create: (input, options) => fieldOf(transport, CREATE_SUBSCRIPTION_PLAN_MUTATION, 'createSubscriptionPlan', { input }, options),
|
|
587
|
+
update: (planId, input, options) => fieldOf(transport, UPDATE_SUBSCRIPTION_PLAN_MUTATION, 'updateSubscriptionPlan', { id: planId, input }, options),
|
|
588
|
+
setVariants: (planId, variants, options) => fieldOf(transport, SET_SUBSCRIPTION_PLAN_VARIANTS_MUTATION, 'setSubscriptionPlanVariants', {
|
|
589
|
+
planId,
|
|
590
|
+
variants: variants.map(({ variantId, quantity }) => ({ variantId, quantity })),
|
|
591
|
+
}, options),
|
|
592
|
+
async delete(planId, options) {
|
|
593
|
+
const response = await fieldOf(transport, DELETE_SUBSCRIPTION_PLAN_MUTATION, 'deleteSubscriptionPlan', { id: planId }, options);
|
|
594
|
+
if (response == null)
|
|
595
|
+
throw unexpected('deleteSubscriptionPlan');
|
|
596
|
+
assertDeleted('SUBSCRIPTION_PLAN_NOT_DELETED', [response]);
|
|
597
|
+
},
|
|
598
|
+
priceBreakdown: (input, options) => fieldOf(transport, SUBSCRIPTION_PLAN_PRICE_BREAKDOWN_QUERY, 'subscriptionPlanPriceBreakdown', {
|
|
599
|
+
input: {
|
|
600
|
+
price: input.price,
|
|
601
|
+
variants: input.variants.map(({ variantId, quantity }) => ({ variantId, quantity })),
|
|
602
|
+
fulfillmentMode: input.fulfillmentMode,
|
|
603
|
+
shippingMethodId: input.shippingMethodId ?? null,
|
|
604
|
+
},
|
|
605
|
+
}, options),
|
|
606
|
+
};
|
|
607
|
+
return {
|
|
608
|
+
plans,
|
|
609
|
+
purchase: {
|
|
610
|
+
async preview(input, options) {
|
|
611
|
+
const preview = await fieldOf(transport, SUBSCRIPTION_PURCHASE_PREVIEW_QUERY, 'subscriptionPurchasePreview', {
|
|
612
|
+
planId: input.planId,
|
|
613
|
+
customerId: input.customerId,
|
|
614
|
+
provider: input.provider ?? null,
|
|
615
|
+
mandateId: input.mandateId ?? null,
|
|
616
|
+
}, options);
|
|
617
|
+
if (preview == null)
|
|
618
|
+
throw unexpected('subscriptionPurchasePreview');
|
|
619
|
+
return preview;
|
|
620
|
+
},
|
|
621
|
+
async start(input, options) {
|
|
622
|
+
const key = keyOf(options);
|
|
623
|
+
const purchase = await fieldOf(transport, START_SUBSCRIPTION_PURCHASE_MUTATION, 'startSubscriptionPurchase', {
|
|
624
|
+
input: {
|
|
625
|
+
customerId: input.customerId,
|
|
626
|
+
planId: input.planId,
|
|
627
|
+
provider: input.provider ?? null,
|
|
628
|
+
mandateId: input.mandateId ?? null,
|
|
629
|
+
expectedAmount: input.expectedAmount ?? null,
|
|
630
|
+
sendPaymentEmail: input.sendPaymentEmail ?? false,
|
|
631
|
+
returnUrl: input.returnUrl ?? '',
|
|
632
|
+
requestKey: key,
|
|
633
|
+
},
|
|
634
|
+
}, { ...options, idempotencyKey: key });
|
|
635
|
+
if (purchase == null)
|
|
636
|
+
throw unexpected('startSubscriptionPurchase');
|
|
637
|
+
return purchaseOf(purchase);
|
|
638
|
+
},
|
|
639
|
+
async status(purchaseId, options) {
|
|
640
|
+
const purchase = await fieldOf(transport, SUBSCRIPTION_PURCHASE_STATUS_QUERY, 'subscriptionPurchaseStatus', { id: purchaseId }, options);
|
|
641
|
+
if (purchase == null)
|
|
642
|
+
throw unexpected('subscriptionPurchaseStatus');
|
|
643
|
+
return purchaseOf(purchase);
|
|
644
|
+
},
|
|
645
|
+
async reconcile(purchaseId, input, options) {
|
|
646
|
+
const key = keyOf(options);
|
|
647
|
+
const done = await fieldOf(transport, RECONCILE_SUBSCRIPTION_PURCHASE_MUTATION, 'reconcileSubscriptionPurchase', {
|
|
648
|
+
id: purchaseId,
|
|
649
|
+
requestKey: key,
|
|
650
|
+
investigationReason: input.investigationReason,
|
|
651
|
+
providerReference: input.providerReference ?? null,
|
|
652
|
+
reopen: input.reopen ?? false,
|
|
653
|
+
}, { ...options, idempotencyKey: key });
|
|
654
|
+
if (done !== true)
|
|
655
|
+
throw unexpected('reconcileSubscriptionPurchase');
|
|
656
|
+
},
|
|
657
|
+
},
|
|
658
|
+
async previewChange(subscriptionId, change, options) {
|
|
659
|
+
const preview = await fieldOf(transport, PREVIEW_SUBSCRIPTION_CHANGE_QUERY, 'previewSubscriptionChange',
|
|
660
|
+
// A preview writes nothing; the engine's input type still requires a key.
|
|
661
|
+
{ id: subscriptionId, input: commandOf(change, 'preview') }, options);
|
|
662
|
+
if (preview == null)
|
|
663
|
+
throw unexpected('previewSubscriptionChange');
|
|
664
|
+
return preview;
|
|
665
|
+
},
|
|
666
|
+
async manage(subscriptionId, change, options) {
|
|
667
|
+
// A JavaScript caller is not held to the type: a cancellation goes through `cancel`.
|
|
668
|
+
const action = change.action;
|
|
669
|
+
if (action === 'cancel' || action === 'cancelImmediately') {
|
|
670
|
+
throw invalid('A cancellation is made with `cancel`, not `manage`.');
|
|
671
|
+
}
|
|
672
|
+
const key = keyOf(options);
|
|
673
|
+
return subscriptionAnswer(MANAGE_SUBSCRIPTION_MUTATION, 'manageSubscription', { id: subscriptionId, input: commandOf(change, key) }, { ...options, idempotencyKey: key });
|
|
674
|
+
},
|
|
675
|
+
async cancel(subscriptionId, input, options) {
|
|
676
|
+
const key = keyOf(options);
|
|
677
|
+
const change = {
|
|
678
|
+
action: input?.immediately ? 'cancelImmediately' : 'cancel',
|
|
679
|
+
reason: input?.reason,
|
|
680
|
+
overrideReason: input?.overrideReason,
|
|
681
|
+
};
|
|
682
|
+
return subscriptionAnswer(MANAGE_SUBSCRIPTION_MUTATION, 'manageSubscription', { id: subscriptionId, input: commandOf(change, key) }, { ...options, idempotencyKey: key });
|
|
683
|
+
},
|
|
684
|
+
async replaceMandate(subscriptionId, input, options) {
|
|
685
|
+
const key = keyOf(options);
|
|
686
|
+
const purchase = await fieldOf(transport, REPLACE_SUBSCRIPTION_MANDATE_MUTATION, 'replaceSubscriptionMandate', {
|
|
687
|
+
id: subscriptionId,
|
|
688
|
+
input: { requestKey: key, provider: input.provider, returnUrl: input.returnUrl ?? '' },
|
|
689
|
+
}, { ...options, idempotencyKey: key });
|
|
690
|
+
if (purchase == null)
|
|
691
|
+
throw unexpected('replaceSubscriptionMandate');
|
|
692
|
+
return purchaseOf(purchase);
|
|
693
|
+
},
|
|
694
|
+
async recoverPayment(subscriptionId, input, options) {
|
|
695
|
+
const key = keyOf(options);
|
|
696
|
+
const purchase = await fieldOf(transport, RECOVER_SUBSCRIPTION_PAYMENT_MUTATION, 'recoverSubscriptionPayment', { id: subscriptionId, input: { requestKey: key, returnUrl: input?.returnUrl ?? '' } }, { ...options, idempotencyKey: key });
|
|
697
|
+
if (purchase == null)
|
|
698
|
+
throw unexpected('recoverSubscriptionPayment');
|
|
699
|
+
return purchaseOf(purchase);
|
|
700
|
+
},
|
|
701
|
+
async reconcilePayment(subscriptionId, input, options) {
|
|
702
|
+
const key = keyOf(options);
|
|
703
|
+
return subscriptionAnswer(RECONCILE_SUBSCRIPTION_PAYMENT_MUTATION, 'reconcileSubscriptionPayment', {
|
|
704
|
+
id: subscriptionId,
|
|
705
|
+
attemptId: input.attemptId,
|
|
706
|
+
providerReference: input.providerReference,
|
|
707
|
+
investigationReason: input.investigationReason,
|
|
708
|
+
requestKey: key,
|
|
709
|
+
}, { ...options, idempotencyKey: key });
|
|
710
|
+
},
|
|
711
|
+
async reopenUnknownPayment(subscriptionId, input, options) {
|
|
712
|
+
const key = keyOf(options);
|
|
713
|
+
return subscriptionAnswer(REOPEN_UNKNOWN_SUBSCRIPTION_PAYMENT_MUTATION, 'reopenUnknownSubscriptionPayment', {
|
|
714
|
+
id: subscriptionId,
|
|
715
|
+
attemptId: input.attemptId,
|
|
716
|
+
investigationReason: input.investigationReason,
|
|
717
|
+
requestKey: key,
|
|
718
|
+
}, { ...options, idempotencyKey: key });
|
|
719
|
+
},
|
|
720
|
+
async retryRenewal(subscriptionId, options) {
|
|
721
|
+
const key = keyOf(options);
|
|
722
|
+
const attempt = await fieldOf(transport, RETRY_SUBSCRIPTION_RENEWAL_MUTATION, 'retrySubscriptionRenewal', { subscriptionId, requestKey: key }, { ...options, idempotencyKey: key });
|
|
723
|
+
if (attempt == null)
|
|
724
|
+
throw unexpected('retrySubscriptionRenewal');
|
|
725
|
+
return attempt;
|
|
726
|
+
},
|
|
727
|
+
async retrySettlement(subscriptionId, options) {
|
|
728
|
+
const key = keyOf(options);
|
|
729
|
+
const cycle = await fieldOf(transport, RETRY_SUBSCRIPTION_SETTLEMENT_MUTATION, 'retrySubscriptionSettlement', { subscriptionId, requestKey: key }, { ...options, idempotencyKey: key });
|
|
730
|
+
if (cycle == null)
|
|
731
|
+
throw unexpected('retrySubscriptionSettlement');
|
|
732
|
+
return cycle;
|
|
733
|
+
},
|
|
734
|
+
async clearAttention(cycleId, reason, options) {
|
|
735
|
+
const key = keyOf(options);
|
|
736
|
+
const cycle = await fieldOf(transport, CLEAR_SUBSCRIPTION_CYCLE_ATTENTION_MUTATION, 'clearSubscriptionCycleAttention', { cycleId, reason, requestKey: key }, { ...options, idempotencyKey: key });
|
|
737
|
+
if (cycle == null)
|
|
738
|
+
throw unexpected('clearSubscriptionCycleAttention');
|
|
739
|
+
return cycle;
|
|
740
|
+
},
|
|
741
|
+
async updatePrice(subscriptionId, newPrice, options) {
|
|
742
|
+
if (!Number.isSafeInteger(newPrice) || newPrice < 1) {
|
|
743
|
+
throw invalid(`newPrice must be a positive integer in minor units; got ${String(newPrice)}.`);
|
|
744
|
+
}
|
|
745
|
+
const key = keyOf(options);
|
|
746
|
+
return subscriptionAnswer(UPDATE_SUBSCRIPTION_PRICE_MUTATION, 'updateSubscriptionPrice', { id: subscriptionId, newPrice, requestKey: key }, { ...options, idempotencyKey: key });
|
|
747
|
+
},
|
|
748
|
+
async list(options) {
|
|
749
|
+
const { search, needsAttention, status, customerId, planId, take, skip, ...call } = options ?? {};
|
|
750
|
+
if (status !== undefined && !SUBSCRIPTION_STATUSES.includes(status)) {
|
|
751
|
+
throw invalid(`status must be one of ${SUBSCRIPTION_STATUSES.join(', ')}; got "${String(status)}".`);
|
|
752
|
+
}
|
|
753
|
+
const redaction = redactionWatcher();
|
|
754
|
+
const data = await transport.graphql({
|
|
755
|
+
api: 'admin',
|
|
756
|
+
query: SUBSCRIPTIONS_QUERY,
|
|
757
|
+
variables: {
|
|
758
|
+
options: {
|
|
759
|
+
search,
|
|
760
|
+
needsAttention,
|
|
761
|
+
status: status?.toUpperCase(),
|
|
762
|
+
customerId,
|
|
763
|
+
planId,
|
|
764
|
+
take,
|
|
765
|
+
skip,
|
|
766
|
+
},
|
|
767
|
+
},
|
|
768
|
+
onExtensions: redaction.onExtensions,
|
|
769
|
+
}, call);
|
|
770
|
+
if (data?.subscriptions == null)
|
|
771
|
+
throw unexpected('subscriptions');
|
|
772
|
+
return {
|
|
773
|
+
items: data.subscriptions.items.map((item) => redaction.mark(subscriptionOf(item))),
|
|
774
|
+
totalItems: data.subscriptions.totalItems,
|
|
775
|
+
};
|
|
776
|
+
},
|
|
777
|
+
async get(subscriptionId, options) {
|
|
778
|
+
const redaction = redactionWatcher();
|
|
779
|
+
const data = await transport.graphql({
|
|
780
|
+
api: 'admin',
|
|
781
|
+
query: SUBSCRIPTION_QUERY,
|
|
782
|
+
variables: { id: subscriptionId },
|
|
783
|
+
onExtensions: redaction.onExtensions,
|
|
784
|
+
}, options);
|
|
785
|
+
if (data == null || !Object.hasOwn(data, 'subscription'))
|
|
786
|
+
throw unexpected('subscription');
|
|
787
|
+
const subscription = data.subscription;
|
|
788
|
+
return subscription ? redaction.mark(subscriptionOf(subscription)) : null;
|
|
789
|
+
},
|
|
790
|
+
async forCustomer(customerId, options) {
|
|
791
|
+
const redaction = redactionWatcher();
|
|
792
|
+
const data = await transport.graphql({
|
|
793
|
+
api: 'admin',
|
|
794
|
+
query: CUSTOMER_SUBSCRIPTIONS_QUERY,
|
|
795
|
+
variables: { customerId },
|
|
796
|
+
onExtensions: redaction.onExtensions,
|
|
797
|
+
}, options);
|
|
798
|
+
if (data?.customerSubscriptions == null)
|
|
799
|
+
throw unexpected('customerSubscriptions');
|
|
800
|
+
return data.customerSubscriptions.map((item) => redaction.mark(subscriptionOf(item)));
|
|
801
|
+
},
|
|
802
|
+
async mandates(customerId, options) {
|
|
803
|
+
const mandates = await fieldOf(transport, CUSTOMER_MANDATES_QUERY, 'customerMandates', { customerId }, options);
|
|
804
|
+
if (mandates == null)
|
|
805
|
+
throw unexpected('customerMandates');
|
|
806
|
+
return mandates.map(mandateOf);
|
|
807
|
+
},
|
|
808
|
+
async readiness(options) {
|
|
809
|
+
const readiness = await fieldOf(transport, SUBSCRIPTION_CHANNEL_READINESS_QUERY, 'subscriptionChannelReadiness', {}, options);
|
|
810
|
+
if (readiness == null)
|
|
811
|
+
throw unexpected('subscriptionChannelReadiness');
|
|
812
|
+
return readiness;
|
|
813
|
+
},
|
|
814
|
+
};
|
|
815
|
+
}
|