q-koa 10.6.7 → 10.7.1
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/core/app.js +4 -0
- package/core/file/plugins/toutiao/controller.js +191 -3
- package/core/file/plugins/toutiao/service.js +78 -0
- package/core/file/plugins/user/controller.js +32 -14
- package/core/file/plugins/weixin/service.js +5 -13
- package/core/file/utils/index.js +19 -0
- package/package.json +1 -1
package/core/app.js
CHANGED
|
@@ -1987,6 +1987,10 @@ APP.getClientTypeByCtx = (ctx) => {
|
|
|
1987
1987
|
|
|
1988
1988
|
APP.getConfig = (app) => ({
|
|
1989
1989
|
async getObject(type) {
|
|
1990
|
+
if (!type) {
|
|
1991
|
+
console.error(`getObject type : ${type}`)
|
|
1992
|
+
return {}
|
|
1993
|
+
}
|
|
1990
1994
|
let configList = app.cache.get('configList')
|
|
1991
1995
|
if (!configList) {
|
|
1992
1996
|
configList = await app.model.setting.findAll({
|
|
@@ -5,8 +5,7 @@ const axios = require('axios')
|
|
|
5
5
|
const qr = require('qr-image')
|
|
6
6
|
const path = require('path')
|
|
7
7
|
const TOUTIAO = getService('toutiao')
|
|
8
|
-
|
|
9
|
-
const utils = require('../../utils')
|
|
8
|
+
const { signResult, hashFn } = require('../../utils')
|
|
10
9
|
|
|
11
10
|
exports.initData = async (ctx) => {
|
|
12
11
|
const { app, appName } = getAppByCtx(ctx)
|
|
@@ -36,7 +35,7 @@ exports.qr_code = async (ctx) => {
|
|
|
36
35
|
const result = await toutiaoService.createQR({
|
|
37
36
|
path: encodeURIComponent(page),
|
|
38
37
|
appname: type,
|
|
39
|
-
filename:
|
|
38
|
+
filename: hashFn(item.key + page + type),
|
|
40
39
|
})
|
|
41
40
|
console.log(`qr,${item.key},${page},${type}`)
|
|
42
41
|
const qr_image = `https://${site_host || 'api.kuashou.com'}/upload/${result}`
|
|
@@ -194,3 +193,192 @@ exports.login = async (ctx) => {
|
|
|
194
193
|
user: result,
|
|
195
194
|
})
|
|
196
195
|
}
|
|
196
|
+
|
|
197
|
+
exports.pay = async (ctx) => {
|
|
198
|
+
const { app, appName } = getAppByCtx(ctx)
|
|
199
|
+
const appConfig = getConfig(app)
|
|
200
|
+
const { is_dev, site_host } = await appConfig.getObject('base')
|
|
201
|
+
const { app_id, salt, key, is_sandbox, ...rest } = await appConfig.getObject(
|
|
202
|
+
'toutiao'
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
const {
|
|
206
|
+
name,
|
|
207
|
+
out_trade_no: _out_trade_no,
|
|
208
|
+
prefix = '',
|
|
209
|
+
order_id,
|
|
210
|
+
type = 'TOUTIAO-WEIXIN',
|
|
211
|
+
price,
|
|
212
|
+
is_admin = false,
|
|
213
|
+
valid_time = 900,
|
|
214
|
+
} = ctx.request.body
|
|
215
|
+
|
|
216
|
+
const url = `https://${
|
|
217
|
+
is_sandbox ? 'open-sandbox.douyin.com' : 'developer.toutiao.com'
|
|
218
|
+
}/api/apps/ecpay/v1/create_order`
|
|
219
|
+
|
|
220
|
+
const out_order_no = _out_trade_no
|
|
221
|
+
? _out_trade_no
|
|
222
|
+
: prefix
|
|
223
|
+
? `${key.length > 10 ? appName : key}_${prefix}-${order_id}_${type}`
|
|
224
|
+
: `${key.length > 10 ? appName : key}_${order_id}_${type}`
|
|
225
|
+
|
|
226
|
+
const notify_url = `https://${
|
|
227
|
+
site_host || 'api.kuashou.com'
|
|
228
|
+
}/${appName}/toutiao/notify`
|
|
229
|
+
|
|
230
|
+
const data = {
|
|
231
|
+
app_id,
|
|
232
|
+
out_order_no,
|
|
233
|
+
total_amount: is_admin || is_dev ? 1 : Math.round(price * 100),
|
|
234
|
+
subject: name,
|
|
235
|
+
body: `订单【${out_order_no}】`,
|
|
236
|
+
valid_time,
|
|
237
|
+
notify_url,
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const res = await axios
|
|
241
|
+
.post(url, {
|
|
242
|
+
...data,
|
|
243
|
+
sign: signResult(data, salt),
|
|
244
|
+
})
|
|
245
|
+
.then((res) => res.data)
|
|
246
|
+
|
|
247
|
+
if (res.err_no) {
|
|
248
|
+
throw new Error(res.err_tips)
|
|
249
|
+
}
|
|
250
|
+
ctx.SUCCESS(res.data)
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
exports.notify = async (ctx) => {
|
|
254
|
+
const { app } = getAppByCtx(ctx)
|
|
255
|
+
const { type, msg, nonce, msg_signature, timestamp } = ctx.request.body
|
|
256
|
+
|
|
257
|
+
const {
|
|
258
|
+
appid,
|
|
259
|
+
cp_orderno: out_trade_no,
|
|
260
|
+
cp_extra,
|
|
261
|
+
way,
|
|
262
|
+
channel_no,
|
|
263
|
+
payment_order_no,
|
|
264
|
+
total_amount,
|
|
265
|
+
status,
|
|
266
|
+
item_id,
|
|
267
|
+
seller_uid,
|
|
268
|
+
paid_at,
|
|
269
|
+
order_id: transactionid,
|
|
270
|
+
} = JSON.parse(msg)
|
|
271
|
+
|
|
272
|
+
let order_id = out_trade_no.split('_')[1]
|
|
273
|
+
const order_price = Number(total_amount) / 100
|
|
274
|
+
let prefix = ''
|
|
275
|
+
if (order_id.includes('-')) {
|
|
276
|
+
const arr = order_id.split('-')
|
|
277
|
+
order_id = Number(arr[1])
|
|
278
|
+
;[prefix] = arr
|
|
279
|
+
} else {
|
|
280
|
+
order_id = Number(order_id)
|
|
281
|
+
}
|
|
282
|
+
const model = prefix ? `${prefix}_order` : 'order'
|
|
283
|
+
let openid = ''
|
|
284
|
+
|
|
285
|
+
console.log(order_id, '微信支付回调-----', model, order_price, transactionid)
|
|
286
|
+
if (app.service[model] && app.service[model].notify) {
|
|
287
|
+
await app.service[model].notify({
|
|
288
|
+
app,
|
|
289
|
+
order_id,
|
|
290
|
+
order: model,
|
|
291
|
+
order_price,
|
|
292
|
+
transactionid,
|
|
293
|
+
out_trade_no,
|
|
294
|
+
openid,
|
|
295
|
+
})
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
ctx.status = 200
|
|
299
|
+
ctx.body = {
|
|
300
|
+
err_no: 0,
|
|
301
|
+
err_tips: 'success',
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
exports.checkPay = async (ctx) => {
|
|
306
|
+
const { app, appName } = getAppByCtx(ctx)
|
|
307
|
+
|
|
308
|
+
const {
|
|
309
|
+
id,
|
|
310
|
+
prefix,
|
|
311
|
+
type = 'TOUTIAO-DOUYIN',
|
|
312
|
+
out_trade_no: _out_trade_no,
|
|
313
|
+
} = ctx.request.body
|
|
314
|
+
|
|
315
|
+
const orderModel = prefix ? `${prefix}_order` : 'order'
|
|
316
|
+
const result = await app.model[orderModel].findOne({
|
|
317
|
+
where: {
|
|
318
|
+
id,
|
|
319
|
+
},
|
|
320
|
+
})
|
|
321
|
+
if (!result) return ctx.SUCCESS('找不到')
|
|
322
|
+
|
|
323
|
+
const appConfig = getConfig(app)
|
|
324
|
+
const { is_dev, site_host } = await appConfig.getObject('base')
|
|
325
|
+
const { app_id, salt, key, is_sandbox, ...rest } = await appConfig.getObject(
|
|
326
|
+
'toutiao'
|
|
327
|
+
)
|
|
328
|
+
|
|
329
|
+
const orderPrefix = prefix ? `${prefix}-` : ''
|
|
330
|
+
const out_trade_no = _out_trade_no
|
|
331
|
+
? _out_trade_no
|
|
332
|
+
: `${key}_${orderPrefix}${id}_${type}`
|
|
333
|
+
|
|
334
|
+
const url = `https://${
|
|
335
|
+
is_sandbox ? 'open-sandbox.douyin.com' : 'developer.toutiao.com'
|
|
336
|
+
}/api/apps/ecpay/v1/query_order`
|
|
337
|
+
|
|
338
|
+
const data = {
|
|
339
|
+
app_id,
|
|
340
|
+
out_order_no: out_trade_no,
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
const res = await axios
|
|
344
|
+
.post(url, {
|
|
345
|
+
...data,
|
|
346
|
+
sign: signResult(data, salt),
|
|
347
|
+
})
|
|
348
|
+
.then((res) => res.data)
|
|
349
|
+
|
|
350
|
+
if (res.err_no) {
|
|
351
|
+
throw new Error(res.err_tips)
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
const order_price = Number(res.payment_info.total_fee) / 100
|
|
355
|
+
await app.service[orderModel].notify({
|
|
356
|
+
app,
|
|
357
|
+
order: orderModel,
|
|
358
|
+
order_id: id,
|
|
359
|
+
order_price,
|
|
360
|
+
transactionid: res.order_id,
|
|
361
|
+
out_trade_no: res.out_trade_no,
|
|
362
|
+
})
|
|
363
|
+
ctx.SUCCESS({
|
|
364
|
+
...res.payment_info,
|
|
365
|
+
order_id: res.order_id,
|
|
366
|
+
})
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
exports.refund = async (ctx) => {
|
|
370
|
+
const { app, appName } = getAppByCtx(ctx)
|
|
371
|
+
const appConfig = getConfig(app)
|
|
372
|
+
const { id, prefix = '', price, out_trade_no, type } = ctx.request.body
|
|
373
|
+
|
|
374
|
+
if (!app.service.toutiao) throw new Error(`toutiao可能没有service.js`)
|
|
375
|
+
const res = await app.service.toutiao.refund({
|
|
376
|
+
ctx,
|
|
377
|
+
id,
|
|
378
|
+
prefix,
|
|
379
|
+
price,
|
|
380
|
+
out_trade_no,
|
|
381
|
+
type,
|
|
382
|
+
})
|
|
383
|
+
ctx.SUCCESS(res)
|
|
384
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
const { getAppByCtx, getUserByCtx, getConfig } = require('q-koa')
|
|
2
|
+
const axios = require('axios')
|
|
3
|
+
const { signResult } = require('../../utils')
|
|
4
|
+
|
|
5
|
+
exports.refund = async ({
|
|
6
|
+
ctx,
|
|
7
|
+
id,
|
|
8
|
+
prefix = '',
|
|
9
|
+
total_fee,
|
|
10
|
+
refund_fee,
|
|
11
|
+
price,
|
|
12
|
+
out_trade_no: _out_trade_no,
|
|
13
|
+
type = 'TOUTIAO-DOUYIN',
|
|
14
|
+
...rest
|
|
15
|
+
}) => {
|
|
16
|
+
if (!ctx) throw new Error('?ctx')
|
|
17
|
+
const { app, appName } = getAppByCtx(ctx)
|
|
18
|
+
const appConfig = getConfig(app)
|
|
19
|
+
const { app_id, salt, key, is_sandbox } = await appConfig.getObject('toutiao')
|
|
20
|
+
const { site_host } = await appConfig.getObject('base')
|
|
21
|
+
|
|
22
|
+
const orderModel = prefix ? `${prefix}_order` : 'order'
|
|
23
|
+
const out_trade_no = _out_trade_no
|
|
24
|
+
? _out_trade_no
|
|
25
|
+
: prefix
|
|
26
|
+
? `${key}_${prefix}-${id}_${type}`
|
|
27
|
+
: `${key}_${id}_${type}`
|
|
28
|
+
const orderDetail = await app.model[orderModel].findOne({
|
|
29
|
+
where: {
|
|
30
|
+
id,
|
|
31
|
+
},
|
|
32
|
+
})
|
|
33
|
+
if (!orderDetail) throw new Error('不存在该订单')
|
|
34
|
+
|
|
35
|
+
const url = `https://${
|
|
36
|
+
is_sandbox ? 'open-sandbox.douyin.com' : 'developer.toutiao.com'
|
|
37
|
+
}/api/apps/ecpay/v1/create_refund`
|
|
38
|
+
|
|
39
|
+
const data = {
|
|
40
|
+
app_id,
|
|
41
|
+
out_order_no: out_trade_no,
|
|
42
|
+
out_refund_no: `${prefix}-${id}_${type}`,
|
|
43
|
+
reason: rest.remark || '退款',
|
|
44
|
+
refund_amount: Math.round((refund_fee || price) * 100),
|
|
45
|
+
notify_url: `https://${
|
|
46
|
+
site_host || 'api.kuashou.com'
|
|
47
|
+
}/${appName}/toutiao/refund_notify`,
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const signResult = (params, salt) => {
|
|
51
|
+
var skip_arr = ['thirdparty_id', 'app_id', 'sign']
|
|
52
|
+
var paramArray = new Array()
|
|
53
|
+
for (var k in params) {
|
|
54
|
+
if (skip_arr.indexOf(k) != -1) {
|
|
55
|
+
continue
|
|
56
|
+
}
|
|
57
|
+
if (params[k] == '') {
|
|
58
|
+
continue
|
|
59
|
+
}
|
|
60
|
+
paramArray.push(params[k])
|
|
61
|
+
}
|
|
62
|
+
paramArray.push(salt)
|
|
63
|
+
paramArray.sort()
|
|
64
|
+
var signStr = paramArray.join('&')
|
|
65
|
+
return md5(signStr)
|
|
66
|
+
}
|
|
67
|
+
const res = await axios
|
|
68
|
+
.post(url, {
|
|
69
|
+
...data,
|
|
70
|
+
sign: signResult(data, salt),
|
|
71
|
+
})
|
|
72
|
+
.then((res) => res.data)
|
|
73
|
+
if (res.err_no) {
|
|
74
|
+
throw new Error(res.err_tips)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return res
|
|
78
|
+
}
|
|
@@ -7,8 +7,6 @@ exports.login = async (ctx) => {
|
|
|
7
7
|
const { mobile, password, config: _config, ...rest } = ctx.request.body
|
|
8
8
|
|
|
9
9
|
const config = _config || ctx.request.header.config || 'weixin_mp'
|
|
10
|
-
const appConfig = getConfig(app)
|
|
11
|
-
const { app_id } = await appConfig.getObject(config)
|
|
12
10
|
|
|
13
11
|
const where =
|
|
14
12
|
process.env.NODE_ENV !== 'production'
|
|
@@ -36,6 +34,22 @@ exports.login = async (ctx) => {
|
|
|
36
34
|
where,
|
|
37
35
|
})
|
|
38
36
|
if (!result) throw new Error('账号密码错误')
|
|
37
|
+
if (_config === 'none') {
|
|
38
|
+
const tokenResult = {
|
|
39
|
+
id: result.id,
|
|
40
|
+
name: result.name,
|
|
41
|
+
mobile: result.mobile,
|
|
42
|
+
}
|
|
43
|
+
const token = await app.sign({
|
|
44
|
+
user: tokenResult,
|
|
45
|
+
})
|
|
46
|
+
return ctx.SUCCESS({
|
|
47
|
+
token,
|
|
48
|
+
user: app.appConfig.loginData
|
|
49
|
+
? lodash.omit(result.toJSON(), app.appConfig.loginData.omit)
|
|
50
|
+
: result,
|
|
51
|
+
})
|
|
52
|
+
}
|
|
39
53
|
if (
|
|
40
54
|
ctx.request[`${appName}-user`] &&
|
|
41
55
|
ctx.request[`${appName}-user`].mp_user
|
|
@@ -89,6 +103,8 @@ exports.login = async (ctx) => {
|
|
|
89
103
|
}
|
|
90
104
|
)
|
|
91
105
|
}
|
|
106
|
+
const appConfig = getConfig(app)
|
|
107
|
+
const { app_id } = await appConfig.getObject(config)
|
|
92
108
|
/**
|
|
93
109
|
* 查出最新用户,存token并返回
|
|
94
110
|
*/
|
|
@@ -115,18 +131,20 @@ exports.login = async (ctx) => {
|
|
|
115
131
|
: {
|
|
116
132
|
model: app.model.mp_user,
|
|
117
133
|
}
|
|
118
|
-
const includeDefault =
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
134
|
+
const includeDefault =
|
|
135
|
+
config !== 'none'
|
|
136
|
+
? [
|
|
137
|
+
{
|
|
138
|
+
model: app.model.github_user,
|
|
139
|
+
},
|
|
140
|
+
h5_user_include,
|
|
141
|
+
mp_user_include,
|
|
142
|
+
{
|
|
143
|
+
model: app.model.toutiao_user,
|
|
144
|
+
},
|
|
145
|
+
...app.include.user,
|
|
146
|
+
].filter((item) => item.model)
|
|
147
|
+
: []
|
|
130
148
|
if (app.appConfig.loginData) {
|
|
131
149
|
const include = includeDefault.filter((i) => {
|
|
132
150
|
return app.appConfig.loginData.excludeInclude.every((m) => {
|
|
@@ -51,29 +51,21 @@ exports.refund = async ({
|
|
|
51
51
|
})
|
|
52
52
|
if (!orderDetail) throw new Error('不存在该订单')
|
|
53
53
|
try {
|
|
54
|
-
const
|
|
54
|
+
const data = {
|
|
55
55
|
...rest,
|
|
56
56
|
out_trade_no,
|
|
57
|
-
out_refund_no: id
|
|
57
|
+
out_refund_no: `${prefix}-${id}_${type}`,
|
|
58
58
|
total_fee: Math.round((total_fee || refund_fee || price) * 100),
|
|
59
59
|
refund_fee: Math.round((refund_fee || price) * 100),
|
|
60
60
|
notify_url: `https://${
|
|
61
61
|
site_host || 'api.kuashou.com'
|
|
62
62
|
}/${appName}/weixin/refund_notify/${pay_config}`,
|
|
63
|
-
}
|
|
63
|
+
}
|
|
64
|
+
const { result_code, err_code_des } = await payObj.refund(data)
|
|
64
65
|
if (result_code === 'SUCCESS') {
|
|
65
66
|
return true
|
|
66
67
|
} else {
|
|
67
|
-
console.error(
|
|
68
|
-
...rest,
|
|
69
|
-
out_trade_no,
|
|
70
|
-
out_refund_no: id + '_' + type,
|
|
71
|
-
total_fee: Math.round((total_fee || refund_fee || price) * 100),
|
|
72
|
-
refund_fee: Math.round((refund_fee || price) * 100),
|
|
73
|
-
notify_url: `https://${
|
|
74
|
-
site_host || 'api.kuashou.com'
|
|
75
|
-
}/${appName}/weixin/refund_notify/${pay_config}`,
|
|
76
|
-
})
|
|
68
|
+
console.error(data)
|
|
77
69
|
throw new Error(err_code_des)
|
|
78
70
|
}
|
|
79
71
|
} catch (e) {
|
package/core/file/utils/index.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const { lodash } = require('q-koa')
|
|
2
|
+
const md5 = require('md5')
|
|
2
3
|
|
|
3
4
|
const findConfig = (type) => (item) =>
|
|
4
5
|
item.key === type ||
|
|
@@ -169,3 +170,21 @@ exports.getAppConfig = async ({ app, config, key, app_id }) => {
|
|
|
169
170
|
|
|
170
171
|
return target || null
|
|
171
172
|
}
|
|
173
|
+
|
|
174
|
+
exports.signResult = (params, salt) => {
|
|
175
|
+
var skip_arr = ['thirdparty_id', 'app_id', 'sign']
|
|
176
|
+
var paramArray = new Array()
|
|
177
|
+
for (var k in params) {
|
|
178
|
+
if (skip_arr.indexOf(k) != -1) {
|
|
179
|
+
continue
|
|
180
|
+
}
|
|
181
|
+
if (params[k] == '') {
|
|
182
|
+
continue
|
|
183
|
+
}
|
|
184
|
+
paramArray.push(params[k])
|
|
185
|
+
}
|
|
186
|
+
paramArray.push(salt)
|
|
187
|
+
paramArray.sort()
|
|
188
|
+
var signStr = paramArray.join('&')
|
|
189
|
+
return md5(signStr)
|
|
190
|
+
}
|