Commit a70760ab authored by 任国军's avatar 任国军

add buyClass

parent c9cfe28e
Pipeline #24410 passed with stage
in 3 seconds
...@@ -95,6 +95,20 @@ class UserController extends Controller { ...@@ -95,6 +95,20 @@ class UserController extends Controller {
const ret = await service.course.v5.user.getUserAddress(); const ret = await service.course.v5.user.getUserAddress();
ctx.success(ret); ctx.success(ret);
} }
// 购买课程
async buyClass() {
const { ctx, service } = this;
const params = ctx.params;
if (ctx.isEmpty(params) || ctx.isEmpty(params.class_id)) {
ctx.failed('class_id is failed');
}
const ret = await service.course.v5.user.buyClass(params.class_id);
ctx.success(ret);
}
} }
module.exports = UserController; module.exports = UserController;
...@@ -22,7 +22,6 @@ module.exports = app => { ...@@ -22,7 +22,6 @@ module.exports = app => {
redeem: STRING, redeem: STRING,
status: INTEGER, status: INTEGER,
is_deleted: INTEGER, is_deleted: INTEGER,
hash: STRING,
created_time: { created_time: {
type: DATE, type: DATE,
allowNull: true, allowNull: true,
......
...@@ -25,6 +25,13 @@ module.exports = app => { ...@@ -25,6 +25,13 @@ module.exports = app => {
cycle: STRING, cycle: STRING,
channel: TEXT, channel: TEXT,
description: TEXT, description: TEXT,
button_style: INTEGER,
button_text: STRING,
button_type: INTEGER,
button_sub_text: STRING,
top_price: STRING,
pay_price: DECIMAL,
sort: INTEGER,
status: INTEGER, status: INTEGER,
is_deleted: INTEGER, is_deleted: INTEGER,
created_time: { created_time: {
......
...@@ -57,4 +57,6 @@ module.exports = app => { ...@@ -57,4 +57,6 @@ module.exports = app => {
router.get('third', '/video/:id', auth({ is_force: 1 }), 'course.v5.institution.getVideoInfo');// 获取视频详情 router.get('third', '/video/:id', auth({ is_force: 1 }), 'course.v5.institution.getVideoInfo');// 获取视频详情
router.get('third', '/home/class/all', auth({ is_force: 0 }), 'course.v5.institution.getHomeClassList');// 获取课程首页 router.get('third', '/home/class/all', auth({ is_force: 0 }), 'course.v5.institution.getHomeClassList');// 获取课程首页
router.post('third', '/order/class/:class_id', auth({ is_force: 1 }), 'course.v5.user.buyClass');// 购买课程
}; };
...@@ -99,7 +99,7 @@ class InstitutionSubService extends Service { ...@@ -99,7 +99,7 @@ class InstitutionSubService extends Service {
// 课程详情 // 课程详情
async getClassInfo(id) { async getClassInfo(id) {
const { ctx } = this; const { ctx } = this;
const attributes = [ 'id', 'institution_id', 'name', 'logo', 'age', 'price', 'price_type', 'mode', 'time', 'class_amount', 'multi_classes', 'cycle', 'description', 'sort' ]; const attributes = [ 'id', 'institution_id', 'name', 'logo', 'age', 'price', 'price_type', 'mode', 'time', 'class_amount', 'multi_classes', 'cycle', 'description', 'button_style', 'button_text', 'button_type', 'button_sub_text', 'top_price', 'pay_price', 'sort' ];
const classInfo = await ctx.classModel.V5.CourseV5Class.findOne({ where: { id, status: 1, is_deleted: 0 }, attributes, raw: true }); const classInfo = await ctx.classModel.V5.CourseV5Class.findOne({ where: { id, status: 1, is_deleted: 0 }, attributes, raw: true });
if (ctx.isEmpty(classInfo)) { if (ctx.isEmpty(classInfo)) {
ctx.failed('数据不存在'); ctx.failed('数据不存在');
...@@ -443,7 +443,7 @@ class InstitutionSubService extends Service { ...@@ -443,7 +443,7 @@ class InstitutionSubService extends Service {
const results = []; const results = [];
let classList = []; let classList = [];
const classAll = await ctx.classMdel.V5.CourseV5ClassToCat.findAll({ where: { cat_id, status: 1, is_deleted: 0 } }); const classAll = await ctx.classModel.V5.CourseV5ClassToCat.findAll({ where: { cat_id, status: 1, is_deleted: 0 } });
const classIds = R.pluck('class_id', classAll); const classIds = R.pluck('class_id', classAll);
// 体验课 // 体验课
......
...@@ -352,6 +352,62 @@ class UserService extends Service { ...@@ -352,6 +352,62 @@ class UserService extends Service {
return ret; return ret;
} }
// 购买课程
async buyClass(id) {
const { ctx } = this;
const userUuid = ctx.userUuid;
if (ctx.isEmpty(userUuid)) {
ctx.failed('用户异常');
}
// 先判断用户订单
let order = await ctx.classModel.V5.CourseUserOrder.findOne({ where: { user_uuid: userUuid, class_id: id, is_deleted: 0 }, order: [[ 'id', 'asc' ]] });
if (!ctx.isEmpty(order) && order.status === 1) {
ctx.failed('请勿重复购买');
}
// 获取课程详情
const classInfo = await ctx.classModel.V5.CourseV5Class.findOne({ where: { id, status: 1, is_deleted: 0 }, attributions: [ 'name', 'pay_price' ] });
if (ctx.isEmpty(classInfo)) {
ctx.failed('课程不存在');
}
if (ctx.isEmpty(order)) {
const data = {
order_no: '11' + moment().format('YYYYMMDDHHMMSS') + await this.getRandomNumber(6),
user_uuid: userUuid,
class_id: id,
pay: classInfo.pay_price,
type: 1,
};
await ctx.classModel.V5.CourseUserOrder.create(data);
order = await ctx.classModel.V5.CourseUserOrder.findOne({ where: { user_uuid: userUuid, class_id: id, is_deleted: 0 }, order: [[ 'id', 'asc' ]] });
}
await ctx.classModel.V5.CourseUserOrder.update({ pay: classInfo.pay_price, type: 1, redeem: '', status: 0 }, { where: { id: order.id } });
let response = await this.service.course.v5.wechat.pay({ pay: order.pay, order_no: order.order_no, body: `趣选课-${order.order_no}` });
response = await ctx.helper.xmlTojson(response);
if (ctx.isEmpty(response)) {
ctx.failed('未知错误');
}
if (response.return_code[0] === 'FAIL') {
ctx.failed(response.return_msg[0]);
}
if (response.result_code[0] === 'FAIL') {
ctx.failed(response.err_code_des[0]);
}
const ret = {
trade_type: response.trade_type[0],
prepay_id: response.prepay_id[0],
};
return ret;
}
} }
module.exports = UserService; module.exports = UserService;
...@@ -316,21 +316,25 @@ class WechatService extends Service { ...@@ -316,21 +316,25 @@ class WechatService extends Service {
const key = 'xuepenQuXuanKeweixinzhifu2020063'; const key = 'xuepenQuXuanKeweixinzhifu2020063';
const nonce_str = ctx.helper.md5(moment().millisecond()).slice(0, 16); const nonce_str = ctx.helper.md5(moment().millisecond()).slice(0, 16);
const body = input.body || '趣选课-测试'; const body = input.body || '趣选课-测试';
const out_trade_no = '2020060315300001'; const out_trade_no = input.order_no;
const total_fee = '1'; const total_fee = Number(input.pay * 100);
const spbill_create_ip = ctx.helper.getClientIP() || '127.0.0.1'; const spbill_create_ip = ctx.helper.getClientIP() || '127.0.0.1';
const notify_url = 'https://uat-nginx.jianbing.com/51business/api/course/v5/wechat/pay/notify'; const notify_url = 'https://uat-nginx.jianbing.com/51business/api/course/v5/wechat/pay/notify';
const trade_type = 'JSAPI'; const trade_type = 'JSAPI';
const openid = 'ofaz74vASbOyxwS1hyxrmQjYatlU';
// 用户信息
const userInfo = await ctx.classModel.V5.CourseUser.findOne({ where: { uuid: ctx.userUuid, is_deleted: 0 } });
if (ctx.isEmpty(userInfo)) {
ctx.failed('用户不存在');
}
const openid = userInfo.openid;
// 签名 // 签名
const arr = [ `appid=${appId}`, `body=${body}`, `mch_id=${mchId}`, `nonce_str=${nonce_str}`, `notify_url=${notify_url}`, `out_trade_no=${out_trade_no}`, `spbill_create_ip=${spbill_create_ip}`, `total_fee=${total_fee}`, `trade_type=${trade_type}`, `openid=${openid}` ]; const arr = [ `appid=${appId}`, `body=${body}`, `mch_id=${mchId}`, `nonce_str=${nonce_str}`, `notify_url=${notify_url}`, `out_trade_no=${out_trade_no}`, `spbill_create_ip=${spbill_create_ip}`, `total_fee=${total_fee}`, `trade_type=${trade_type}`, `openid=${openid}` ];
arr.sort(); arr.sort();
let sign = ctx.helper.md5(arr.join('&') + `&key=${key}`); let sign = ctx.helper.md5(arr.join('&') + `&key=${key}`);
console.log(arr.join('&') + `&key=${key}`);
sign = sign.toUpperCase(); sign = sign.toUpperCase();
console.log(sign);
// 组装xml数据 // 组装xml数据
let xmlData = '<xml>'; let xmlData = '<xml>';
...@@ -347,16 +351,19 @@ class WechatService extends Service { ...@@ -347,16 +351,19 @@ class WechatService extends Service {
xmlData += '<sign>' + sign + '</sign>'; xmlData += '<sign>' + sign + '</sign>';
xmlData += '</xml>'; xmlData += '</xml>';
const ret = request({ url: 'https://api.mch.weixin.qq.com/pay/unifiedorder', method: 'POST', body: xmlData }, function(err, response, body) { ctx.logger.info('course_wechat_pay_params: ' + xmlData);
if (!err && response.statusCode === 200) { let ret = await new Promise((resolve, reject) => {
console.log('result:'); request({ url: 'https://api.mch.weixin.qq.com/pay/unifiedorder', method: 'POST', body: xmlData }, function(err, response, body) {
console.log(body); if (!err && response.statusCode === 200) {
return body; ctx.logger.info('course_wechat_pay_result: ' + body);
} resolve(body);
return err; } else {
resolve(err);
}
});
}); });
ret = ret.replace(/^\ufeff/i, '').replace(/^\ufffe/i, '');
return ret; return ret;
} }
} }
......
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment