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.
@@ -21,6 +21,7 @@ const handleUserUpdate = async ({ user }: { user: any }) => {
21
21
  email: user.email,
22
22
  phone: user.phone,
23
23
  last_sync_at: now,
24
+ address: Customer.formatAddressFromUser(user),
24
25
  });
25
26
  logger.info(`customer info updated: ${customer.did}`);
26
27
  }
@@ -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<T & { page: number; pageSize: number; livemode?: boolean; q?: string; o?: string }>({
114
- // prettier-ignore
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
- return 100;
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(''), // query
140
- o: Joi.string().empty(''), // order
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', auth, async (req, res) => {
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,
@@ -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: [
@@ -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: [