payment-kit 1.18.20 → 1.18.22
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/integrations/blocklet/user.ts +1 -0
- package/api/src/libs/api.ts +175 -19
- package/api/src/queues/payment.ts +2 -2
- package/api/src/routes/checkout-sessions.ts +36 -4
- package/api/src/routes/connect/shared.ts +1 -0
- package/api/src/routes/customers.ts +5 -5
- package/api/src/routes/donations.ts +2 -2
- package/api/src/routes/events.ts +2 -2
- package/api/src/routes/invoices.ts +4 -4
- package/api/src/routes/payment-intents.ts +3 -2
- package/api/src/routes/payment-links.ts +2 -2
- package/api/src/routes/payment-stats.ts +2 -2
- package/api/src/routes/payouts.ts +3 -3
- package/api/src/routes/prices.ts +3 -3
- package/api/src/routes/pricing-table.ts +2 -2
- package/api/src/routes/products.ts +3 -3
- package/api/src/routes/refunds.ts +3 -3
- package/api/src/routes/settings.ts +5 -5
- package/api/src/routes/subscription-items.ts +2 -2
- package/api/src/routes/subscriptions.ts +8 -30
- package/api/src/routes/usage-records.ts +2 -2
- package/api/src/routes/webhook-attempts.ts +2 -2
- package/api/src/routes/webhook-endpoints.ts +2 -2
- package/api/src/store/models/customer.ts +22 -0
- package/api/src/store/models/types.ts +5 -0
- package/api/tests/libs/api.spec.ts +298 -1
- package/blocklet.yml +1 -1
- package/package.json +8 -8
- package/src/components/layout/user.tsx +10 -0
- package/src/libs/util.ts +1 -18
- package/src/pages/admin/payments/payouts/detail.tsx +4 -6
- package/src/pages/customer/index.tsx +4 -2
- package/src/pages/customer/payout/detail.tsx +4 -6
package/api/src/libs/api.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { BN, fromTokenToUnit } from '@ocap/util';
|
|
|
2
2
|
import Joi from 'joi';
|
|
3
3
|
import { Op } from 'sequelize';
|
|
4
4
|
import SqlWhereParser from 'sql-where-parser';
|
|
5
|
+
import type { OrderDirection, OrderInput, OrderItem } from '../store/models';
|
|
5
6
|
|
|
6
7
|
const parser = new SqlWhereParser();
|
|
7
8
|
|
|
@@ -109,36 +110,191 @@ export const getWhereFromKvQuery = (query?: string) => {
|
|
|
109
110
|
return out;
|
|
110
111
|
};
|
|
111
112
|
|
|
113
|
+
export function normalizeOrder(
|
|
114
|
+
order: OrderInput | undefined,
|
|
115
|
+
defaultOrder: OrderItem[] = [['created_at', 'DESC']]
|
|
116
|
+
): OrderItem[] {
|
|
117
|
+
if (!order) return defaultOrder;
|
|
118
|
+
|
|
119
|
+
let normalizedOrder: OrderItem[];
|
|
120
|
+
|
|
121
|
+
if (typeof order === 'string') {
|
|
122
|
+
const [field, direction] = order.split(':');
|
|
123
|
+
normalizedOrder = [[field || '', (direction?.toUpperCase() as OrderDirection) || 'ASC']];
|
|
124
|
+
} else if (Array.isArray(order)) {
|
|
125
|
+
if (order.length === 0) return defaultOrder;
|
|
126
|
+
|
|
127
|
+
if (Array.isArray(order[0])) {
|
|
128
|
+
normalizedOrder = order.map(([field, direction]) => [
|
|
129
|
+
field || '',
|
|
130
|
+
(direction?.toUpperCase() as OrderDirection) || 'ASC',
|
|
131
|
+
]);
|
|
132
|
+
} else {
|
|
133
|
+
normalizedOrder = order.map((item) => {
|
|
134
|
+
const [field, direction] = (item as string).split(':');
|
|
135
|
+
return [field || '', (direction?.toUpperCase() as OrderDirection) || 'ASC'];
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
} else {
|
|
139
|
+
return defaultOrder;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// merge default order with normalized order
|
|
143
|
+
const orderFields = new Set(normalizedOrder.map(([field]) => field));
|
|
144
|
+
const remainingDefaultOrders = defaultOrder.filter(([field]) => !orderFields.has(field));
|
|
145
|
+
|
|
146
|
+
return [...normalizedOrder, ...remainingDefaultOrders];
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export function getOrder(query: Record<string, any>, defaultOrder?: OrderItem[]): OrderItem[] {
|
|
150
|
+
if (query.order) {
|
|
151
|
+
return normalizeOrder(query.order, defaultOrder);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
if (query.o) {
|
|
155
|
+
const direction = query.o.toUpperCase() as OrderDirection;
|
|
156
|
+
return defaultOrder?.map(([field]) => [field, direction]) || [['created_at', direction]];
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
return defaultOrder || [['created_at', 'DESC']];
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const fieldRegex = /^[\w.]+$/i;
|
|
163
|
+
const directionRegex = /(asc|desc)$/i;
|
|
164
|
+
|
|
165
|
+
const ORDER_ERROR_MESSAGES = {
|
|
166
|
+
FIELD_PATTERN: 'Field name can only contain letters, numbers, dots and underscores',
|
|
167
|
+
DIRECTION_PATTERN: 'Direction must be either "asc" or "desc"',
|
|
168
|
+
SEPARATOR: 'Must use ":" to separate field and direction',
|
|
169
|
+
TUPLE_LENGTH: 'Each tuple must contain exactly 2 elements',
|
|
170
|
+
ARRAY_TYPE: 'Each item must be an array',
|
|
171
|
+
INVALID_FORMAT:
|
|
172
|
+
'Invalid order format. Must be one of:\n' +
|
|
173
|
+
'- Single field: "field:direction"\n' +
|
|
174
|
+
'- Multiple fields: ["field1:asc", "field2:desc"]\n' +
|
|
175
|
+
'- Tuple format: [["field1", "ASC"], ["field2", "DESC"]]\n' +
|
|
176
|
+
'where field contains only letters, numbers, dots and underscores, ' +
|
|
177
|
+
'and direction is either "asc" or "desc" (case insensitive)',
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
const validateField = (field: any): boolean => typeof field === 'string' && fieldRegex.test(field);
|
|
181
|
+
|
|
182
|
+
const validateDirection = (direction: any): boolean => typeof direction === 'string' && directionRegex.test(direction);
|
|
183
|
+
|
|
184
|
+
// Function to validate the order parameter
|
|
185
|
+
export const validateOrderInput = (value: any, helpers: any) => {
|
|
186
|
+
// If it does not exist or is null, skip validation
|
|
187
|
+
if (value == null) return value;
|
|
188
|
+
|
|
189
|
+
// String format: "field:direction"
|
|
190
|
+
if (typeof value === 'string') {
|
|
191
|
+
const parts = value.split(':');
|
|
192
|
+
|
|
193
|
+
if (parts.length !== 2) {
|
|
194
|
+
return helpers.message(ORDER_ERROR_MESSAGES.SEPARATOR);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const [field, direction] = parts;
|
|
198
|
+
|
|
199
|
+
if (!validateField(field)) {
|
|
200
|
+
return helpers.message(ORDER_ERROR_MESSAGES.FIELD_PATTERN);
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (!validateDirection(direction)) {
|
|
204
|
+
return helpers.message(ORDER_ERROR_MESSAGES.DIRECTION_PATTERN);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return value;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Array format
|
|
211
|
+
if (Array.isArray(value)) {
|
|
212
|
+
// Empty array, return directly
|
|
213
|
+
if (value.length === 0) return value;
|
|
214
|
+
|
|
215
|
+
// String array format
|
|
216
|
+
if (typeof value[0] === 'string') {
|
|
217
|
+
const invalidItem = value.find((item) => typeof item !== 'string');
|
|
218
|
+
if (invalidItem !== undefined) {
|
|
219
|
+
return helpers.message(ORDER_ERROR_MESSAGES.INVALID_FORMAT);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
for (const item of value) {
|
|
223
|
+
const parts = item.split(':');
|
|
224
|
+
|
|
225
|
+
if (parts.length !== 2) {
|
|
226
|
+
return helpers.message(ORDER_ERROR_MESSAGES.SEPARATOR);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
const [field, direction] = parts;
|
|
230
|
+
|
|
231
|
+
if (!validateField(field)) {
|
|
232
|
+
return helpers.message(ORDER_ERROR_MESSAGES.FIELD_PATTERN);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (!validateDirection(direction)) {
|
|
236
|
+
return helpers.message(ORDER_ERROR_MESSAGES.DIRECTION_PATTERN);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
return value;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// Multiple tuples format
|
|
244
|
+
if (Array.isArray(value[0])) {
|
|
245
|
+
for (const tuple of value) {
|
|
246
|
+
if (!Array.isArray(tuple)) {
|
|
247
|
+
return helpers.message(ORDER_ERROR_MESSAGES.ARRAY_TYPE);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (tuple.length !== 2) {
|
|
251
|
+
return helpers.message(ORDER_ERROR_MESSAGES.TUPLE_LENGTH);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
const [field, direction] = tuple;
|
|
255
|
+
|
|
256
|
+
if (!validateField(field)) {
|
|
257
|
+
return helpers.message(ORDER_ERROR_MESSAGES.FIELD_PATTERN);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
if (!validateDirection(direction)) {
|
|
261
|
+
return helpers.message(ORDER_ERROR_MESSAGES.DIRECTION_PATTERN);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
return value;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
return helpers.message(ORDER_ERROR_MESSAGES.INVALID_FORMAT);
|
|
269
|
+
};
|
|
270
|
+
|
|
112
271
|
export function createListParamSchema<T>(schema: any, pageSize: number = 20) {
|
|
113
|
-
return Joi.object<
|
|
114
|
-
|
|
272
|
+
return Joi.object<
|
|
273
|
+
T & {
|
|
274
|
+
page: number;
|
|
275
|
+
pageSize: number;
|
|
276
|
+
livemode?: boolean;
|
|
277
|
+
q?: string;
|
|
278
|
+
o?: string;
|
|
279
|
+
order?: OrderInput;
|
|
280
|
+
}
|
|
281
|
+
>({
|
|
115
282
|
page: Joi.number()
|
|
116
283
|
.integer()
|
|
117
284
|
.default(1)
|
|
118
|
-
.custom((value) =>
|
|
119
|
-
if (value < 1) {
|
|
120
|
-
return 1;
|
|
121
|
-
}
|
|
122
|
-
return value;
|
|
123
|
-
}, 'page should be valid'),
|
|
124
|
-
|
|
285
|
+
.custom((value) => (value < 1 ? 1 : value), 'page should be valid'),
|
|
125
286
|
pageSize: Joi.number()
|
|
126
287
|
.integer()
|
|
127
288
|
.default(pageSize)
|
|
128
289
|
.custom((value) => {
|
|
129
|
-
if (value > 100)
|
|
130
|
-
|
|
131
|
-
}
|
|
132
|
-
if (value < 1) {
|
|
133
|
-
return 1;
|
|
134
|
-
}
|
|
290
|
+
if (value > 100) return 100;
|
|
291
|
+
if (value < 1) return 1;
|
|
135
292
|
return value;
|
|
136
293
|
}, 'pageSize should be valid'),
|
|
137
|
-
|
|
138
294
|
livemode: Joi.boolean().empty(''),
|
|
139
|
-
q: Joi.string().empty(''),
|
|
140
|
-
o: Joi.string().empty(''),
|
|
141
|
-
|
|
295
|
+
q: Joi.string().empty(''),
|
|
296
|
+
o: Joi.string().valid('asc', 'desc').insensitive().empty(''),
|
|
297
|
+
order: Joi.any().custom(validateOrderInput).optional(),
|
|
142
298
|
...schema,
|
|
143
299
|
});
|
|
144
300
|
}
|
|
@@ -125,8 +125,8 @@ export const handlePaymentSucceed = async (
|
|
|
125
125
|
did: user.did,
|
|
126
126
|
name: user.fullName,
|
|
127
127
|
email: user.email,
|
|
128
|
-
phone:
|
|
129
|
-
address:
|
|
128
|
+
phone: user.phone,
|
|
129
|
+
address: Customer.formatAddressFromUser(user),
|
|
130
130
|
description: user.remark,
|
|
131
131
|
metadata: {},
|
|
132
132
|
balance: '0',
|
|
@@ -76,6 +76,7 @@ import { ensureInvoiceForCheckout } from './connect/shared';
|
|
|
76
76
|
import { isCreditSufficientForPayment, isDelegationSufficientForPayment } from '../libs/payment';
|
|
77
77
|
import { handleStripeSubscriptionSucceed } from '../integrations/stripe/handlers/subscription';
|
|
78
78
|
import { CHARGE_SUPPORTED_CHAIN_TYPES } from '../libs/constants';
|
|
79
|
+
import { blocklet } from '../libs/auth';
|
|
79
80
|
|
|
80
81
|
const router = Router();
|
|
81
82
|
|
|
@@ -838,14 +839,15 @@ router.put('/:id/submit', user, ensureCheckoutSessionOpen, async (req, res) => {
|
|
|
838
839
|
|
|
839
840
|
let customer = await Customer.findOne({ where: { did: req.user.did } });
|
|
840
841
|
if (!customer) {
|
|
842
|
+
const { user: userInfo } = await blocklet.getUser(req.user.did);
|
|
841
843
|
customer = await Customer.create({
|
|
842
844
|
livemode: !!checkoutSession.livemode,
|
|
843
845
|
did: req.user.did,
|
|
844
846
|
name: req.body.customer_name,
|
|
845
|
-
email: req.body.customer_email,
|
|
846
|
-
phone: req.body.customer_phone,
|
|
847
|
-
address: req.body.billing_address,
|
|
848
|
-
description: '',
|
|
847
|
+
email: req.body.customer_email || userInfo?.email || '',
|
|
848
|
+
phone: req.body.customer_phone || userInfo?.phone || '',
|
|
849
|
+
address: req.body.billing_address || Customer.formatAddressFromUser(userInfo),
|
|
850
|
+
description: userInfo?.remark || '',
|
|
849
851
|
metadata: {},
|
|
850
852
|
balance: '0',
|
|
851
853
|
next_invoice_sequence: 1,
|
|
@@ -853,6 +855,20 @@ router.put('/:id/submit', user, ensureCheckoutSessionOpen, async (req, res) => {
|
|
|
853
855
|
invoice_prefix: Customer.getInvoicePrefix(),
|
|
854
856
|
});
|
|
855
857
|
logger.info('customer created on checkout session submit', { did: req.user.did, id: customer.id });
|
|
858
|
+
try {
|
|
859
|
+
await blocklet.updateUserAddress({
|
|
860
|
+
did: customer.did,
|
|
861
|
+
address: Customer.formatAddressFromCustomer(customer),
|
|
862
|
+
});
|
|
863
|
+
logger.info('updateUserAddress success', {
|
|
864
|
+
did: customer.did,
|
|
865
|
+
});
|
|
866
|
+
} catch (err) {
|
|
867
|
+
logger.error('updateUserAddress failed', {
|
|
868
|
+
error: err,
|
|
869
|
+
customerId: customer.id,
|
|
870
|
+
});
|
|
871
|
+
}
|
|
856
872
|
} else {
|
|
857
873
|
const updates: Record<string, string> = {};
|
|
858
874
|
if (checkoutSession.customer_update?.name) {
|
|
@@ -868,6 +884,22 @@ router.put('/:id/submit', user, ensureCheckoutSessionOpen, async (req, res) => {
|
|
|
868
884
|
}
|
|
869
885
|
|
|
870
886
|
await customer.update(updates);
|
|
887
|
+
try {
|
|
888
|
+
await blocklet.updateUserAddress({
|
|
889
|
+
did: customer.did,
|
|
890
|
+
address: Customer.formatAddressFromCustomer(customer),
|
|
891
|
+
// @ts-ignore
|
|
892
|
+
phone: customer.phone,
|
|
893
|
+
});
|
|
894
|
+
logger.info('updateUserAddress success', {
|
|
895
|
+
did: customer.did,
|
|
896
|
+
});
|
|
897
|
+
} catch (err) {
|
|
898
|
+
logger.error('updateUserAddress failed', {
|
|
899
|
+
error: err,
|
|
900
|
+
customerId: customer.id,
|
|
901
|
+
});
|
|
902
|
+
}
|
|
871
903
|
}
|
|
872
904
|
|
|
873
905
|
// check if customer can make new purchase
|
|
@@ -117,6 +117,7 @@ export async function ensurePaymentIntent(checkoutSessionId: string, userDid?: s
|
|
|
117
117
|
metadata: { fromDonation: true },
|
|
118
118
|
livemode: checkoutSession.livemode,
|
|
119
119
|
phone: user.phone,
|
|
120
|
+
address: Customer.formatAddressFromUser(user),
|
|
120
121
|
delinquent: false,
|
|
121
122
|
balance: '0',
|
|
122
123
|
next_invoice_sequence: 1,
|
|
@@ -7,7 +7,7 @@ import isEmail from 'validator/es/lib/isEmail';
|
|
|
7
7
|
import { Op } from 'sequelize';
|
|
8
8
|
import { BN } from '@ocap/util';
|
|
9
9
|
import { getStakeSummaryByDid, getTokenSummaryByDid, getTokenByAddress } from '../integrations/arcblock/stake';
|
|
10
|
-
import { createListParamSchema, getWhereFromKvQuery, getWhereFromQuery, MetadataSchema } from '../libs/api';
|
|
10
|
+
import { createListParamSchema, getOrder, getWhereFromKvQuery, getWhereFromQuery, MetadataSchema } from '../libs/api';
|
|
11
11
|
import { authenticate } from '../libs/security';
|
|
12
12
|
import { formatMetadata } from '../libs/util';
|
|
13
13
|
import { Customer } from '../store/models/customer';
|
|
@@ -52,7 +52,7 @@ router.get('/', auth, async (req, res) => {
|
|
|
52
52
|
try {
|
|
53
53
|
const { rows: list, count } = await Customer.findAndCountAll({
|
|
54
54
|
where,
|
|
55
|
-
order: [['created_at', query.o === 'asc' ? 'ASC' : 'DESC']],
|
|
55
|
+
order: getOrder(query, [['created_at', query.o === 'asc' ? 'ASC' : 'DESC']]),
|
|
56
56
|
offset: (page - 1) * pageSize,
|
|
57
57
|
limit: pageSize,
|
|
58
58
|
include: [],
|
|
@@ -83,7 +83,7 @@ router.get('/search', auth, async (req, res) => {
|
|
|
83
83
|
}
|
|
84
84
|
const { rows: list, count } = await Customer.findAndCountAll({
|
|
85
85
|
where,
|
|
86
|
-
order: [['created_at', o === 'asc' ? 'ASC' : 'DESC']],
|
|
86
|
+
order: getOrder(req.query, [['created_at', o === 'asc' ? 'ASC' : 'DESC']]),
|
|
87
87
|
offset: (page - 1) * pageSize,
|
|
88
88
|
limit: pageSize,
|
|
89
89
|
include: [],
|
|
@@ -115,7 +115,7 @@ router.get('/me', sessionMiddleware(), async (req, res) => {
|
|
|
115
115
|
name: user.fullName,
|
|
116
116
|
email: user.email,
|
|
117
117
|
phone: user.phone,
|
|
118
|
-
address:
|
|
118
|
+
address: Customer.formatAddressFromUser(user),
|
|
119
119
|
description: user.remark,
|
|
120
120
|
metadata: {},
|
|
121
121
|
balance: '0',
|
|
@@ -169,7 +169,7 @@ router.get('/me', sessionMiddleware(), async (req, res) => {
|
|
|
169
169
|
});
|
|
170
170
|
|
|
171
171
|
// get overdue invoices
|
|
172
|
-
router.get('/:id/overdue/invoices',
|
|
172
|
+
router.get('/:id/overdue/invoices', sessionMiddleware(), async (req, res) => {
|
|
173
173
|
if (!req.user) {
|
|
174
174
|
return res.status(403).json({ error: 'Unauthorized' });
|
|
175
175
|
}
|
|
@@ -2,7 +2,7 @@ import { Joi } from '@arcblock/validator';
|
|
|
2
2
|
import { Router } from 'express';
|
|
3
3
|
|
|
4
4
|
import { BN } from '@ocap/util';
|
|
5
|
-
import { createListParamSchema } from '../libs/api';
|
|
5
|
+
import { createListParamSchema, getOrder } from '../libs/api';
|
|
6
6
|
import logger from '../libs/logger';
|
|
7
7
|
import { CheckoutSession } from '../store/models/checkout-session';
|
|
8
8
|
import { Customer } from '../store/models/customer';
|
|
@@ -143,7 +143,7 @@ router.get('/', async (req, res) => {
|
|
|
143
143
|
'created_at',
|
|
144
144
|
'updated_at',
|
|
145
145
|
],
|
|
146
|
-
order: [['created_at', 'DESC']],
|
|
146
|
+
order: getOrder(req.query, [['created_at', 'DESC']]),
|
|
147
147
|
offset: (page - 1) * pageSize,
|
|
148
148
|
include: [{ model: Customer, as: 'customer', attributes: ['id', 'did', 'name', 'metadata'] }],
|
|
149
149
|
limit: pageSize,
|
package/api/src/routes/events.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { Router } from 'express';
|
|
|
2
2
|
import Joi from 'joi';
|
|
3
3
|
import type { WhereOptions } from 'sequelize';
|
|
4
4
|
|
|
5
|
-
import { createListParamSchema } from '../libs/api';
|
|
5
|
+
import { createListParamSchema, getOrder } from '../libs/api';
|
|
6
6
|
import { authenticate } from '../libs/security';
|
|
7
7
|
import { Event } from '../store/models/event';
|
|
8
8
|
import { blocklet } from '../libs/auth';
|
|
@@ -42,7 +42,7 @@ router.get('/', auth, async (req, res) => {
|
|
|
42
42
|
const { rows: list, count } = await Event.findAndCountAll({
|
|
43
43
|
where,
|
|
44
44
|
attributes: { exclude: ['data', 'request'] },
|
|
45
|
-
order: [['created_at', 'DESC']],
|
|
45
|
+
order: getOrder(req.query, [['created_at', 'DESC']]),
|
|
46
46
|
offset: (page - 1) * pageSize,
|
|
47
47
|
limit: pageSize,
|
|
48
48
|
include: [],
|
|
@@ -8,7 +8,7 @@ import { Op } from 'sequelize';
|
|
|
8
8
|
import { BN } from '@ocap/util';
|
|
9
9
|
import { syncStripeInvoice } from '../integrations/stripe/handlers/invoice';
|
|
10
10
|
import { syncStripePayment } from '../integrations/stripe/handlers/payment-intent';
|
|
11
|
-
import { createListParamSchema, getWhereFromKvQuery, MetadataSchema } from '../libs/api';
|
|
11
|
+
import { createListParamSchema, getOrder, getWhereFromKvQuery, MetadataSchema } from '../libs/api';
|
|
12
12
|
import { authenticate } from '../libs/security';
|
|
13
13
|
import { expandLineItems } from '../libs/session';
|
|
14
14
|
import { formatMetadata, getBlockletJson, getUserOrAppInfo } from '../libs/util';
|
|
@@ -136,7 +136,7 @@ router.get('/', authMine, async (req, res) => {
|
|
|
136
136
|
try {
|
|
137
137
|
const { rows: list, count } = await Invoice.findAndCountAll({
|
|
138
138
|
where,
|
|
139
|
-
order: [['created_at', query.o === 'asc' ? 'ASC' : 'DESC']],
|
|
139
|
+
order: getOrder(req.query, [['created_at', query.o === 'asc' ? 'ASC' : 'DESC']]),
|
|
140
140
|
offset: (page - 1) * pageSize,
|
|
141
141
|
limit: pageSize,
|
|
142
142
|
include: [
|
|
@@ -212,7 +212,7 @@ router.get('/recharge', authMine, async (req, res) => {
|
|
|
212
212
|
},
|
|
213
213
|
offset: (page - 1) * pageSize,
|
|
214
214
|
limit: pageSize,
|
|
215
|
-
order: [['created_at', 'DESC']],
|
|
215
|
+
order: getOrder(req.query, [['created_at', 'DESC']]),
|
|
216
216
|
include: [
|
|
217
217
|
{ model: PaymentCurrency, as: 'paymentCurrency' },
|
|
218
218
|
{ model: PaymentMethod, as: 'paymentMethod' },
|
|
@@ -240,7 +240,7 @@ router.get('/search', authMine, async (req, res) => {
|
|
|
240
240
|
|
|
241
241
|
const { rows: list, count } = await Invoice.findAndCountAll({
|
|
242
242
|
where,
|
|
243
|
-
order: [['created_at', o === 'asc' ? 'ASC' : 'DESC']],
|
|
243
|
+
order: getOrder(req.query, [['created_at', o === 'asc' ? 'ASC' : 'DESC']]),
|
|
244
244
|
offset: (page - 1) * pageSize,
|
|
245
245
|
limit: pageSize,
|
|
246
246
|
distinct: true,
|
|
@@ -9,6 +9,7 @@ import { syncStripePayment } from '../integrations/stripe/handlers/payment-inten
|
|
|
9
9
|
import {
|
|
10
10
|
BNPositiveValidator,
|
|
11
11
|
createListParamSchema,
|
|
12
|
+
getOrder,
|
|
12
13
|
getWhereFromKvQuery,
|
|
13
14
|
getWhereFromQuery,
|
|
14
15
|
MetadataSchema,
|
|
@@ -111,7 +112,7 @@ router.get('/', authMine, async (req, res) => {
|
|
|
111
112
|
try {
|
|
112
113
|
const { rows: list, count } = await PaymentIntent.findAndCountAll({
|
|
113
114
|
where,
|
|
114
|
-
order: [['created_at', query.o === 'asc' ? 'ASC' : 'DESC']],
|
|
115
|
+
order: getOrder(req.query, [['created_at', query.o === 'asc' ? 'ASC' : 'DESC']]),
|
|
115
116
|
offset: (page - 1) * pageSize,
|
|
116
117
|
limit: pageSize,
|
|
117
118
|
include: [
|
|
@@ -147,7 +148,7 @@ router.get('/search', authMine, async (req, res) => {
|
|
|
147
148
|
|
|
148
149
|
const { rows: list, count } = await PaymentIntent.findAndCountAll({
|
|
149
150
|
where,
|
|
150
|
-
order: [['created_at', o === 'asc' ? 'ASC' : 'DESC']],
|
|
151
|
+
order: getOrder(req.query, [['created_at', o === 'asc' ? 'ASC' : 'DESC']]),
|
|
151
152
|
offset: (page - 1) * pageSize,
|
|
152
153
|
limit: pageSize,
|
|
153
154
|
include: [
|
|
@@ -4,7 +4,7 @@ import pick from 'lodash/pick';
|
|
|
4
4
|
import { Op } from 'sequelize';
|
|
5
5
|
import type { WhereOptions } from 'sequelize';
|
|
6
6
|
|
|
7
|
-
import { createListParamSchema, MetadataSchema } from '../libs/api';
|
|
7
|
+
import { createListParamSchema, getOrder, MetadataSchema } from '../libs/api';
|
|
8
8
|
import logger from '../libs/logger';
|
|
9
9
|
import { authenticate } from '../libs/security';
|
|
10
10
|
import { isLineItemAligned } from '../libs/session';
|
|
@@ -239,7 +239,7 @@ router.get('/', auth, async (req, res) => {
|
|
|
239
239
|
try {
|
|
240
240
|
const { rows: list, count } = await PaymentLink.findAndCountAll({
|
|
241
241
|
where,
|
|
242
|
-
order: [['created_at', 'DESC']],
|
|
242
|
+
order: getOrder(req.query, [['created_at', 'DESC']]),
|
|
243
243
|
offset: (page - 1) * pageSize,
|
|
244
244
|
limit: pageSize,
|
|
245
245
|
include: [],
|
|
@@ -5,7 +5,7 @@ import { joinURL } from 'ufo';
|
|
|
5
5
|
|
|
6
6
|
import { getPaymentStat } from '../crons/payment-stat';
|
|
7
7
|
import { getTokenSummaryByDid } from '../integrations/arcblock/stake';
|
|
8
|
-
import { createListParamSchema } from '../libs/api';
|
|
8
|
+
import { createListParamSchema, getOrder } from '../libs/api';
|
|
9
9
|
import { ethWallet, wallet } from '../libs/auth';
|
|
10
10
|
import dayjs from '../libs/dayjs';
|
|
11
11
|
import { authenticate } from '../libs/security';
|
|
@@ -56,7 +56,7 @@ router.get('/', auth, async (req, res) => {
|
|
|
56
56
|
try {
|
|
57
57
|
const { rows: list, count } = await PaymentStat.findAndCountAll({
|
|
58
58
|
where,
|
|
59
|
-
order: [['created_at', 'ASC']],
|
|
59
|
+
order: getOrder(req.query, [['created_at', 'ASC']]),
|
|
60
60
|
include: [],
|
|
61
61
|
});
|
|
62
62
|
|
|
@@ -4,7 +4,7 @@ import Joi from 'joi';
|
|
|
4
4
|
import pick from 'lodash/pick';
|
|
5
5
|
|
|
6
6
|
import sessionMiddleware from '@blocklet/sdk/lib/middlewares/session';
|
|
7
|
-
import { createListParamSchema, getWhereFromKvQuery, MetadataSchema } from '../libs/api';
|
|
7
|
+
import { createListParamSchema, getOrder, getWhereFromKvQuery, MetadataSchema } from '../libs/api';
|
|
8
8
|
import { authenticate } from '../libs/security';
|
|
9
9
|
import { formatMetadata } from '../libs/util';
|
|
10
10
|
import { Customer } from '../store/models/customer';
|
|
@@ -90,7 +90,7 @@ router.get('/', authMine, async (req, res) => {
|
|
|
90
90
|
try {
|
|
91
91
|
const { rows: list, count } = await Payout.findAndCountAll({
|
|
92
92
|
where,
|
|
93
|
-
order: [['created_at', query.o === 'asc' ? 'ASC' : 'DESC']],
|
|
93
|
+
order: getOrder(req.query, [['created_at', query.o === 'asc' ? 'ASC' : 'DESC']]),
|
|
94
94
|
offset: (page - 1) * pageSize,
|
|
95
95
|
limit: pageSize,
|
|
96
96
|
include: [
|
|
@@ -146,7 +146,7 @@ router.get('/mine', sessionMiddleware(), async (req, res) => {
|
|
|
146
146
|
|
|
147
147
|
const { rows: list, count } = await Payout.findAndCountAll({
|
|
148
148
|
where,
|
|
149
|
-
order: [['created_at', 'DESC']],
|
|
149
|
+
order: getOrder(req.query, [['created_at', 'DESC']]),
|
|
150
150
|
offset: (page - 1) * pageSize,
|
|
151
151
|
limit: pageSize,
|
|
152
152
|
include: [
|
package/api/src/routes/prices.ts
CHANGED
|
@@ -4,7 +4,7 @@ import Joi from 'joi';
|
|
|
4
4
|
import pick from 'lodash/pick';
|
|
5
5
|
import type { WhereOptions } from 'sequelize';
|
|
6
6
|
|
|
7
|
-
import { createListParamSchema, getWhereFromQuery, MetadataSchema } from '../libs/api';
|
|
7
|
+
import { createListParamSchema, getOrder, getWhereFromQuery, MetadataSchema } from '../libs/api';
|
|
8
8
|
import logger from '../libs/logger';
|
|
9
9
|
import { authenticate } from '../libs/security';
|
|
10
10
|
import { canUpsell } from '../libs/session';
|
|
@@ -88,7 +88,7 @@ router.get('/', auth, async (req, res) => {
|
|
|
88
88
|
const { rows, count } = await Price.findAndCountAll({
|
|
89
89
|
where,
|
|
90
90
|
attributes: ['id'],
|
|
91
|
-
order: [['created_at', 'DESC']],
|
|
91
|
+
order: getOrder(req.query, [['created_at', 'DESC']]),
|
|
92
92
|
offset: (page - 1) * pageSize,
|
|
93
93
|
limit: pageSize,
|
|
94
94
|
});
|
|
@@ -115,7 +115,7 @@ router.get('/search', auth, async (req, res) => {
|
|
|
115
115
|
const { rows, count } = await Price.findAndCountAll({
|
|
116
116
|
where,
|
|
117
117
|
attributes: ['id'],
|
|
118
|
-
order: [['created_at', 'DESC']],
|
|
118
|
+
order: getOrder(req.query, [['created_at', 'DESC']]),
|
|
119
119
|
offset: (page - 1) * pageSize,
|
|
120
120
|
limit: pageSize,
|
|
121
121
|
});
|
|
@@ -8,7 +8,7 @@ import uniq from 'lodash/uniq';
|
|
|
8
8
|
import type { WhereOptions } from 'sequelize';
|
|
9
9
|
|
|
10
10
|
import { checkPassportForPricingTable } from '../integrations/blocklet/passport';
|
|
11
|
-
import { createListParamSchema, MetadataSchema } from '../libs/api';
|
|
11
|
+
import { createListParamSchema, getOrder, MetadataSchema } from '../libs/api';
|
|
12
12
|
import logger from '../libs/logger';
|
|
13
13
|
import { authenticate } from '../libs/security';
|
|
14
14
|
import { getBillingThreshold, getMinStakeAmount, isLineItemCurrencyAligned } from '../libs/session';
|
|
@@ -107,7 +107,7 @@ router.get('/', auth, async (req, res) => {
|
|
|
107
107
|
try {
|
|
108
108
|
const { rows: list, count } = await PricingTable.findAndCountAll({
|
|
109
109
|
where,
|
|
110
|
-
order: [['created_at', 'DESC']],
|
|
110
|
+
order: getOrder(req.query, [['created_at', 'DESC']]),
|
|
111
111
|
offset: (page - 1) * pageSize,
|
|
112
112
|
limit: pageSize,
|
|
113
113
|
include: [],
|
|
@@ -5,7 +5,7 @@ import cloneDeep from 'lodash/cloneDeep';
|
|
|
5
5
|
import pick from 'lodash/pick';
|
|
6
6
|
import { Op } from 'sequelize';
|
|
7
7
|
|
|
8
|
-
import { createListParamSchema, getWhereFromKvQuery, getWhereFromQuery, MetadataSchema } from '../libs/api';
|
|
8
|
+
import { createListParamSchema, getOrder, getWhereFromKvQuery, getWhereFromQuery, MetadataSchema } from '../libs/api';
|
|
9
9
|
import logger from '../libs/logger';
|
|
10
10
|
import { authenticate } from '../libs/security';
|
|
11
11
|
import { formatMetadata } from '../libs/util';
|
|
@@ -257,7 +257,7 @@ router.get('/', auth, async (req, res) => {
|
|
|
257
257
|
|
|
258
258
|
const { rows: list, count } = await Product.findAndCountAll({
|
|
259
259
|
where,
|
|
260
|
-
order: [['created_at', query.o === 'asc' ? 'ASC' : 'DESC']],
|
|
260
|
+
order: getOrder(req.query, [['created_at', query.o === 'asc' ? 'ASC' : 'DESC']]),
|
|
261
261
|
offset: (page - 1) * pageSize,
|
|
262
262
|
limit: pageSize,
|
|
263
263
|
include: [{ model: Price, as: 'prices' }],
|
|
@@ -286,7 +286,7 @@ router.get('/search', auth, async (req, res) => {
|
|
|
286
286
|
|
|
287
287
|
const { rows: list, count } = await Product.findAndCountAll({
|
|
288
288
|
where,
|
|
289
|
-
order: [['created_at', 'DESC']],
|
|
289
|
+
order: getOrder(req.query, [['created_at', 'DESC']]),
|
|
290
290
|
offset: (page - 1) * pageSize,
|
|
291
291
|
limit: pageSize,
|
|
292
292
|
include: [{ model: Price, as: 'prices', separate: true }],
|
|
@@ -5,7 +5,7 @@ import Joi from 'joi';
|
|
|
5
5
|
import pick from 'lodash/pick';
|
|
6
6
|
|
|
7
7
|
import { BN, fromTokenToUnit } from '@ocap/util';
|
|
8
|
-
import { BNPositiveValidator, createListParamSchema, getWhereFromKvQuery, MetadataSchema } from '../libs/api';
|
|
8
|
+
import { BNPositiveValidator, createListParamSchema, getOrder, getWhereFromKvQuery, MetadataSchema } from '../libs/api';
|
|
9
9
|
import { authenticate } from '../libs/security';
|
|
10
10
|
import { formatMetadata } from '../libs/util';
|
|
11
11
|
import {
|
|
@@ -94,7 +94,7 @@ router.get('/', auth, async (req, res) => {
|
|
|
94
94
|
|
|
95
95
|
const { rows: list, count } = await Refund.findAndCountAll({
|
|
96
96
|
where,
|
|
97
|
-
order: [['created_at', query.o === 'asc' ? 'ASC' : 'DESC']],
|
|
97
|
+
order: getOrder(req.query, [['created_at', query.o === 'asc' ? 'ASC' : 'DESC']]),
|
|
98
98
|
offset: (page - 1) * pageSize,
|
|
99
99
|
limit: pageSize,
|
|
100
100
|
include: [
|
|
@@ -196,7 +196,7 @@ router.get('/search', auth, async (req, res) => {
|
|
|
196
196
|
|
|
197
197
|
const { rows: list, count } = await Refund.findAndCountAll({
|
|
198
198
|
where,
|
|
199
|
-
order: [['created_at', o === 'asc' ? 'ASC' : 'DESC']],
|
|
199
|
+
order: getOrder(req.query, [['created_at', o === 'asc' ? 'ASC' : 'DESC']]),
|
|
200
200
|
offset: (page - 1) * pageSize,
|
|
201
201
|
limit: pageSize,
|
|
202
202
|
include: [
|