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

add redeemCode

parent d958e381
Pipeline #24593 passed with stage
in 4 seconds
......@@ -109,6 +109,29 @@ class UserController extends Controller {
const ret = await service.course.v5.user.buyClass(params.class_id);
ctx.success(ret);
}
// 用户订单列表
async getUserOrderList() {
const { ctx, service } = this;
const ret = await service.course.v5.user.getUserOrderList();
ctx.success(ret);
}
// 兑换课程
async redeemClass() {
const { ctx, service } = this;
const params = ctx.params;
if (ctx.isEmpty(params) || ctx.isEmpty(params.redeem_code)) {
ctx.failed('redeem_code is failed');
}
const ret = await service.course.v5.user.redeemClass(params.redeem_code);
ctx.success(ret);
}
}
module.exports = UserController;
......@@ -118,6 +118,7 @@ class WechatController extends Controller {
if (!ctx.isEmpty(parseObj)) {
ctx.logger.info('wechat_pay_callback: ' + JSON.stringify(parseObj));
await ctx.classModel.V5.CourseWechatLog.create({ type: 3, content: JSON.stringify(parseObj) });
if (parseObj.xml.return_code === 'SUCCESS') {
const arr = [];
for (const k in parseObj.xml) {
......
'use strict';
const moment = require('moment');
module.exports = app => {
const { STRING, INTEGER, DATE } = app.Sequelize;
const CourseRedeemCode = app.classModel.define('course_redeem_code', {
id: {
type: INTEGER,
primaryKey: true,
autoIncrement: true,
},
code: STRING,
class_id: INTEGER,
user_uuid: STRING,
is_used: INTEGER,
status: INTEGER,
is_deleted: INTEGER,
created_time: {
type: DATE,
allowNull: true,
get() {
const date = this.getDataValue('created_time');
return date ? moment(date).format('YYYY-MM-DD HH:mm:ss') : undefined;
},
},
updated_time: {
type: DATE,
allowNull: true,
get() {
const date = this.getDataValue('updated_time');
return date ? moment(date).format('YYYY-MM-DD HH:mm:ss') : undefined;
},
},
}, {
timestamps: false,
tableName: 'course_redeem_code',
});
return CourseRedeemCode;
};
......@@ -20,6 +20,7 @@ module.exports = app => {
pay_result: TEXT,
type: INTEGER,
redeem: STRING,
address: STRING,
status: INTEGER,
is_deleted: INTEGER,
created_time: {
......
'use strict';
const moment = require('moment');
module.exports = app => {
const { TEXT, INTEGER, DATE } = app.Sequelize;
const CourseWechatLog = app.classModel.define('course_wechat_log', {
id: {
type: INTEGER,
primaryKey: true,
autoIncrement: true,
},
type: INTEGER,
title: TEXT,
created_time: {
type: DATE,
allowNull: true,
get() {
const date = this.getDataValue('created_time');
return date ? moment(date).format('YYYY-MM-DD HH:mm:ss') : undefined;
},
},
}, {
timestamps: false,
tableName: 'course_wechat_log',
});
return CourseWechatLog;
};
......@@ -14,6 +14,8 @@ module.exports = app => {
router.post('third', '/user/baby', auth({ is_force: 1 }), 'course.v5.user.addUserBaby');// 上传用户宝宝信息
router.post('third', '/user/address', auth({ is_force: 1 }), 'course.v5.user.addUserAddress');// 新增用户收货地址
router.get('third', '/user/address', auth({ is_force: 1 }), 'course.v5.user.getUserAddress');// 获取用户收货地址
router.get('third', '/user/order/all', auth({ is_force: 1 }), 'course.v5.user.getUserOrderList');// 获取订单列表
router.post('third', '/user/redeem/class/:redeem_code', auth({ is_force: 1 }), 'course.v5.user.redeemClass');// 兑换课程
router.get('third', '/category/all', auth({ is_force: 0 }), 'course.v5.option.getCategoryList');// 获取分类列表
router.get('third', '/banner/all', 'course.v5.option.getBannerList');// 获取banner列表
......@@ -54,7 +56,7 @@ module.exports = app => {
router.get('third', '/search/recommend', auth({ is_force: 0 }), 'course.v5.institution.getSearchRecommend');// 搜索联想
router.get('third', '/search', auth({ is_force: 0 }), 'course.v5.institution.getSearch');// 搜索
router.get('third', '/video/all', auth({ is_force: 1 }), 'course.v5.institution.getVideoList');// 获取视频列表
router.get('third', '/video/all', auth({ is_force: 0 }), 'course.v5.institution.getVideoList');// 获取视频列表
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');// 获取课程首页
......
......@@ -5,6 +5,7 @@ const Service = require('egg').Service;
const uuidV4 = require('uuid/v4');
const moment = require('moment');
const R = require('ramda');
const _ = require('lodash');
class UserService extends Service {
// 发送验证码
......@@ -370,12 +371,18 @@ class UserService extends Service {
}
// 获取课程详情
const classInfo = await ctx.classModel.V5.CourseV5Class.findOne({ where: { id, status: 1, is_deleted: 0 }, attributions: [ 'name', 'pay_price' ] });
const classInfo = await ctx.classModel.V5.CourseV5Class.findOne({ where: { id, status: 1, is_deleted: 0 }, attributes: [ 'name', 'pay_price' ] });
if (ctx.isEmpty(classInfo)) {
ctx.failed('课程不存在');
}
const orderNo = '12' + moment().format('YYYYMMDDHHMMSS') + await this.getRandomNumber(6);
// 获取用户地址
const address = await ctx.classModel.V5.CourseUserAddress.findOne({ where: { user_uuid: ctx.userUuid, is_deleted: 0 }, attributes: [ 'province', 'city', 'area', 'address', 'name', 'phone' ], raw: true });
if (ctx.isEmpty(address)) {
ctx.failed('地址不能为空');
}
const orderNo = '11' + moment().format('YYYYMMDDHHMMSS') + await this.getRandomNumber(6);
if (ctx.isEmpty(order)) {
const data = {
order_no: orderNo,
......@@ -383,12 +390,13 @@ class UserService extends Service {
class_id: id,
pay: classInfo.pay_price,
type: 1,
address: JSON.stringify(address),
};
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, order_no: orderNo, type: 1, redeem: '', status: 0 }, { where: { id: order.id } });
await ctx.classModel.V5.CourseUserOrder.update({ pay: classInfo.pay_price, order_no: orderNo, type: 1, redeem: '', address: JSON.stringify(address), status: 0 }, { where: { id: order.id } });
let response = await this.service.course.v5.wechat.pay({ pay: order.pay, order_no: orderNo, body: `趣选课-订单${orderNo}` });
response = await ctx.helper.xmlTojson(response);
......@@ -427,8 +435,70 @@ class UserService extends Service {
const { ctx } = this;
const userUuid = ctx.userUuid;
const orderList = await ctx.classModel.V5.CourseUserOrder.findAll({ where: { user_uuid: userUuid, status: 1, is_deleted: 0 } });
const classList = await ctx.classModel.V5.CourseV5Class.findAll({ where: { id: { $in: R.pluck('class_id', orderList) } } });
const orderList = await ctx.classModel.V5.CourseUserOrder.findAll({ where: { user_uuid: userUuid, status: 1, is_deleted: 0 }, order: [[ 'id', 'desc' ]] });
let classList = await ctx.classModel.V5.CourseV5Class.findAll({ where: { id: { $in: R.pluck('class_id', orderList) } }, attributes: [ 'id', 'name', 'logo' ], raw: true });
classList = _.groupBy(classList, 'id');
const results = [];
for (const v of orderList) {
results.push({
id: v.id,
order_no: v.order_no,
class_id: v.class_id,
class_name: ctx.isEmpty(classList[v.class_id]) ? '' : classList[v.class_id][0].name,
class_logo: ctx.isEmpty(classList[v.class_id]) ? '' : classList[v.class_id][0].logo,
});
}
const ret = {
list: results,
};
return ret;
}
// 兑换课程
async redeemClass(redeemCode) {
const { ctx } = this;
const userUuid = ctx.userUuid;
if (ctx.isEmpty(userUuid)) {
ctx.failed('用户异常');
}
ctx.logger.info('course_redeem_code: ' + redeemCode + ' ' + userUuid);
const codeInfo = await ctx.classModel.V5.CourseRedeemCode.findOne({ where: { code: redeemCode, status: 1, is_deleted: 0 } });
if (ctx.isEmpty(codeInfo)) {
ctx.failed('无效码');
}
if (codeInfo.is_used === 1) {
ctx.failed('兑换码已被使用');
}
// 获取用户地址
const address = await ctx.classModel.V5.CourseUserAddress.findOne({ where: { user_uuid: ctx.userUuid, is_deleted: 0 }, attributes: [ 'province', 'city', 'area', 'address', 'name', 'phone' ], raw: true });
if (ctx.isEmpty(address)) {
ctx.failed('地址不能为空');
}
// 订单处理
const orderInfo = await ctx.classModel.V5.CourseUserOrder.findOne({ where: { user_uuid: userUuid, class_id: codeInfo.class_id, is_deleted: 0 } });
if (ctx.isEmpty(orderInfo)) {
const orderNo = '12' + moment().format('YYYYMMDDHHMMSS') + await this.getRandomNumber(6);
await ctx.classModel.V5.CourseUserOrder.create({ user_uuid: userUuid, order_no: orderNo, class_id: codeInfo.class_id, pay: 0, pay_time: moment().format('YYYY-MM-DD HH:mm:ss'), pay_result: '', type: 2, redeem: redeemCode, address: JSON.stringify(address), status: 1 });
} else {
if (orderInfo.status === 1) {
ctx.failed('您已购买过该课程');
} else {
await ctx.classModel.V5.CourseUserOrder.update({ pay: 0, pay_time: moment().format('YYYY-MM-DD HH:mm:ss'), pay_result: '', type: 2, redeem: redeemCode, address: JSON.stringify(address), status: 1 }, { where: { id: orderInfo.id } });
}
}
await ctx.classModel.V5.CourseRedeemCode.update({ user_uuid: userUuid, is_used: 1 }, { where: { id: codeInfo.id } });
return { class_id: codeInfo.class_id };
}
}
......
......@@ -352,6 +352,7 @@ class WechatService extends Service {
xmlData += '</xml>';
ctx.logger.info('course_wechat_pay_params: ' + xmlData);
await ctx.classModel.V5.CourseWechatLog.create({ type: 1, content: xmlData });
let ret = await new Promise((resolve, reject) => {
request({ url: 'https://api.mch.weixin.qq.com/pay/unifiedorder', method: 'POST', body: xmlData }, function(err, response, body) {
if (!err && response.statusCode === 200) {
......@@ -363,6 +364,7 @@ class WechatService extends Service {
});
});
await ctx.classModel.V5.CourseWechatLog.create({ type: 2, content: ret });
ret = ret.replace(/^\ufeff/i, '').replace(/^\ufffe/i, '');
return ret;
}
......
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