@owlmeans/server-payment 0.1.18-rc.2 → 0.1.18-rc.21
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 +109 -25
- package/agent-meta/manifest.json +2 -2
- package/agent-meta/skills/server-payment/SKILL.md +475 -52
- package/build/actions/index.d.ts +1 -0
- package/build/actions/index.d.ts.map +1 -1
- package/build/actions/index.js +1 -0
- package/build/actions/index.js.map +1 -1
- package/build/actions/resync-subscriptions.d.ts +3 -0
- package/build/actions/resync-subscriptions.d.ts.map +1 -0
- package/build/actions/resync-subscriptions.js +7 -0
- package/build/actions/resync-subscriptions.js.map +1 -0
- package/build/actions/resync.d.ts +1 -0
- package/build/actions/resync.d.ts.map +1 -1
- package/build/actions/resync.js +7 -3
- package/build/actions/resync.js.map +1 -1
- package/build/actions/webhook.d.ts.map +1 -1
- package/build/actions/webhook.js +6 -3
- package/build/actions/webhook.js.map +1 -1
- package/build/config.d.ts +60 -5
- package/build/config.d.ts.map +1 -1
- package/build/config.js +237 -5
- package/build/config.js.map +1 -1
- package/build/consts.d.ts +75 -3
- package/build/consts.d.ts.map +1 -1
- package/build/consts.js +94 -5
- package/build/consts.js.map +1 -1
- package/build/consumer/capture.d.ts +74 -0
- package/build/consumer/capture.d.ts.map +1 -0
- package/build/consumer/capture.js +291 -0
- package/build/consumer/capture.js.map +1 -0
- package/build/consumer/format.d.ts +27 -0
- package/build/consumer/format.d.ts.map +1 -0
- package/build/consumer/format.js +81 -0
- package/build/consumer/format.js.map +1 -0
- package/build/consumer/handlers.d.ts +28 -0
- package/build/consumer/handlers.d.ts.map +1 -0
- package/build/consumer/handlers.js +173 -0
- package/build/consumer/handlers.js.map +1 -0
- package/build/consumer/index.d.ts +7 -0
- package/build/consumer/index.d.ts.map +1 -0
- package/build/consumer/index.js +6 -0
- package/build/consumer/index.js.map +1 -0
- package/build/consumer/mail.d.ts +27 -0
- package/build/consumer/mail.d.ts.map +1 -0
- package/build/consumer/mail.js +314 -0
- package/build/consumer/mail.js.map +1 -0
- package/build/consumer/origin.d.ts +14 -0
- package/build/consumer/origin.d.ts.map +1 -0
- package/build/consumer/origin.js +47 -0
- package/build/consumer/origin.js.map +1 -0
- package/build/consumer/reconcile.d.ts +12 -0
- package/build/consumer/reconcile.d.ts.map +1 -0
- package/build/consumer/reconcile.js +317 -0
- package/build/consumer/reconcile.js.map +1 -0
- package/build/consumer/records.d.ts +78 -0
- package/build/consumer/records.d.ts.map +1 -0
- package/build/consumer/records.js +296 -0
- package/build/consumer/records.js.map +1 -0
- package/build/consumer/service.d.ts +51 -0
- package/build/consumer/service.d.ts.map +1 -0
- package/build/consumer/service.js +760 -0
- package/build/consumer/service.js.map +1 -0
- package/build/consumer/withdrawal.d.ts +57 -0
- package/build/consumer/withdrawal.d.ts.map +1 -0
- package/build/consumer/withdrawal.js +247 -0
- package/build/consumer/withdrawal.js.map +1 -0
- package/build/entitlement.d.ts +10 -0
- package/build/entitlement.d.ts.map +1 -0
- package/build/entitlement.js +69 -0
- package/build/entitlement.js.map +1 -0
- package/build/entrypoints.d.ts +1 -1
- package/build/entrypoints.d.ts.map +1 -1
- package/build/entrypoints.js +2 -1
- package/build/entrypoints.js.map +1 -1
- package/build/gate.d.ts +32 -4
- package/build/gate.d.ts.map +1 -1
- package/build/gate.js +59 -19
- package/build/gate.js.map +1 -1
- package/build/index.d.ts +18 -3
- package/build/index.d.ts.map +1 -1
- package/build/index.js +15 -3
- package/build/index.js.map +1 -1
- package/build/limit.d.ts +13 -0
- package/build/limit.d.ts.map +1 -0
- package/build/limit.js +47 -0
- package/build/limit.js.map +1 -0
- package/build/model.d.ts +10 -1
- package/build/model.d.ts.map +1 -1
- package/build/model.js +215 -17
- package/build/model.js.map +1 -1
- package/build/observer.d.ts +9 -0
- package/build/observer.d.ts.map +1 -1
- package/build/observer.js +38 -12
- package/build/observer.js.map +1 -1
- package/build/plan.d.ts +22 -0
- package/build/plan.d.ts.map +1 -0
- package/build/plan.js +72 -0
- package/build/plan.js.map +1 -0
- package/build/plugins/checkout-plugins.d.ts +49 -0
- package/build/plugins/checkout-plugins.d.ts.map +1 -0
- package/build/plugins/checkout-plugins.js +124 -0
- package/build/plugins/checkout-plugins.js.map +1 -0
- package/build/plugins/estimate.d.ts +43 -0
- package/build/plugins/estimate.d.ts.map +1 -0
- package/build/plugins/estimate.js +268 -0
- package/build/plugins/estimate.js.map +1 -0
- package/build/plugins/events.d.ts +45 -10
- package/build/plugins/events.d.ts.map +1 -1
- package/build/plugins/events.js +605 -136
- package/build/plugins/events.js.map +1 -1
- package/build/plugins/fx.d.ts +31 -0
- package/build/plugins/fx.d.ts.map +1 -0
- package/build/plugins/fx.js +81 -0
- package/build/plugins/fx.js.map +1 -0
- package/build/plugins/portal.d.ts +37 -0
- package/build/plugins/portal.d.ts.map +1 -0
- package/build/plugins/portal.js +265 -0
- package/build/plugins/portal.js.map +1 -0
- package/build/plugins/refunds.d.ts +33 -0
- package/build/plugins/refunds.d.ts.map +1 -0
- package/build/plugins/refunds.js +80 -0
- package/build/plugins/refunds.js.map +1 -0
- package/build/plugins/stripe.d.ts +36 -4
- package/build/plugins/stripe.d.ts.map +1 -1
- package/build/plugins/stripe.js +492 -97
- package/build/plugins/stripe.js.map +1 -1
- package/build/plugins/webhook-manager.d.ts +46 -0
- package/build/plugins/webhook-manager.d.ts.map +1 -0
- package/build/plugins/webhook-manager.js +231 -0
- package/build/plugins/webhook-manager.js.map +1 -0
- package/build/reconcile.d.ts +15 -0
- package/build/reconcile.d.ts.map +1 -0
- package/build/reconcile.js +88 -0
- package/build/reconcile.js.map +1 -0
- package/build/resource.d.ts +12 -1
- package/build/resource.d.ts.map +1 -1
- package/build/resource.js +97 -6
- package/build/resource.js.map +1 -1
- package/build/service.d.ts +28 -3
- package/build/service.d.ts.map +1 -1
- package/build/service.js +146 -19
- package/build/service.js.map +1 -1
- package/build/subscription.d.ts +48 -0
- package/build/subscription.d.ts.map +1 -0
- package/build/subscription.js +176 -0
- package/build/subscription.js.map +1 -0
- package/build/sync.d.ts +28 -1
- package/build/sync.d.ts.map +1 -1
- package/build/sync.js +208 -31
- package/build/sync.js.map +1 -1
- package/build/types.d.ts +1115 -36
- package/build/types.d.ts.map +1 -1
- package/build/usage.d.ts +63 -0
- package/build/usage.d.ts.map +1 -0
- package/build/usage.js +363 -0
- package/build/usage.js.map +1 -0
- package/build/utils.d.ts +52 -1
- package/build/utils.d.ts.map +1 -1
- package/build/utils.js +69 -7
- package/build/utils.js.map +1 -1
- package/package.json +17 -13
- package/src/actions/index.ts +1 -0
- package/src/actions/resync-subscriptions.ts +10 -0
- package/src/actions/resync.ts +6 -3
- package/src/actions/webhook.ts +5 -3
- package/src/config.ts +264 -8
- package/src/consts.ts +114 -6
- package/src/consumer/capture.ts +362 -0
- package/src/consumer/format.ts +90 -0
- package/src/consumer/handlers.ts +211 -0
- package/src/consumer/index.ts +6 -0
- package/src/consumer/mail.ts +368 -0
- package/src/consumer/origin.ts +63 -0
- package/src/consumer/reconcile.ts +329 -0
- package/src/consumer/records.ts +374 -0
- package/src/consumer/service.ts +868 -0
- package/src/consumer/withdrawal.ts +302 -0
- package/src/entitlement.ts +84 -0
- package/src/entrypoints.ts +2 -1
- package/src/gate.ts +88 -21
- package/src/index.ts +24 -3
- package/src/limit.ts +57 -0
- package/src/model.ts +237 -18
- package/src/observer.ts +44 -11
- package/src/plan.ts +89 -0
- package/src/plugins/checkout-plugins.ts +155 -0
- package/src/plugins/estimate.ts +339 -0
- package/src/plugins/events.ts +677 -121
- package/src/plugins/fx.ts +122 -0
- package/src/plugins/portal.ts +306 -0
- package/src/plugins/refunds.ts +108 -0
- package/src/plugins/stripe.ts +581 -96
- package/src/plugins/webhook-manager.ts +270 -0
- package/src/reconcile.ts +103 -0
- package/src/resource.ts +152 -7
- package/src/service.ts +174 -18
- package/src/subscription.ts +231 -0
- package/src/sync.ts +249 -29
- package/src/types.ts +1227 -32
- package/src/usage.ts +453 -0
- package/src/utils.ts +127 -10
- package/tests/checkout-consumer.spec.ts +348 -0
- package/tests/checkout-plugins.spec.ts +164 -0
- package/tests/checkout.spec.ts +184 -83
- package/tests/consumer-events.spec.ts +218 -0
- package/tests/consumer-fixtures.ts +132 -0
- package/tests/consumer-ops.spec.ts +351 -0
- package/tests/consumer-rights.integration.spec.ts +150 -0
- package/tests/consumer-rights.spec.ts +501 -0
- package/tests/context.ts +109 -0
- package/tests/entitlement.spec.ts +103 -0
- package/tests/estimate.spec.ts +240 -0
- package/tests/events.spec.ts +356 -0
- package/tests/fake-stripe.ts +972 -0
- package/tests/gate.spec.ts +62 -72
- package/tests/limit-gate.spec.ts +68 -0
- package/tests/portal.spec.ts +200 -0
- package/tests/protocol.spec.ts +23 -6
- package/tests/sync.spec.ts +114 -0
- package/tests/usage.integration.spec.ts +101 -0
- package/tests/usage.spec.ts +171 -0
- package/tests/webhook-manager.spec.ts +152 -0
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import { chargeAmountMinor, chargeCurrencyOf, CheckoutPricingMode, currencyOfCountry, ProductError, ratePpmOf, regionOf, TaxBehavior, TaxEstimateStatus, TaxType, UnknownProduct, } from '@owlmeans/payment';
|
|
2
|
+
import { STRIPE_FX_QUOTES_API_VERSION, STRIPE_PAYGATE_ALIAS } from '../consts.js';
|
|
3
|
+
import { findProduct } from '../plan.js';
|
|
4
|
+
import { isSoldThrough } from '../sync.js';
|
|
5
|
+
import { consumerRightsOf, fingerprints, isMissingObject, paygateCustomers, payment, stripePricingConfig, } from '../utils.js';
|
|
6
|
+
import { stripeFxRate } from './fx.js';
|
|
7
|
+
/** @param taxTtlMs default 24h; @param fxTtlMs default 1h; @param customerTtlMs default 5min. */
|
|
8
|
+
export const makeEstimateCache = (taxTtlMs = 24 * 60 * 60 * 1_000, fxTtlMs = 60 * 60 * 1_000, customerTtlMs = 5 * 60 * 1_000) => ({
|
|
9
|
+
taxTtlMs, fxTtlMs, customerTtlMs, tax: new Map(), fx: new Map(), customer: new Map(), inflight: new Map(),
|
|
10
|
+
});
|
|
11
|
+
/**
|
|
12
|
+
* A keyed value cached for `ttlMs`, with in-flight requests shared across concurrent callers. Only
|
|
13
|
+
* a settled (resolved) outcome is cached — a thrown error (a rate limit, a dropped connection) never
|
|
14
|
+
* is, so the next call simply tries again.
|
|
15
|
+
*/
|
|
16
|
+
const cached = async (store, inflight, key, ttlMs, factory) => {
|
|
17
|
+
const now = Date.now();
|
|
18
|
+
const hit = store.get(key);
|
|
19
|
+
if (hit != null && hit.expiresAt > now) {
|
|
20
|
+
return hit.value;
|
|
21
|
+
}
|
|
22
|
+
const pending = inflight.get(key);
|
|
23
|
+
if (pending != null) {
|
|
24
|
+
return pending;
|
|
25
|
+
}
|
|
26
|
+
const promise = factory().then(value => {
|
|
27
|
+
store.set(key, { value, expiresAt: Date.now() + ttlMs });
|
|
28
|
+
inflight.delete(key);
|
|
29
|
+
return value;
|
|
30
|
+
}).catch(error => {
|
|
31
|
+
inflight.delete(key);
|
|
32
|
+
throw error;
|
|
33
|
+
});
|
|
34
|
+
inflight.set(key, promise);
|
|
35
|
+
return promise;
|
|
36
|
+
};
|
|
37
|
+
// -------------------------------------------------------------------------------------------
|
|
38
|
+
// Customer lookup — the fallback country and the tax ids a request-given country still checks.
|
|
39
|
+
// -------------------------------------------------------------------------------------------
|
|
40
|
+
const cachedCustomer = async (ctx, stripe, entityId, cache) => cached(cache.customer, cache.inflight, `customer:${entityId}`, cache.customerTtlMs, async () => {
|
|
41
|
+
const record = await paygateCustomers(ctx).byEntity(entityId, STRIPE_PAYGATE_ALIAS);
|
|
42
|
+
if (record == null || record.deletedAt != null) {
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
try {
|
|
46
|
+
const retrieved = await stripe.customers.retrieve(record.externalId, { expand: ['tax_ids'] });
|
|
47
|
+
return retrieved.deleted ? null : retrieved;
|
|
48
|
+
}
|
|
49
|
+
catch (error) {
|
|
50
|
+
if (isMissingObject(error))
|
|
51
|
+
return null;
|
|
52
|
+
throw error;
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
/** A duck-typed check, matching `isMissingObject` above: the installed SDK's own error classes. */
|
|
56
|
+
const isInvalidRequest = (error) => error?.type === 'StripeInvalidRequestError';
|
|
57
|
+
const NON_SCALABLE_REASONS = new Set([
|
|
58
|
+
'portion_product_exempt', 'portion_reduced_rated', 'portion_standard_rated', 'taxable_basis_reduced',
|
|
59
|
+
'proportionally_rated',
|
|
60
|
+
]);
|
|
61
|
+
/** A linear percentage rate scales with the amount; a flat fee, a partial exemption, or several inclusive rates do not. */
|
|
62
|
+
const scalableOf = (breakdown, behavior) => {
|
|
63
|
+
if (breakdown.some(row => row.tax_rate_details?.rate_type === 'flat_amount'))
|
|
64
|
+
return false;
|
|
65
|
+
if (breakdown.some(row => NON_SCALABLE_REASONS.has(row.taxability_reason)))
|
|
66
|
+
return false;
|
|
67
|
+
if (behavior === TaxBehavior.Inclusive && breakdown.length > 1)
|
|
68
|
+
return false;
|
|
69
|
+
return true;
|
|
70
|
+
};
|
|
71
|
+
const statusOf = (breakdown, taxMinor) => {
|
|
72
|
+
if (breakdown.some(row => row.taxability_reason === 'reverse_charge'))
|
|
73
|
+
return TaxEstimateStatus.ReverseCharge;
|
|
74
|
+
if (taxMinor > 0)
|
|
75
|
+
return TaxEstimateStatus.Taxed;
|
|
76
|
+
if (breakdown.some(row => row.taxability_reason === 'not_supported'))
|
|
77
|
+
return TaxEstimateStatus.AtCheckout;
|
|
78
|
+
return TaxEstimateStatus.None;
|
|
79
|
+
};
|
|
80
|
+
const TAX_TYPE_MAP = Object.freeze({
|
|
81
|
+
vat: TaxType.Vat, gst: TaxType.Gst, sales_tax: TaxType.SalesTax,
|
|
82
|
+
});
|
|
83
|
+
const taxTypeOf = (raw) => raw != null && raw in TAX_TYPE_MAP ? TAX_TYPE_MAP[raw] : TaxType.Tax;
|
|
84
|
+
const ratesOf = (breakdown) => breakdown
|
|
85
|
+
.filter((row) => row.tax_rate_details != null)
|
|
86
|
+
.map(row => ({
|
|
87
|
+
type: taxTypeOf(row.tax_rate_details.tax_type),
|
|
88
|
+
percentage: row.tax_rate_details.percentage_decimal,
|
|
89
|
+
ratePpm: ratePpmOf(row.tax_rate_details.percentage_decimal),
|
|
90
|
+
...(row.tax_rate_details.country != null ? { country: row.tax_rate_details.country } : {}),
|
|
91
|
+
...(row.tax_rate_details.state != null ? { state: row.tax_rate_details.state } : {}),
|
|
92
|
+
}));
|
|
93
|
+
const taxEstimateOf = (calculation, behavior, subtotalMinor) => {
|
|
94
|
+
const breakdown = calculation.tax_breakdown ?? [];
|
|
95
|
+
const taxMinor = calculation.tax_amount_exclusive + calculation.tax_amount_inclusive;
|
|
96
|
+
const status = statusOf(breakdown, taxMinor);
|
|
97
|
+
return {
|
|
98
|
+
status, subtotalMinor, taxMinor, totalMinor: calculation.amount_total,
|
|
99
|
+
scalable: scalableOf(breakdown, behavior), rates: ratesOf(breakdown),
|
|
100
|
+
};
|
|
101
|
+
};
|
|
102
|
+
/** The reference amount and currency of the estimate: an amount plan's default preset, else the plan's own price. */
|
|
103
|
+
const referenceOf = (plan) => {
|
|
104
|
+
if (plan.pricingMode === CheckoutPricingMode.Amount) {
|
|
105
|
+
if (plan.amountPolicy == null)
|
|
106
|
+
throw new ProductError(`amount-policy:${plan.sku}`);
|
|
107
|
+
return {
|
|
108
|
+
subtotalMinor: chargeAmountMinor(plan.amountPolicy.defaultMinor, plan.amountPolicy),
|
|
109
|
+
currency: plan.amountPolicy.currency.toLowerCase(),
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
return { subtotalMinor: Math.round(plan.price * 100), currency: (plan.currency ?? 'usd').toLowerCase() };
|
|
113
|
+
};
|
|
114
|
+
/**
|
|
115
|
+
* The reference amount in the currency the buyer is charged in: a recurring or quantity plan's
|
|
116
|
+
* synced price in that currency (its default or an option — no paygate call), else the plan's own
|
|
117
|
+
* catalogue reference. An amount plan keeps its policy currency.
|
|
118
|
+
*/
|
|
119
|
+
const chargedReferenceOf = async (ctx, product, plan, chargeCurrency) => {
|
|
120
|
+
const reference = referenceOf(plan);
|
|
121
|
+
if (chargeCurrency == null || plan.pricingMode === CheckoutPricingMode.Amount || chargeCurrency === reference.currency && plan.currencyPrices == null) {
|
|
122
|
+
return reference;
|
|
123
|
+
}
|
|
124
|
+
const synced = (await fingerprints(ctx).bySku(product.sku))?.prices?.find(price => price.planSku === plan.sku);
|
|
125
|
+
if (synced == null) {
|
|
126
|
+
return reference;
|
|
127
|
+
}
|
|
128
|
+
if (synced.currency === chargeCurrency) {
|
|
129
|
+
return { subtotalMinor: synced.unitAmount, currency: chargeCurrency };
|
|
130
|
+
}
|
|
131
|
+
const option = synced.options.find(entry => entry.currency === chargeCurrency);
|
|
132
|
+
return option != null ? { subtotalMinor: option.unitAmount, currency: chargeCurrency } : reference;
|
|
133
|
+
};
|
|
134
|
+
/** A placeholder estimate — no known tax, shown by its `status`, never by its zeroed numbers. */
|
|
135
|
+
const unresolvedEstimate = (status, subtotalMinor) => ({
|
|
136
|
+
status, subtotalMinor, taxMinor: 0, totalMinor: subtotalMinor, scalable: false, rates: [],
|
|
137
|
+
});
|
|
138
|
+
const fetchFxRate = async (stripe, currency, localCurrency, apiVersion, settlementCurrency = currency) => {
|
|
139
|
+
const settlement = settlementCurrency.toLowerCase();
|
|
140
|
+
const sourceRate = settlement === currency
|
|
141
|
+
? { referenceRate: 1 }
|
|
142
|
+
: await stripeFxRate(stripe, currency, settlement, apiVersion);
|
|
143
|
+
if (sourceRate == null)
|
|
144
|
+
return null;
|
|
145
|
+
if (localCurrency === settlement) {
|
|
146
|
+
return { currency: localCurrency, exchangeRate: 1 / sourceRate.referenceRate };
|
|
147
|
+
}
|
|
148
|
+
const localRate = await stripeFxRate(stripe, localCurrency, settlement, apiVersion);
|
|
149
|
+
if (localRate == null)
|
|
150
|
+
return null;
|
|
151
|
+
return {
|
|
152
|
+
currency: localCurrency, exchangeRate: localRate.exchangeRate / sourceRate.referenceRate,
|
|
153
|
+
...(localRate.fxFeeRate != null ? { fxFeeRate: localRate.fxFeeRate } : {}),
|
|
154
|
+
};
|
|
155
|
+
};
|
|
156
|
+
// -------------------------------------------------------------------------------------------
|
|
157
|
+
/**
|
|
158
|
+
* A Stripe Tax estimate (and, when the pricing policy asks for it, a local-currency conversion) for
|
|
159
|
+
* one product/plan, at a billing country the request names or the entity's paygate customer does.
|
|
160
|
+
*
|
|
161
|
+
* Costs one Tax Calculation API call ($0.05) per distinct (currency, country, amount, tax code,
|
|
162
|
+
* behavior, matching tax ids) within `cache`'s TTL, and one free FX Quotes call per distinct
|
|
163
|
+
* (currency, local currency) — never more, and never for a rate-limit or connection error, which is
|
|
164
|
+
* never cached.
|
|
165
|
+
*/
|
|
166
|
+
export const estimateStripePrice = async (ctx, stripe, params, cache) => {
|
|
167
|
+
const product = await findProduct(ctx, params.productSku);
|
|
168
|
+
if (product == null)
|
|
169
|
+
throw new UnknownProduct(params.productSku);
|
|
170
|
+
const plans = (await payment(ctx).allPlans(product.sku))
|
|
171
|
+
.filter(plan => isSoldThrough(product, plan, STRIPE_PAYGATE_ALIAS));
|
|
172
|
+
const plan = params.planSku != null
|
|
173
|
+
? plans.find(item => item.sku === params.planSku)
|
|
174
|
+
: plans.find(item => item.recurring != null) ?? plans[0];
|
|
175
|
+
if (plan == null)
|
|
176
|
+
throw new ProductError(params.planSku != null ? `plan:${params.planSku}` : 'plan');
|
|
177
|
+
const pricing = await payment(ctx).pricingPolicy();
|
|
178
|
+
const behavior = pricing.tax.behavior ?? TaxBehavior.Exclusive;
|
|
179
|
+
const rights = await payment(ctx).consumerRightsPolicy();
|
|
180
|
+
// A locked billing country overrides whatever the request names: a picker shows it, locked.
|
|
181
|
+
const profile = rights != null ? await consumerRightsOf(ctx)?.profile(params.entityId) ?? null : null;
|
|
182
|
+
const locked = profile?.locked === true && profile.country != null;
|
|
183
|
+
let country = locked ? profile.country : params.country?.toUpperCase();
|
|
184
|
+
let source = locked ? 'profile' : country != null ? 'request' : undefined;
|
|
185
|
+
let matchingTaxIds = [];
|
|
186
|
+
let taxabilityOverride;
|
|
187
|
+
const customer = await cachedCustomer(ctx, stripe, params.entityId, cache);
|
|
188
|
+
if (customer != null) {
|
|
189
|
+
if (country == null && customer.address?.country != null) {
|
|
190
|
+
country = customer.address.country;
|
|
191
|
+
source = 'customer';
|
|
192
|
+
}
|
|
193
|
+
if (country != null) {
|
|
194
|
+
matchingTaxIds = (customer.tax_ids?.data ?? [])
|
|
195
|
+
.filter(taxId => taxId.country === country)
|
|
196
|
+
.map(taxId => ({ type: taxId.type, value: taxId.value }));
|
|
197
|
+
if (customer.tax_exempt === 'exempt')
|
|
198
|
+
taxabilityOverride = 'customer_exempt';
|
|
199
|
+
else if (customer.tax_exempt === 'reverse')
|
|
200
|
+
taxabilityOverride = 'reverse_charge';
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
const region = rights != null ? regionOf(country, rights) : null;
|
|
204
|
+
const settlementCurrency = (await stripePricingConfig(ctx))?.settlementCurrency?.toLowerCase();
|
|
205
|
+
const { subtotalMinor, currency } = await chargedReferenceOf(ctx, product, plan, rights != null && rights.currencies != null
|
|
206
|
+
&& Object.keys(rights.currencies).length > 0
|
|
207
|
+
? (profile?.currency ?? chargeCurrencyOf(region, rights, settlementCurrency ?? (plan.currency ?? 'usd'))).toLowerCase()
|
|
208
|
+
: null);
|
|
209
|
+
const where = { ...(region != null ? { region } : {}), ...(locked ? { locked: true } : {}) };
|
|
210
|
+
if (country == null) {
|
|
211
|
+
return { currency, behavior, tax: unresolvedEstimate(TaxEstimateStatus.LocationRequired, subtotalMinor), ...where };
|
|
212
|
+
}
|
|
213
|
+
const cacheKey = JSON.stringify([
|
|
214
|
+
currency, country, subtotalMinor, product.taxCode ?? null, behavior,
|
|
215
|
+
matchingTaxIds.map(id => `${id.type}:${id.value}`).sort(), taxabilityOverride ?? null,
|
|
216
|
+
]);
|
|
217
|
+
const outcome = await cached(cache.tax, cache.inflight, `tax:${cacheKey}`, cache.taxTtlMs, async () => {
|
|
218
|
+
try {
|
|
219
|
+
const calculation = await stripe.tax.calculations.create({
|
|
220
|
+
currency,
|
|
221
|
+
line_items: [{
|
|
222
|
+
amount: subtotalMinor, reference: plan.sku, tax_behavior: behavior,
|
|
223
|
+
...(product.taxCode != null ? { tax_code: product.taxCode } : {}),
|
|
224
|
+
}],
|
|
225
|
+
customer_details: {
|
|
226
|
+
address: { country },
|
|
227
|
+
address_source: 'billing',
|
|
228
|
+
// Cast: `Stripe.TaxId.type` (the customer's saved tax id) and the Tax Calculation
|
|
229
|
+
// parameter's own tax-id-type enum are independently generated from Stripe's OpenAPI
|
|
230
|
+
// spec and can drift apart in this pinned SDK; every value here still came from a real
|
|
231
|
+
// Stripe `TaxId` record, so it is valid at the API even where the two types disagree.
|
|
232
|
+
...(matchingTaxIds.length > 0
|
|
233
|
+
? { tax_ids: matchingTaxIds }
|
|
234
|
+
: {}),
|
|
235
|
+
...(taxabilityOverride != null ? { taxability_override: taxabilityOverride } : {}),
|
|
236
|
+
},
|
|
237
|
+
});
|
|
238
|
+
return { ok: true, calculation };
|
|
239
|
+
}
|
|
240
|
+
catch (error) {
|
|
241
|
+
if (isInvalidRequest(error))
|
|
242
|
+
return { ok: false, code: error.code };
|
|
243
|
+
throw error;
|
|
244
|
+
}
|
|
245
|
+
});
|
|
246
|
+
const tax = outcome.ok
|
|
247
|
+
? taxEstimateOf(outcome.calculation, behavior, subtotalMinor)
|
|
248
|
+
: unresolvedEstimate(TaxEstimateStatus.AtCheckout, subtotalMinor);
|
|
249
|
+
const result = { country, source, currency, behavior, tax, ...where };
|
|
250
|
+
// Adaptive Pricing — and so a local-currency line — applies only to a session charged in the
|
|
251
|
+
// settlement currency; a forced region currency (exact USD) is shown as it is.
|
|
252
|
+
const adaptive = rights?.currencies == null || currency === (settlementCurrency ?? currency);
|
|
253
|
+
if (pricing.currency.estimate && pricing.currency.adaptive === true && adaptive) {
|
|
254
|
+
const localCurrency = currencyOfCountry(country);
|
|
255
|
+
if (localCurrency != null && localCurrency !== currency) {
|
|
256
|
+
const stripePricing = await stripePricingConfig(ctx);
|
|
257
|
+
const apiVersion = stripePricing?.fxApiVersion ?? STRIPE_FX_QUOTES_API_VERSION;
|
|
258
|
+
const settlementCurrency = stripePricing?.settlementCurrency?.toLowerCase() ?? currency;
|
|
259
|
+
// A preview endpoint: unreachable or erroring never fails the estimate, it only drops `local`.
|
|
260
|
+
const fx = await cached(cache.fx, cache.inflight, `fx:${currency}:${settlementCurrency}:${localCurrency}:${apiVersion}`, cache.fxTtlMs, () => fetchFxRate(stripe, currency, localCurrency, apiVersion, settlementCurrency)).catch(() => null);
|
|
261
|
+
if (fx != null) {
|
|
262
|
+
result.local = { currency: fx.currency, exchangeRate: fx.exchangeRate, ...(fx.fxFeeRate != null ? { fxFeeRate: fx.fxFeeRate } : {}) };
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
return result;
|
|
267
|
+
};
|
|
268
|
+
//# sourceMappingURL=estimate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"estimate.js","sourceRoot":"","sources":["../../src/plugins/estimate.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,16 +1,51 @@
|
|
|
1
1
|
import type Stripe from 'stripe';
|
|
2
2
|
import { SubscriptionStatus } from '@owlmeans/payment';
|
|
3
3
|
import type { Context as ApiContext } from '@owlmeans/server-api';
|
|
4
|
-
|
|
4
|
+
import type { CommitResult } from '../subscription.js';
|
|
5
|
+
import type { SubscriptionRef } from '../types.js';
|
|
6
|
+
/**
|
|
7
|
+
* Stripe's subscription status as a `SubscriptionStatus`. `past_due` still entitles (flagged);
|
|
8
|
+
* `unpaid`, `paused` and paused collection revoke until resumed.
|
|
9
|
+
*/
|
|
10
|
+
export declare const mapStatus: (subscription: Pick<Stripe.Subscription, 'status' | 'pause_collection'>) => SubscriptionStatus;
|
|
11
|
+
export interface ApplyOptions {
|
|
12
|
+
source: 'webhook' | 'resync';
|
|
13
|
+
eventId?: string;
|
|
14
|
+
/** `event.created` (epoch seconds) of a webhook payload; an older payload than the stored state is skipped. */
|
|
15
|
+
eventCreated?: number;
|
|
16
|
+
renewal?: boolean;
|
|
17
|
+
invoiceId?: string;
|
|
18
|
+
trialEnding?: boolean;
|
|
19
|
+
/** Store this status whatever the payload says (a deleted subscription is canceled). */
|
|
20
|
+
forced?: SubscriptionStatus;
|
|
21
|
+
/** The paygate client — lets the first commit read the first invoice for its purchase row. */
|
|
22
|
+
stripe?: Stripe;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Apply one Stripe subscription — from a webhook payload or a fresh retrieval — to its row, and
|
|
26
|
+
* tell observers what changed. Shared by every webhook and by resync.
|
|
27
|
+
*/
|
|
28
|
+
export declare const applySubscription: (ctx: ApiContext, subscription: Stripe.Subscription, opts: ApplyOptions) => Promise<CommitResult>;
|
|
29
|
+
/**
|
|
30
|
+
* Re-read paygate subscriptions — one by id, or every row of one entity — and apply each as a
|
|
31
|
+
* webhook would. A subscription the paygate no longer has is canceled.
|
|
32
|
+
*
|
|
33
|
+
* @returns how many rows changed
|
|
34
|
+
*/
|
|
35
|
+
export declare const resyncStripeSubscription: (ctx: ApiContext, stripe: Stripe, ref: SubscriptionRef) => Promise<number>;
|
|
36
|
+
/** Resync every paygate subscription that is not already terminal. Errors per row are logged. */
|
|
37
|
+
export declare const resyncStripeSubscriptions: (ctx: ApiContext, stripe: Stripe) => Promise<{
|
|
38
|
+
scanned: number;
|
|
39
|
+
updated: number;
|
|
40
|
+
}>;
|
|
41
|
+
type EventHandler = (event: Stripe.Event) => Promise<void>;
|
|
42
|
+
/**
|
|
43
|
+
* The Stripe event dispatch table. `process` runs the handler of an event type and ignores every
|
|
44
|
+
* other type; a throw escapes so Stripe delivers the event again.
|
|
45
|
+
*/
|
|
46
|
+
export declare const createEventHandler: (ctx: ApiContext, stripe: Stripe) => {
|
|
47
|
+
handlers: Record<string, EventHandler>;
|
|
5
48
|
process: (event: Stripe.Event) => Promise<void>;
|
|
6
|
-
'customer.created': (event: Stripe.CustomerCreatedEvent) => Promise<void>;
|
|
7
|
-
'customer.updated': (event: Stripe.CustomerUpdatedEvent) => Promise<void>;
|
|
8
|
-
'checkout.session.completed': (event: Stripe.CheckoutSessionCompletedEvent) => Promise<void>;
|
|
9
|
-
'checkout.session.async_payment_succeeded': (event: Stripe.CheckoutSessionAsyncPaymentSucceededEvent) => Promise<void>;
|
|
10
|
-
'customer.subscription.created': (event: Stripe.CustomerSubscriptionCreatedEvent) => Promise<void>;
|
|
11
|
-
'customer.subscription.updated': (event: Stripe.CustomerSubscriptionUpdatedEvent) => Promise<void>;
|
|
12
|
-
'customer.subscription.deleted': (event: Stripe.CustomerSubscriptionDeletedEvent) => Promise<void>;
|
|
13
|
-
_upsertCustomer: (customer: Stripe.Customer) => Promise<void>;
|
|
14
|
-
_syncSubscription: (pgSubscription: Stripe.Subscription, forced?: SubscriptionStatus) => Promise<void>;
|
|
15
49
|
};
|
|
50
|
+
export {};
|
|
16
51
|
//# sourceMappingURL=events.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/plugins/events.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAA;AAEhC,OAAO,
|
|
1
|
+
{"version":3,"file":"events.d.ts","sourceRoot":"","sources":["../../src/plugins/events.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,QAAQ,CAAA;AAEhC,OAAO,EACkD,kBAAkB,EAC1E,MAAM,mBAAmB,CAAA;AAC1B,OAAO,KAAK,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,sBAAsB,CAAA;AAIjE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAA;AAYtD,OAAO,KAAK,EAEV,eAAe,EAChB,MAAM,aAAa,CAAA;AAmBpB;;;GAGG;AACH,eAAO,MAAM,SAAS,iBAAkB,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,QAAQ,GAAG,kBAAkB,CAAC,KAAG,kBAclG,CAAA;AAmBD,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,SAAS,GAAG,QAAQ,CAAA;IAC5B,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,+GAA+G;IAC/G,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,OAAO,CAAC,EAAE,OAAO,CAAA;IACjB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,wFAAwF;IACxF,MAAM,CAAC,EAAE,kBAAkB,CAAA;IAC3B,8FAA8F;IAC9F,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAID;;;GAGG;AACH,eAAO,MAAM,iBAAiB,QACvB,UAAU,gBAAgB,MAAM,CAAC,YAAY,QAAQ,YAAY,KACrE,OAAO,CAAC,YAAY,CA4EtB,CAAA;AA2BD;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,QAC9B,UAAU,UAAU,MAAM,OAAO,eAAe,KACpD,OAAO,CAAC,MAAM,CAuBhB,CAAA;AAID,iGAAiG;AACjG,eAAO,MAAM,yBAAyB,QAC/B,UAAU,UAAU,MAAM,KAC9B,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAuB9C,CAAA;AAgBD,KAAK,YAAY,GAAG,CAAC,KAAK,EAAE,MAAM,CAAC,KAAK,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;AAO1D;;;GAGG;AACH,eAAO,MAAM,kBAAkB,QAAS,UAAU,UAAU,MAAM;;qBAobvC,MAAM,CAAC,KAAK,KAAG,OAAO,CAAC,IAAI,CAAC;CAOtD,CAAA"}
|