payment-kit 1.25.10 → 1.26.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/api/src/libs/session.ts +43 -25
- package/api/src/queues/subscription.ts +3 -1
- package/api/src/routes/checkout-sessions.ts +50 -34
- package/api/src/routes/meters.ts +28 -0
- package/blocklet.yml +2 -1
- package/package.json +6 -6
- package/src/components/customer/actions.tsx +1 -1
- package/src/components/customer/credit-overview.tsx +3 -1
- package/src/components/customer/overdraft-protection.tsx +1 -1
- package/src/components/event/list.tsx +1 -1
- package/src/components/filter-toolbar.tsx +2 -2
- package/src/components/invoice/action.tsx +3 -3
- package/src/components/invoice/list.tsx +1 -1
- package/src/components/invoice/recharge.tsx +2 -2
- package/src/components/meter/add-usage-dialog.tsx +1 -1
- package/src/components/passport/actions.tsx +1 -1
- package/src/components/passport/assign.tsx +1 -1
- package/src/components/payment-currency/add.tsx +1 -1
- package/src/components/payment-currency/edit.tsx +1 -1
- package/src/components/payment-intent/actions.tsx +4 -4
- package/src/components/payment-intent/list.tsx +1 -1
- package/src/components/payment-link/actions.tsx +4 -4
- package/src/components/payment-link/item.tsx +1 -1
- package/src/components/payouts/list.tsx +1 -1
- package/src/components/payouts/portal/list.tsx +1 -1
- package/src/components/price/upsell-select.tsx +1 -1
- package/src/components/price/upsell.tsx +2 -2
- package/src/components/pricing-table/actions.tsx +3 -3
- package/src/components/pricing-table/product-item.tsx +1 -1
- package/src/components/product/actions.tsx +3 -3
- package/src/components/product/create.tsx +1 -1
- package/src/components/product/cross-sell.tsx +2 -2
- package/src/components/promotion/active-redemptions.tsx +1 -1
- package/src/components/refund/list.tsx +1 -1
- package/src/components/subscription/actions/index.tsx +1 -1
- package/src/components/subscription/items/usage-records.tsx +4 -2
- package/src/components/subscription/list.tsx +1 -1
- package/src/components/subscription/metrics.tsx +3 -3
- package/src/components/subscription/portal/actions.tsx +15 -12
- package/src/components/subscription/portal/list.tsx +1 -1
- package/src/components/webhook/attempts.tsx +4 -4
- package/src/hooks/subscription.ts +2 -2
- package/src/pages/admin/billing/meter-events/index.tsx +3 -3
- package/src/pages/admin/billing/meters/index.tsx +1 -1
- package/src/pages/admin/billing/overdue/index.tsx +2 -2
- package/src/pages/admin/billing/subscriptions/detail.tsx +2 -2
- package/src/pages/admin/customers/customers/credit-grant/detail.tsx +1 -1
- package/src/pages/admin/customers/customers/credit-transaction/detail.tsx +1 -1
- package/src/pages/admin/customers/customers/detail.tsx +4 -4
- package/src/pages/admin/developers/events/detail.tsx +1 -1
- package/src/pages/admin/developers/webhooks/detail.tsx +1 -1
- package/src/pages/admin/developers/webhooks/index.tsx +1 -1
- package/src/pages/admin/payments/intents/detail.tsx +2 -2
- package/src/pages/admin/payments/payouts/detail.tsx +2 -2
- package/src/pages/admin/payments/refunds/detail.tsx +2 -2
- package/src/pages/admin/products/coupons/detail.tsx +1 -1
- package/src/pages/admin/products/coupons/index.tsx +1 -1
- package/src/pages/admin/products/exchange-rate-providers/index.tsx +1 -1
- package/src/pages/admin/products/links/create.tsx +1 -1
- package/src/pages/admin/products/links/detail.tsx +2 -2
- package/src/pages/admin/products/links/index.tsx +1 -1
- package/src/pages/admin/products/passports/index.tsx +1 -1
- package/src/pages/admin/products/prices/actions.tsx +4 -4
- package/src/pages/admin/products/prices/detail.tsx +2 -2
- package/src/pages/admin/products/pricing-tables/create.tsx +1 -1
- package/src/pages/admin/products/pricing-tables/detail.tsx +2 -2
- package/src/pages/admin/products/pricing-tables/index.tsx +1 -1
- package/src/pages/admin/products/products/index.tsx +1 -1
- package/src/pages/admin/products/promotion-codes/actions.tsx +2 -2
- package/src/pages/admin/products/promotion-codes/detail.tsx +2 -2
- package/src/pages/admin/products/promotion-codes/list.tsx +1 -1
- package/src/pages/admin/settings/payment-methods/create.tsx +1 -1
- package/src/pages/admin/settings/payment-methods/edit.tsx +1 -1
- package/src/pages/admin/settings/payment-methods/index.tsx +2 -2
- package/src/pages/admin/tax/detail.tsx +2 -2
- package/src/pages/admin/tax/list.tsx +1 -1
- package/src/pages/checkout/pay.tsx +2 -2
- package/src/pages/customer/index.tsx +1 -1
- package/src/pages/customer/invoice/past-due.tsx +1 -1
- package/src/pages/customer/payout/detail.tsx +1 -1
- package/src/pages/customer/refund/list.tsx +1 -1
- package/src/pages/customer/subscription/change-payment.tsx +2 -2
- package/src/pages/customer/subscription/change-plan.tsx +3 -3
- package/src/pages/customer/subscription/detail.tsx +3 -3
- package/src/pages/integrations/donations/index.tsx +1 -1
- package/vite.config.ts +2 -1
package/api/src/libs/session.ts
CHANGED
|
@@ -120,9 +120,16 @@ export async function getCheckoutAmount(
|
|
|
120
120
|
.reduce(
|
|
121
121
|
async (accPromise, x) => {
|
|
122
122
|
const acc = await accPromise;
|
|
123
|
+
const price = x.upsell_price || x.price;
|
|
124
|
+
|
|
125
|
+
const isRecurring = price?.type === 'recurring';
|
|
126
|
+
// trialing/metered recurring items: no upfront charge, skip adding to subtotal
|
|
127
|
+
const skipAccAdd = isRecurring && (trialing || price?.recurring?.usage_type === 'metered');
|
|
123
128
|
|
|
124
129
|
// Priority 1: Use custom_amount if available
|
|
125
130
|
if (x.custom_amount) {
|
|
131
|
+
if (isRecurring) renew = renew.add(new BN(x.custom_amount));
|
|
132
|
+
if (skipAccAdd) return acc;
|
|
126
133
|
return acc.add(new BN(x.custom_amount));
|
|
127
134
|
}
|
|
128
135
|
|
|
@@ -136,6 +143,8 @@ export async function getCheckoutAmount(
|
|
|
136
143
|
quoteId: (x as any).quote_id,
|
|
137
144
|
quotedAmount: quote.quoted_amount,
|
|
138
145
|
});
|
|
146
|
+
if (isRecurring) renew = renew.add(new BN(quote.quoted_amount));
|
|
147
|
+
if (skipAccAdd) return acc;
|
|
139
148
|
return acc.add(new BN(quote.quoted_amount));
|
|
140
149
|
}
|
|
141
150
|
|
|
@@ -154,27 +163,23 @@ export async function getCheckoutAmount(
|
|
|
154
163
|
}
|
|
155
164
|
|
|
156
165
|
// Priority 3: Calculate from price (fixed pricing or quote query failed)
|
|
157
|
-
const price = x.upsell_price || x.price;
|
|
158
166
|
const unitPrice = getPriceUintAmountByCurrency(price, currencyId);
|
|
159
167
|
|
|
168
|
+
const itemPrice = new BN(unitPrice).mul(new BN(x.quantity));
|
|
160
169
|
if (price.custom_unit_amount) {
|
|
161
170
|
if (unitPrice) {
|
|
162
|
-
|
|
171
|
+
if (isRecurring) renew = renew.add(itemPrice);
|
|
172
|
+
if (skipAccAdd) return acc;
|
|
173
|
+
return acc.add(itemPrice);
|
|
163
174
|
}
|
|
164
175
|
}
|
|
165
176
|
|
|
166
|
-
if (
|
|
167
|
-
renew = renew.add(
|
|
168
|
-
|
|
169
|
-
if (trialing) {
|
|
170
|
-
return acc;
|
|
171
|
-
}
|
|
172
|
-
if (price?.recurring?.usage_type === 'metered') {
|
|
173
|
-
return acc;
|
|
174
|
-
}
|
|
177
|
+
if (isRecurring) {
|
|
178
|
+
renew = renew.add(itemPrice);
|
|
179
|
+
if (skipAccAdd) return acc;
|
|
175
180
|
}
|
|
176
181
|
|
|
177
|
-
return acc.add(
|
|
182
|
+
return acc.add(itemPrice);
|
|
178
183
|
},
|
|
179
184
|
Promise.resolve(new BN(0))
|
|
180
185
|
)
|
|
@@ -1301,19 +1306,24 @@ export async function validatePaymentAmounts(
|
|
|
1301
1306
|
return { valid: true };
|
|
1302
1307
|
}
|
|
1303
1308
|
|
|
1304
|
-
// Case 2:
|
|
1309
|
+
// Case 2: Subscriptions - validate non-metered recurring items only.
|
|
1310
|
+
// Metered items are usage-based, their invoice amount depends on actual usage,
|
|
1311
|
+
// so checking unit_price against the minimum is meaningless.
|
|
1305
1312
|
if (recurringItems.length > 0) {
|
|
1306
1313
|
if (enableGrouping) {
|
|
1307
|
-
//
|
|
1314
|
+
// Each subscription group is billed independently
|
|
1308
1315
|
const priceGroups = groupLineItemsByPrice(lineItems);
|
|
1309
1316
|
|
|
1310
1317
|
for (const [priceId, items] of Object.entries(priceGroups)) {
|
|
1311
|
-
//
|
|
1312
|
-
|
|
1318
|
+
// Skip metered groups — invoice amount depends on usage, not fixed price
|
|
1319
|
+
const price = items[0]?.upsell_price || items[0]?.price;
|
|
1320
|
+
// eslint-disable-next-line no-continue
|
|
1321
|
+
if (price?.recurring?.usage_type === 'metered') continue;
|
|
1313
1322
|
|
|
1323
|
+
let totalUnitPrice = new BN(0);
|
|
1314
1324
|
items.forEach((item) => {
|
|
1315
|
-
const
|
|
1316
|
-
const unitPrice = getPriceUintAmountByCurrency(
|
|
1325
|
+
const p = item.upsell_price || item.price;
|
|
1326
|
+
const unitPrice = getPriceUintAmountByCurrency(p, currency.id);
|
|
1317
1327
|
totalUnitPrice = totalUnitPrice.add(new BN(unitPrice).mul(new BN(item.quantity)));
|
|
1318
1328
|
});
|
|
1319
1329
|
|
|
@@ -1326,13 +1336,21 @@ export async function validatePaymentAmounts(
|
|
|
1326
1336
|
}
|
|
1327
1337
|
}
|
|
1328
1338
|
} else {
|
|
1329
|
-
//
|
|
1330
|
-
const
|
|
1331
|
-
|
|
1332
|
-
return
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1339
|
+
// Non-grouping: all recurring items share one invoice
|
|
1340
|
+
const nonMeteredItems = recurringItems.filter((item) => {
|
|
1341
|
+
const price = item.upsell_price || item.price;
|
|
1342
|
+
return price?.recurring?.usage_type !== 'metered';
|
|
1343
|
+
});
|
|
1344
|
+
|
|
1345
|
+
// If all recurring items are metered, skip validation
|
|
1346
|
+
if (nonMeteredItems.length > 0) {
|
|
1347
|
+
const { renew } = await getCheckoutAmount(nonMeteredItems, currency.id);
|
|
1348
|
+
if (new BN(renew).lt(new BN(minAmountInUnits))) {
|
|
1349
|
+
return {
|
|
1350
|
+
valid: false,
|
|
1351
|
+
error: 'Total subscription amount must be greater or equal to 0.5 USD',
|
|
1352
|
+
};
|
|
1353
|
+
}
|
|
1336
1354
|
}
|
|
1337
1355
|
}
|
|
1338
1356
|
}
|
|
@@ -399,7 +399,9 @@ const doHandleSubscriptionInvoice = async ({
|
|
|
399
399
|
});
|
|
400
400
|
}
|
|
401
401
|
|
|
402
|
-
|
|
402
|
+
// Skip slippage check when final amount is 0 (e.g. 100% discount) — no crypto payment needed
|
|
403
|
+
const isFinalAmountZero = new BN(safeFinalTotal).isZero();
|
|
404
|
+
const shouldMarkOverdue = slippageCheck?.belowThreshold === true && !isFinalAmountZero;
|
|
403
405
|
const invoiceStatus = shouldMarkOverdue && status === 'open' ? 'uncollectible' : status;
|
|
404
406
|
|
|
405
407
|
const { invoice } = await ensureInvoiceAndItems({
|
|
@@ -550,13 +550,15 @@ async function createOrUpdatePaymentIntent(
|
|
|
550
550
|
if (shouldLockQuotes) {
|
|
551
551
|
const lockedAtMs = paymentIntent.quote_locked_at ? new Date(paymentIntent.quote_locked_at).getTime() : null;
|
|
552
552
|
if (lockedAtMs && nowMs - lockedAtMs > QUOTE_LOCK_DURATION_MS) {
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
553
|
+
// Lock expired — reset instead of throwing
|
|
554
|
+
// Intent: "Quote never expires due to time — time limits are flow SLAs, not price validity"
|
|
555
|
+
logger.info('Quote lock expired, resetting for resubmit', {
|
|
556
|
+
sessionId: checkoutSession.id,
|
|
557
|
+
lockedAtMs,
|
|
558
|
+
expiredMs: nowMs - lockedAtMs,
|
|
556
559
|
});
|
|
557
|
-
|
|
558
|
-
}
|
|
559
|
-
if (!lockedAtMs) {
|
|
560
|
+
updateData.quote_locked_at = new Date(nowMs);
|
|
561
|
+
} else if (!lockedAtMs) {
|
|
560
562
|
updateData.quote_locked_at = new Date(nowMs);
|
|
561
563
|
}
|
|
562
564
|
}
|
|
@@ -1894,38 +1896,52 @@ async function createQuotesAtSubmit(options: {
|
|
|
1894
1896
|
|
|
1895
1897
|
// Early check: if user has set min_acceptable_rate, verify current rate is above it
|
|
1896
1898
|
// This prevents users from submitting when the rate has already dropped below their limit
|
|
1897
|
-
if (
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1899
|
+
// Skip for idempotent retries: if quotes already exist, reuse them (intent: "retry with same Quote")
|
|
1900
|
+
if (minAcceptableRate && dynamicItems.length > 0) {
|
|
1901
|
+
const firstItem = dynamicItems[0]!;
|
|
1902
|
+
const firstPriceId = firstItem.upsell_price_id || firstItem.price_id;
|
|
1903
|
+
const firstItemKey = `${idempotencyKey}:${firstPriceId}`;
|
|
1904
|
+
const existingQuote = await PriceQuote.findByIdempotencyKey(firstItemKey);
|
|
1905
|
+
|
|
1906
|
+
if (existingQuote) {
|
|
1907
|
+
logger.info('Skipping early rate check for idempotent retry (quotes already exist)', {
|
|
1908
|
+
sessionId: checkoutSession.id,
|
|
1909
|
+
idempotencyKey,
|
|
1910
|
+
existingQuoteId: existingQuote.id,
|
|
1911
|
+
});
|
|
1912
|
+
} else {
|
|
1913
|
+
try {
|
|
1914
|
+
const rateResult = await fetchCurrentExchangeRate(
|
|
1915
|
+
paymentCurrency as PaymentCurrency,
|
|
1916
|
+
paymentCurrency?.payment_method as PaymentMethod
|
|
1917
|
+
);
|
|
1911
1918
|
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
validationError: {
|
|
1916
|
-
code: 'RATE_BELOW_SLIPPAGE_LIMIT',
|
|
1917
|
-
message: `Current exchange rate (${rateResult.rate}) is below your minimum acceptable rate (${minAcceptableRate}). Please update your slippage settings.`,
|
|
1919
|
+
if (isRateBelowMinAcceptableRate(rateResult.rate, minAcceptableRate)) {
|
|
1920
|
+
logger.info('Current rate below user slippage limit', {
|
|
1921
|
+
sessionId: checkoutSession.id,
|
|
1918
1922
|
currentRate: rateResult.rate,
|
|
1919
1923
|
minAcceptableRate,
|
|
1920
|
-
|
|
1921
|
-
|
|
1924
|
+
slippagePercent,
|
|
1925
|
+
});
|
|
1926
|
+
|
|
1927
|
+
return {
|
|
1928
|
+
lineItems,
|
|
1929
|
+
consumedQuotes: [],
|
|
1930
|
+
validationError: {
|
|
1931
|
+
code: 'RATE_BELOW_SLIPPAGE_LIMIT',
|
|
1932
|
+
message: `Current exchange rate (${rateResult.rate}) is below your minimum acceptable rate (${minAcceptableRate}). Please update your slippage settings.`,
|
|
1933
|
+
currentRate: rateResult.rate,
|
|
1934
|
+
minAcceptableRate,
|
|
1935
|
+
},
|
|
1936
|
+
};
|
|
1937
|
+
}
|
|
1938
|
+
} catch (error: any) {
|
|
1939
|
+
logger.warn('Failed to fetch rate for slippage limit check', {
|
|
1940
|
+
sessionId: checkoutSession.id,
|
|
1941
|
+
error: error.message,
|
|
1942
|
+
});
|
|
1943
|
+
// Continue with normal flow if rate fetch fails - will be caught later
|
|
1922
1944
|
}
|
|
1923
|
-
} catch (error: any) {
|
|
1924
|
-
logger.warn('Failed to fetch rate for slippage limit check', {
|
|
1925
|
-
sessionId: checkoutSession.id,
|
|
1926
|
-
error: error.message,
|
|
1927
|
-
});
|
|
1928
|
-
// Continue with normal flow if rate fetch fails - will be caught later
|
|
1929
1945
|
}
|
|
1930
1946
|
}
|
|
1931
1947
|
|
package/api/src/routes/meters.ts
CHANGED
|
@@ -137,6 +137,34 @@ router.post('/', auth, async (req, res) => {
|
|
|
137
137
|
}
|
|
138
138
|
});
|
|
139
139
|
|
|
140
|
+
// Public endpoint: only returns safe fields, no auth required
|
|
141
|
+
const PUBLIC_METER_FIELDS = ['id', 'name', 'event_name', 'status', 'unit', 'description', 'currency_id'] as const;
|
|
142
|
+
|
|
143
|
+
router.get('/public/:id', async (req, res) => {
|
|
144
|
+
try {
|
|
145
|
+
const meter = await Meter.findOne({
|
|
146
|
+
where: {
|
|
147
|
+
[Op.or]: [{ id: req.params.id }, { event_name: req.params.id }],
|
|
148
|
+
},
|
|
149
|
+
include: [{ model: PaymentCurrency, as: 'paymentCurrency' }],
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
if (!meter) {
|
|
153
|
+
return res.status(404).json({ error: 'Meter not found' });
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
return res.json({
|
|
157
|
+
...pick(meter.toJSON(), PUBLIC_METER_FIELDS),
|
|
158
|
+
paymentCurrency: (meter as any).paymentCurrency
|
|
159
|
+
? pick((meter as any).paymentCurrency.toJSON(), ['id', 'name', 'symbol', 'decimal', 'logo', 'type'])
|
|
160
|
+
: null,
|
|
161
|
+
});
|
|
162
|
+
} catch (err) {
|
|
163
|
+
logger.error('get public meter failed', { error: err?.message, meterId: req.params.id });
|
|
164
|
+
return res.status(400).json({ error: err?.message });
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
|
|
140
168
|
router.get('/:id', auth, async (req, res) => {
|
|
141
169
|
try {
|
|
142
170
|
const meter = await Meter.findOne({
|
package/blocklet.yml
CHANGED
|
@@ -14,7 +14,7 @@ repository:
|
|
|
14
14
|
type: git
|
|
15
15
|
url: git+https://github.com/blocklet/payment-kit.git
|
|
16
16
|
specVersion: 1.2.8
|
|
17
|
-
version: 1.
|
|
17
|
+
version: 1.26.0
|
|
18
18
|
logo: logo.png
|
|
19
19
|
files:
|
|
20
20
|
- dist
|
|
@@ -47,6 +47,7 @@ interfaces:
|
|
|
47
47
|
- /api/products/**
|
|
48
48
|
- /methods/**
|
|
49
49
|
- /currencies/**
|
|
50
|
+
- /meters/public/**
|
|
50
51
|
blockUnauthorized: false
|
|
51
52
|
proxyBehavior: service
|
|
52
53
|
community: ''
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "payment-kit",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.26.0",
|
|
4
4
|
"scripts": {
|
|
5
5
|
"dev": "blocklet dev --open",
|
|
6
6
|
"prelint": "npm run types",
|
|
@@ -59,9 +59,9 @@
|
|
|
59
59
|
"@blocklet/error": "^0.3.5",
|
|
60
60
|
"@blocklet/js-sdk": "^1.17.8-beta-20260104-120132-cb5b1914",
|
|
61
61
|
"@blocklet/logger": "^1.17.8-beta-20260104-120132-cb5b1914",
|
|
62
|
-
"@blocklet/payment-broker-client": "1.
|
|
63
|
-
"@blocklet/payment-react": "1.
|
|
64
|
-
"@blocklet/payment-vendor": "1.
|
|
62
|
+
"@blocklet/payment-broker-client": "1.26.0",
|
|
63
|
+
"@blocklet/payment-react": "1.26.0",
|
|
64
|
+
"@blocklet/payment-vendor": "1.26.0",
|
|
65
65
|
"@blocklet/sdk": "^1.17.8-beta-20260104-120132-cb5b1914",
|
|
66
66
|
"@blocklet/ui-react": "^3.5.1",
|
|
67
67
|
"@blocklet/uploader": "^0.3.19",
|
|
@@ -132,7 +132,7 @@
|
|
|
132
132
|
"devDependencies": {
|
|
133
133
|
"@abtnode/types": "^1.17.8-beta-20260104-120132-cb5b1914",
|
|
134
134
|
"@arcblock/eslint-config-ts": "^0.3.3",
|
|
135
|
-
"@blocklet/payment-types": "1.
|
|
135
|
+
"@blocklet/payment-types": "1.26.0",
|
|
136
136
|
"@types/cookie-parser": "^1.4.9",
|
|
137
137
|
"@types/cors": "^2.8.19",
|
|
138
138
|
"@types/debug": "^4.1.12",
|
|
@@ -179,5 +179,5 @@
|
|
|
179
179
|
"parser": "typescript"
|
|
180
180
|
}
|
|
181
181
|
},
|
|
182
|
-
"gitHead": "
|
|
182
|
+
"gitHead": "9585ec8bc077fc5f8a8c5946d05436b10576e145"
|
|
183
183
|
}
|
|
@@ -25,7 +25,7 @@ export default function CustomerActions({ data, onChange, variant = 'compact' }:
|
|
|
25
25
|
const onUpdateInfo = async (updates: TCustomerExpanded) => {
|
|
26
26
|
try {
|
|
27
27
|
setState({ loading: true });
|
|
28
|
-
await api.put(`/api/customers/${data.id}`, updates).then((res) => res.data);
|
|
28
|
+
await api.put(`/api/customers/${data.id}`, updates).then((res: any) => res.data);
|
|
29
29
|
Toast.success(t('common.saved'));
|
|
30
30
|
onChange('update');
|
|
31
31
|
} catch (err) {
|
|
@@ -117,7 +117,9 @@ export default function CreditOverview({ customerId, settings, mode = 'portal' }
|
|
|
117
117
|
|
|
118
118
|
const handleRecharge = async (currency: TPaymentCurrency) => {
|
|
119
119
|
try {
|
|
120
|
-
const response = await api
|
|
120
|
+
const response = await api
|
|
121
|
+
.get(`/api/payment-currencies/${currency.id}/recharge-config`)
|
|
122
|
+
.then((res: any) => res.data);
|
|
121
123
|
if (response.recharge_config && response.recharge_config.payment_url) {
|
|
122
124
|
const url = new URL(response.recharge_config.payment_url);
|
|
123
125
|
url.searchParams.set('redirect', window.location.href);
|
|
@@ -35,7 +35,7 @@ const fetchCycleAmount = (
|
|
|
35
35
|
subscriptionId: string,
|
|
36
36
|
params: { overdraftProtection: boolean }
|
|
37
37
|
): Promise<{ amount: string; gas: string; currency: TPaymentCurrency }> => {
|
|
38
|
-
return api.get(`/api/subscriptions/${subscriptionId}/cycle-amount`, { params }).then((res) => res.data);
|
|
38
|
+
return api.get(`/api/subscriptions/${subscriptionId}/cycle-amount`, { params }).then((res: any) => res.data);
|
|
39
39
|
};
|
|
40
40
|
|
|
41
41
|
function safeAdd(currency: { decimal: number }, ...numbers: string[]) {
|
|
@@ -16,7 +16,7 @@ const fetchData = (params: Record<string, any> = {}): Promise<{ list: TEventExpa
|
|
|
16
16
|
Object.keys(params).forEach((key) => {
|
|
17
17
|
search.set(key, String(params[key]));
|
|
18
18
|
});
|
|
19
|
-
return api.get(`/api/events?${search.toString()}`).then((res) => res.data);
|
|
19
|
+
return api.get(`/api/events?${search.toString()}`).then((res: any) => res.data);
|
|
20
20
|
};
|
|
21
21
|
|
|
22
22
|
type SearchProps = {
|
|
@@ -30,7 +30,7 @@ const fetchUserData = (params: Record<string, any> = {}): Promise<{ list: TCusto
|
|
|
30
30
|
}
|
|
31
31
|
search.set(key, String(v));
|
|
32
32
|
});
|
|
33
|
-
return api.get(`api/customers?${search.toString()}`).then((res) => res.data);
|
|
33
|
+
return api.get(`api/customers?${search.toString()}`).then((res: any) => res.data);
|
|
34
34
|
};
|
|
35
35
|
|
|
36
36
|
const fetchSubscriptionItems = (params: Record<string, any> = {}): Promise<{ list: TCustomer[]; count: number }> => {
|
|
@@ -39,7 +39,7 @@ const fetchSubscriptionItems = (params: Record<string, any> = {}): Promise<{ lis
|
|
|
39
39
|
const v = params[key];
|
|
40
40
|
search.set(key, String(v));
|
|
41
41
|
});
|
|
42
|
-
return api.get(`api/subscription-items?${search.toString()}`).then((res) => res.data);
|
|
42
|
+
return api.get(`api/subscription-items?${search.toString()}`).then((res: any) => res.data);
|
|
43
43
|
};
|
|
44
44
|
|
|
45
45
|
type Props = {
|
|
@@ -55,7 +55,7 @@ export default function InvoiceActions({ data, variant = 'compact', onChange, mo
|
|
|
55
55
|
try {
|
|
56
56
|
setState({ loading: true });
|
|
57
57
|
if (state.action === 'return-stake') {
|
|
58
|
-
const result = await api.post(`/api/invoices/${data.id}/return-stake`).then((res) => res.data);
|
|
58
|
+
const result = await api.post(`/api/invoices/${data.id}/return-stake`).then((res: any) => res.data);
|
|
59
59
|
if (result.success) {
|
|
60
60
|
Toast.success(t('admin.invoice.returnStake.success'));
|
|
61
61
|
} else {
|
|
@@ -69,11 +69,11 @@ export default function InvoiceActions({ data, variant = 'compact', onChange, mo
|
|
|
69
69
|
invoiceId: data.id,
|
|
70
70
|
},
|
|
71
71
|
})
|
|
72
|
-
.then((res) => res.data);
|
|
72
|
+
.then((res: any) => res.data);
|
|
73
73
|
Toast.success(t('admin.invoice.retryUncollectible.success'));
|
|
74
74
|
}
|
|
75
75
|
if (state.action === 'void') {
|
|
76
|
-
await api.post(`/api/invoices/${data.id}/void`).then((res) => res.data);
|
|
76
|
+
await api.post(`/api/invoices/${data.id}/void`).then((res: any) => res.data);
|
|
77
77
|
Toast.success(t('admin.invoice.void.success'));
|
|
78
78
|
}
|
|
79
79
|
onChange(state.action);
|
|
@@ -52,7 +52,7 @@ const fetchData = (params: Record<string, any> = {}): Promise<{ list: TInvoiceEx
|
|
|
52
52
|
search.set(key, String(v));
|
|
53
53
|
});
|
|
54
54
|
|
|
55
|
-
return api.get(`/api/invoices?${search.toString()}`).then((res) => res.data);
|
|
55
|
+
return api.get(`/api/invoices?${search.toString()}`).then((res: any) => res.data);
|
|
56
56
|
};
|
|
57
57
|
|
|
58
58
|
type SearchProps = {
|
|
@@ -35,12 +35,12 @@ const fetchData = (
|
|
|
35
35
|
});
|
|
36
36
|
|
|
37
37
|
if (subscriptionId) {
|
|
38
|
-
return api.get(`/api/subscriptions/${subscriptionId}/recharge?${search.toString()}`).then((res) => res.data);
|
|
38
|
+
return api.get(`/api/subscriptions/${subscriptionId}/recharge?${search.toString()}`).then((res: any) => res.data);
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
if (currencyId) {
|
|
42
42
|
search.set('currency_id', currencyId);
|
|
43
|
-
return api.get(`/api/invoices/recharge?${search.toString()}`).then((res) => res.data);
|
|
43
|
+
return api.get(`/api/invoices/recharge?${search.toString()}`).then((res: any) => res.data);
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
return Promise.resolve({ list: [], count: 0 });
|
|
@@ -30,7 +30,7 @@ export default function PassportActions(rawProps: Props) {
|
|
|
30
30
|
try {
|
|
31
31
|
setState({ loading: true });
|
|
32
32
|
// eslint-disable-next-line react/prop-types
|
|
33
|
-
await api.delete(`/api/passports/assign/${props.data.name}`).then((res) => res.data);
|
|
33
|
+
await api.delete(`/api/passports/assign/${props.data.name}`).then((res: any) => res.data);
|
|
34
34
|
Toast.success(t('common.saved'));
|
|
35
35
|
} catch (err) {
|
|
36
36
|
console.error(err);
|
|
@@ -6,7 +6,7 @@ import { useRequest } from 'ahooks';
|
|
|
6
6
|
import { useEffect, useState } from 'react';
|
|
7
7
|
|
|
8
8
|
const fetchData = (): Promise<any[]> => {
|
|
9
|
-
return api.get('/api/passports').then((res) => res.data);
|
|
9
|
+
return api.get('/api/passports').then((res: any) => res.data);
|
|
10
10
|
};
|
|
11
11
|
|
|
12
12
|
export default function AssignPassportDialog(props: { id: string; onCancel: any }) {
|
|
@@ -116,7 +116,7 @@ export default function PaymentCurrencyAdd({
|
|
|
116
116
|
dispatch('drawer.submitted');
|
|
117
117
|
dispatch('paymentCurrency.added');
|
|
118
118
|
})
|
|
119
|
-
.catch((err) => {
|
|
119
|
+
.catch((err: any) => {
|
|
120
120
|
setState({ loading: false });
|
|
121
121
|
console.error(err);
|
|
122
122
|
Toast.error(formatError(err));
|
|
@@ -132,7 +132,7 @@ export default function PaymentCurrencyEdit({
|
|
|
132
132
|
dispatch('drawer.submitted');
|
|
133
133
|
dispatch('paymentCurrency.updated');
|
|
134
134
|
})
|
|
135
|
-
.catch((err) => {
|
|
135
|
+
.catch((err: any) => {
|
|
136
136
|
setState({ loading: false });
|
|
137
137
|
console.error(err);
|
|
138
138
|
Toast.error(formatError(err));
|
|
@@ -28,7 +28,7 @@ type Props = {
|
|
|
28
28
|
};
|
|
29
29
|
|
|
30
30
|
const fetchRefundData = (id: string) => {
|
|
31
|
-
return api.get(`/api/payment-intents/${id}/refundable-amount`).then((res) => res.data);
|
|
31
|
+
return api.get(`/api/payment-intents/${id}/refundable-amount`).then((res: any) => res.data);
|
|
32
32
|
};
|
|
33
33
|
|
|
34
34
|
function RefundForm({ data, refundMaxAmount }: { data: TPaymentIntentExpanded; refundMaxAmount: string }) {
|
|
@@ -176,7 +176,7 @@ export function PaymentIntentActionsInner({ data, variant = 'compact', onChange
|
|
|
176
176
|
});
|
|
177
177
|
const [refundMaxAmount, setRefundMaxAmount] = useState('0');
|
|
178
178
|
const isSlash = data.payment_details?.arcblock?.type === 'slash' && data.paymentMethod?.type === 'arcblock';
|
|
179
|
-
const { runAsync: runRefundAmountAsync } = useRequest(
|
|
179
|
+
const { runAsync: runRefundAmountAsync } = useRequest<any, any[]>(
|
|
180
180
|
() => {
|
|
181
181
|
if (isSlash) {
|
|
182
182
|
return Promise.resolve({ amount: '0' });
|
|
@@ -184,7 +184,7 @@ export function PaymentIntentActionsInner({ data, variant = 'compact', onChange
|
|
|
184
184
|
return fetchRefundData(data.id);
|
|
185
185
|
},
|
|
186
186
|
{
|
|
187
|
-
onSuccess: (res) => {
|
|
187
|
+
onSuccess: (res: any) => {
|
|
188
188
|
const amount = formatBNStr(res?.amount, data.paymentCurrency.decimal);
|
|
189
189
|
setRefundMaxAmount(amount);
|
|
190
190
|
},
|
|
@@ -200,7 +200,7 @@ export function PaymentIntentActionsInner({ data, variant = 'compact', onChange
|
|
|
200
200
|
}
|
|
201
201
|
try {
|
|
202
202
|
setState({ loading: true });
|
|
203
|
-
await api.put(`/api/payment-intents/${data.id}/refund`, refund).then((res) => res.data);
|
|
203
|
+
await api.put(`/api/payment-intents/${data.id}/refund`, refund).then((res: any) => res.data);
|
|
204
204
|
Toast.success(t('admin.paymentIntent.refundSuccess'));
|
|
205
205
|
onChange('refund');
|
|
206
206
|
runRefundAmountAsync();
|
|
@@ -31,7 +31,7 @@ const fetchData = (params: Record<string, any> = {}): Promise<{ list: TPaymentIn
|
|
|
31
31
|
}
|
|
32
32
|
search.set(key, String(v));
|
|
33
33
|
});
|
|
34
|
-
return api.get(`/api/payment-intents?${search.toString()}`).then((res) => res.data);
|
|
34
|
+
return api.get(`/api/payment-intents?${search.toString()}`).then((res: any) => res.data);
|
|
35
35
|
};
|
|
36
36
|
|
|
37
37
|
type SearchProps = {
|
|
@@ -28,7 +28,7 @@ export default function PaymentLinkActions({ data, variant = 'compact', onChange
|
|
|
28
28
|
const onUpdate = async (updates: TPaymentLinkExpanded) => {
|
|
29
29
|
try {
|
|
30
30
|
setState({ loading: true });
|
|
31
|
-
await api.put(`/api/payment-links/${data.id}`, updates).then((res) => res.data);
|
|
31
|
+
await api.put(`/api/payment-links/${data.id}`, updates).then((res: any) => res.data);
|
|
32
32
|
Toast.success(t('common.saved'));
|
|
33
33
|
onChange(state.action);
|
|
34
34
|
} catch (err) {
|
|
@@ -41,7 +41,7 @@ export default function PaymentLinkActions({ data, variant = 'compact', onChange
|
|
|
41
41
|
const onArchive = async () => {
|
|
42
42
|
try {
|
|
43
43
|
setState({ loading: true });
|
|
44
|
-
await api.put(`/api/payment-links/${data.id}/archive`).then((res) => res.data);
|
|
44
|
+
await api.put(`/api/payment-links/${data.id}/archive`).then((res: any) => res.data);
|
|
45
45
|
Toast.success(t('common.saved'));
|
|
46
46
|
onChange(state.action);
|
|
47
47
|
} catch (err) {
|
|
@@ -54,7 +54,7 @@ export default function PaymentLinkActions({ data, variant = 'compact', onChange
|
|
|
54
54
|
const onRemove = async () => {
|
|
55
55
|
try {
|
|
56
56
|
setState({ loading: true });
|
|
57
|
-
await api.delete(`/api/payment-links/${data.id}`).then((res) => res.data);
|
|
57
|
+
await api.delete(`/api/payment-links/${data.id}`).then((res: any) => res.data);
|
|
58
58
|
Toast.success(t('common.removed'));
|
|
59
59
|
onChange(state.action);
|
|
60
60
|
} catch (err) {
|
|
@@ -72,7 +72,7 @@ export default function PaymentLinkActions({ data, variant = 'compact', onChange
|
|
|
72
72
|
.put(`/api/payment-links/${data.id}`, {
|
|
73
73
|
allow_promotion_codes: !data.allow_promotion_codes,
|
|
74
74
|
})
|
|
75
|
-
.then((res) => res.data);
|
|
75
|
+
.then((res: any) => res.data);
|
|
76
76
|
Toast.success(t('common.saved'));
|
|
77
77
|
onChange(state.action);
|
|
78
78
|
} catch (err) {
|
|
@@ -34,7 +34,7 @@ export default function LineItem({ prefix, product, valid, onUpdate, onRemove }:
|
|
|
34
34
|
const onSave = async (updates: TProduct) => {
|
|
35
35
|
try {
|
|
36
36
|
setState({ loading: true });
|
|
37
|
-
await api.put(`/api/products/${product.id}`, updates).then((res) => res.data);
|
|
37
|
+
await api.put(`/api/products/${product.id}`, updates).then((res: any) => res.data);
|
|
38
38
|
Toast.success(t('common.saved'));
|
|
39
39
|
onUpdate();
|
|
40
40
|
} catch (err) {
|
|
@@ -34,7 +34,7 @@ const fetchData = (params: Record<string, any> = {}): Promise<{ list: TPayoutExp
|
|
|
34
34
|
}
|
|
35
35
|
search.set(key, String(v));
|
|
36
36
|
});
|
|
37
|
-
return api.get(`/api/payouts?${search.toString()}`).then((res) => res.data);
|
|
37
|
+
return api.get(`/api/payouts?${search.toString()}`).then((res: any) => res.data);
|
|
38
38
|
};
|
|
39
39
|
|
|
40
40
|
type SearchProps = {
|
|
@@ -31,7 +31,7 @@ const fetchData = (
|
|
|
31
31
|
}
|
|
32
32
|
search.set(key, String(v));
|
|
33
33
|
});
|
|
34
|
-
return api.get(`/api/payouts/mine?${search.toString()}`).then((res) => res.data);
|
|
34
|
+
return api.get(`/api/payouts/mine?${search.toString()}`).then((res: any) => res.data);
|
|
35
35
|
};
|
|
36
36
|
|
|
37
37
|
type SearchProps = {
|
|
@@ -16,7 +16,7 @@ type Props = {
|
|
|
16
16
|
};
|
|
17
17
|
|
|
18
18
|
const fetchData = (id: string): Promise<TPriceExpanded[]> => {
|
|
19
|
-
return api.get(`/api/prices/${id}/upsell`).then((res) => res.data);
|
|
19
|
+
return api.get(`/api/prices/${id}/upsell`).then((res: any) => res.data);
|
|
20
20
|
};
|
|
21
21
|
|
|
22
22
|
export default function UpsellSelect({ price, onSelect, onAdd }: Props) {
|
|
@@ -17,7 +17,7 @@ export function UpsellForm({ data, onChange }: { data: TPriceExpanded; onChange:
|
|
|
17
17
|
const onRemoveUpsell = async () => {
|
|
18
18
|
try {
|
|
19
19
|
setState({ loading: true });
|
|
20
|
-
await api.put(`/api/prices/${data.id}`, { upsell: { upsells_to_id: '' } }).then((res) => res.data);
|
|
20
|
+
await api.put(`/api/prices/${data.id}`, { upsell: { upsells_to_id: '' } }).then((res: any) => res.data);
|
|
21
21
|
setState({ loading: false });
|
|
22
22
|
onChange();
|
|
23
23
|
} catch (err) {
|
|
@@ -30,7 +30,7 @@ export function UpsellForm({ data, onChange }: { data: TPriceExpanded; onChange:
|
|
|
30
30
|
const onSelectUpsell = async (id: string) => {
|
|
31
31
|
try {
|
|
32
32
|
setState({ loading: true });
|
|
33
|
-
await api.put(`/api/prices/${data.id}`, { upsell: { upsells_to_id: id } }).then((res) => res.data);
|
|
33
|
+
await api.put(`/api/prices/${data.id}`, { upsell: { upsells_to_id: id } }).then((res: any) => res.data);
|
|
34
34
|
setState({ loading: false });
|
|
35
35
|
onChange();
|
|
36
36
|
} catch (err) {
|