payment-kit 1.23.9 → 1.23.10
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.
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
CreditGrant,
|
|
8
8
|
Customer,
|
|
9
9
|
Invoice,
|
|
10
|
+
Meter,
|
|
10
11
|
PaymentCurrency,
|
|
11
12
|
PaymentMethod,
|
|
12
13
|
Price,
|
|
@@ -51,6 +52,22 @@ export async function processAutoRecharge(job: AutoRechargeJobData) {
|
|
|
51
52
|
return;
|
|
52
53
|
}
|
|
53
54
|
|
|
55
|
+
// Check if the associated meter is inactive
|
|
56
|
+
if (currency.type === 'credit') {
|
|
57
|
+
// Find meter by currency_id (meter.currency_id -> PaymentCurrency) or by metadata.meter_id
|
|
58
|
+
const meter = await Meter.findOne({
|
|
59
|
+
where: { currency_id: currencyId },
|
|
60
|
+
});
|
|
61
|
+
if (meter && meter.status === 'inactive') {
|
|
62
|
+
logger.info('Meter is inactive, skipping auto recharge', {
|
|
63
|
+
customerId,
|
|
64
|
+
currencyId,
|
|
65
|
+
meterId: meter.id,
|
|
66
|
+
});
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
54
71
|
// 1. find auto recharge config
|
|
55
72
|
const config = (await AutoRechargeConfig.findOne({
|
|
56
73
|
where: {
|
|
@@ -302,6 +319,24 @@ export async function checkAndTriggerAutoRecharge(
|
|
|
302
319
|
currencyId,
|
|
303
320
|
currentBalance,
|
|
304
321
|
});
|
|
322
|
+
|
|
323
|
+
// Check if the associated meter is inactive
|
|
324
|
+
const currency = await PaymentCurrency.findByPk(currencyId);
|
|
325
|
+
if (currency?.type === 'credit') {
|
|
326
|
+
// Find meter by currency_id (meter.currency_id -> PaymentCurrency)
|
|
327
|
+
const meter = await Meter.findOne({
|
|
328
|
+
where: { currency_id: currencyId },
|
|
329
|
+
});
|
|
330
|
+
if (meter && meter.status === 'inactive') {
|
|
331
|
+
logger.info('Meter is inactive, skipping auto recharge check', {
|
|
332
|
+
customerId: customer.id,
|
|
333
|
+
currencyId,
|
|
334
|
+
meterId: meter.id,
|
|
335
|
+
});
|
|
336
|
+
return;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
305
340
|
const config = await AutoRechargeConfig.findOne({
|
|
306
341
|
where: {
|
|
307
342
|
customer_id: customer.id,
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
AutoRechargeConfig,
|
|
11
11
|
Customer,
|
|
12
12
|
EVMChainType,
|
|
13
|
+
Meter,
|
|
13
14
|
PaymentCurrency,
|
|
14
15
|
PaymentMethod,
|
|
15
16
|
Price,
|
|
@@ -339,6 +340,16 @@ router.post('/submit', async (req, res) => {
|
|
|
339
340
|
throw new CustomError(400, `Currency not found: ${value.currency_id}`);
|
|
340
341
|
}
|
|
341
342
|
|
|
343
|
+
// Check if the associated meter is active when enabling auto-recharge
|
|
344
|
+
if (configData.enabled && currency.type === 'credit') {
|
|
345
|
+
const meter = await Meter.findOne({
|
|
346
|
+
where: { currency_id: value.currency_id },
|
|
347
|
+
});
|
|
348
|
+
if (meter && meter.status === 'inactive') {
|
|
349
|
+
throw new CustomError(400, 'Cannot enable auto top-up: the associated meter is inactive');
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
342
353
|
if (currency.recharge_config?.base_price_id && currency.recharge_config?.base_price_id !== value.price_id) {
|
|
343
354
|
throw new CustomError(400, 'Price is not the base price');
|
|
344
355
|
}
|
|
@@ -2,7 +2,7 @@ import { Router } from 'express';
|
|
|
2
2
|
import Joi from 'joi';
|
|
3
3
|
import { BN, fromTokenToUnit } from '@ocap/util';
|
|
4
4
|
|
|
5
|
-
import { literal, OrderItem } from 'sequelize';
|
|
5
|
+
import { literal, OrderItem, fn, col, Op } from 'sequelize';
|
|
6
6
|
import pick from 'lodash/pick';
|
|
7
7
|
import { createListParamSchema, getOrder, getWhereFromKvQuery, MetadataSchema } from '../libs/api';
|
|
8
8
|
import logger from '../libs/logger';
|
|
@@ -165,6 +165,89 @@ router.get('/summary', authMine, async (req, res) => {
|
|
|
165
165
|
}
|
|
166
166
|
});
|
|
167
167
|
|
|
168
|
+
const holdersSchema = Joi.object({
|
|
169
|
+
currency_id: Joi.string().required(),
|
|
170
|
+
page: Joi.number().integer().min(1).default(1),
|
|
171
|
+
pageSize: Joi.number().integer().min(0).optional(), // 0 or undefined = return all
|
|
172
|
+
livemode: Joi.boolean().optional(),
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
// Get all holders (customers with balance) for a specific credit currency
|
|
176
|
+
router.get('/holders', auth, async (req, res) => {
|
|
177
|
+
try {
|
|
178
|
+
const { error, value } = holdersSchema.validate(req.query, { stripUnknown: true });
|
|
179
|
+
if (error) {
|
|
180
|
+
return res.status(400).json({ error: error.message });
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const { currency_id: currencyId, page, pageSize, livemode } = value;
|
|
184
|
+
|
|
185
|
+
const currency = await PaymentCurrency.findByPk(currencyId);
|
|
186
|
+
if (!currency) {
|
|
187
|
+
return res.status(404).json({ error: `PaymentCurrency ${currencyId} not found` });
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (currency.type !== 'credit') {
|
|
191
|
+
return res.status(400).json({ error: 'Currency must be of type credit' });
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// Build where clause for credit grants
|
|
195
|
+
const grantWhere: any = {
|
|
196
|
+
currency_id: currencyId,
|
|
197
|
+
status: { [Op.in]: ['granted', 'pending'] }, // Only active grants
|
|
198
|
+
};
|
|
199
|
+
if (typeof livemode === 'boolean') {
|
|
200
|
+
grantWhere.livemode = livemode;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// Use database aggregation - only customer_id, no JOIN needed
|
|
204
|
+
const aggregatedData = (await CreditGrant.findAll({
|
|
205
|
+
where: grantWhere,
|
|
206
|
+
attributes: [
|
|
207
|
+
'customer_id',
|
|
208
|
+
[fn('COUNT', col('id')), 'grantCount'],
|
|
209
|
+
[fn('SUM', literal('CAST(remaining_amount AS DECIMAL(40,0))')), 'totalBalance'],
|
|
210
|
+
],
|
|
211
|
+
group: ['customer_id'], // Only group by customer_id - much faster!
|
|
212
|
+
order: [[literal('totalBalance'), 'DESC']],
|
|
213
|
+
raw: true,
|
|
214
|
+
})) as any[];
|
|
215
|
+
|
|
216
|
+
const totalCount = aggregatedData.length;
|
|
217
|
+
|
|
218
|
+
// Paginate (pageSize = 0 or undefined means return all)
|
|
219
|
+
const shouldPaginate = pageSize && pageSize > 0;
|
|
220
|
+
const paginatedData = shouldPaginate
|
|
221
|
+
? aggregatedData.slice((page - 1) * pageSize, page * pageSize)
|
|
222
|
+
: aggregatedData;
|
|
223
|
+
|
|
224
|
+
const holders = paginatedData.map((item) => ({
|
|
225
|
+
customer_id: item.customer_id,
|
|
226
|
+
balance: (item.totalBalance || '0').toString(),
|
|
227
|
+
grantCount: parseInt(item.grantCount || '0', 10),
|
|
228
|
+
}));
|
|
229
|
+
|
|
230
|
+
return res.json({
|
|
231
|
+
holders,
|
|
232
|
+
currency: {
|
|
233
|
+
id: currency.id,
|
|
234
|
+
name: currency.name,
|
|
235
|
+
symbol: currency.symbol,
|
|
236
|
+
decimal: currency.decimal,
|
|
237
|
+
},
|
|
238
|
+
paging: {
|
|
239
|
+
page: shouldPaginate ? page : 1,
|
|
240
|
+
pageSize: shouldPaginate ? pageSize : totalCount,
|
|
241
|
+
total: totalCount,
|
|
242
|
+
totalPages: shouldPaginate ? Math.ceil(totalCount / pageSize) : 1,
|
|
243
|
+
},
|
|
244
|
+
});
|
|
245
|
+
} catch (err: any) {
|
|
246
|
+
logger.error('Error getting credit holders', { error: err.message });
|
|
247
|
+
return res.status(400).json({ error: err.message });
|
|
248
|
+
}
|
|
249
|
+
});
|
|
250
|
+
|
|
168
251
|
const checkAutoRechargeSchema = Joi.object({
|
|
169
252
|
customer_id: Joi.string().required(),
|
|
170
253
|
currency_id: Joi.string().required(),
|
package/blocklet.yml
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "payment-kit",
|
|
3
|
-
"version": "1.23.
|
|
3
|
+
"version": "1.23.10",
|
|
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.23.
|
|
63
|
-
"@blocklet/payment-react": "1.23.
|
|
64
|
-
"@blocklet/payment-vendor": "1.23.
|
|
62
|
+
"@blocklet/payment-broker-client": "1.23.10",
|
|
63
|
+
"@blocklet/payment-react": "1.23.10",
|
|
64
|
+
"@blocklet/payment-vendor": "1.23.10",
|
|
65
65
|
"@blocklet/sdk": "^1.17.8-beta-20260104-120132-cb5b1914",
|
|
66
66
|
"@blocklet/ui-react": "^3.3.10",
|
|
67
67
|
"@blocklet/uploader": "^0.3.19",
|
|
@@ -131,7 +131,7 @@
|
|
|
131
131
|
"devDependencies": {
|
|
132
132
|
"@abtnode/types": "^1.17.8-beta-20260104-120132-cb5b1914",
|
|
133
133
|
"@arcblock/eslint-config-ts": "^0.3.3",
|
|
134
|
-
"@blocklet/payment-types": "1.23.
|
|
134
|
+
"@blocklet/payment-types": "1.23.10",
|
|
135
135
|
"@types/cookie-parser": "^1.4.9",
|
|
136
136
|
"@types/cors": "^2.8.19",
|
|
137
137
|
"@types/debug": "^4.1.12",
|
|
@@ -178,5 +178,5 @@
|
|
|
178
178
|
"parser": "typescript"
|
|
179
179
|
}
|
|
180
180
|
},
|
|
181
|
-
"gitHead": "
|
|
181
|
+
"gitHead": "9d058650e81ae43ffafb3e1253b50b6245d510ac"
|
|
182
182
|
}
|