|
@@ -3,6 +3,8 @@ const { CrudService } = require('naf-framework-mongoose-free/lib/service');
|
|
const { BusinessError, ErrorCode } = require('naf-core').Error;
|
|
const { BusinessError, ErrorCode } = require('naf-core').Error;
|
|
const _ = require('lodash');
|
|
const _ = require('lodash');
|
|
const assert = require('assert');
|
|
const assert = require('assert');
|
|
|
|
+const Transaction = require('mongoose-transactions');
|
|
|
|
+const moment = require('moment');
|
|
|
|
|
|
//
|
|
//
|
|
class LessonService extends CrudService {
|
|
class LessonService extends CrudService {
|
|
@@ -12,6 +14,12 @@ class LessonService extends CrudService {
|
|
this.lessonCoachModel = this.ctx.model.Business.LessonCoach;
|
|
this.lessonCoachModel = this.ctx.model.Business.LessonCoach;
|
|
this.lessonStudentModel = this.ctx.model.Business.LessonStudent;
|
|
this.lessonStudentModel = this.ctx.model.Business.LessonStudent;
|
|
this.coachInBillService = this.ctx.service.business.coachInBill;
|
|
this.coachInBillService = this.ctx.service.business.coachInBill;
|
|
|
|
+ this.lessonStudentModel = this.ctx.model.Business.LessonStudent;
|
|
|
|
+ this.tempLessonApplyModel = this.ctx.model.Apply.TempLessonApply;
|
|
|
|
+ this.rssModel = this.ctx.model.Relation.RelationStudentSchool;
|
|
|
|
+ this.payOrderModel = this.ctx.model.Business.PayOrder;
|
|
|
|
+ this.payService = this.ctx.service.wxpay;
|
|
|
|
+ this.tran = new Transaction();
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -24,39 +32,169 @@ class LessonService extends CrudService {
|
|
async afterUpdate(filter, body, data) {
|
|
async afterUpdate(filter, body, data) {
|
|
const { _id: lesson_id, type, status, school_id } = data;
|
|
const { _id: lesson_id, type, status, school_id } = data;
|
|
if (status !== '4') return data;
|
|
if (status !== '4') return data;
|
|
|
|
+ if (status === '-1') {
|
|
|
|
+ await this.refundThisLesson(data);
|
|
|
|
+ return data;
|
|
|
|
+ }
|
|
const arr = [];
|
|
const arr = [];
|
|
|
|
|
|
- if (type === '0') {
|
|
|
|
- // 公开课,每个教师都带着自己的金额. 按 人头数 * 单价 算钱
|
|
|
|
- const lessonCoachList = await this.lessonCoachModel.find({ lesson_id });
|
|
|
|
- // 这节课付了款的学生总数
|
|
|
|
- const studentNum = await this.lessonStudentModel.count({ lesson_id, is_pay: '1' });
|
|
|
|
- const obj = { lesson_id, type, school_id };
|
|
|
|
- for (const c of lessonCoachList) {
|
|
|
|
- const { coach_id, money } = c;
|
|
|
|
- const total = money * studentNum;
|
|
|
|
- arr.push({ ...obj, coach_id, money: total });
|
|
|
|
|
|
+ // if (type === '0') {
|
|
|
|
+ // // 公开课,每个教师都带着自己的金额. 按 人头数 * 单价 算钱
|
|
|
|
+ // const lessonCoachList = await this.lessonCoachModel.find({ lesson_id });
|
|
|
|
+ // // 这节课付了款的学生总数
|
|
|
|
+ // const studentNum = await this.lessonStudentModel.count({ lesson_id, is_pay: '1' });
|
|
|
|
+ // const obj = { lesson_id, type, school_id };
|
|
|
|
+ // for (const c of lessonCoachList) {
|
|
|
|
+ // const { coach_id, money } = c;
|
|
|
|
+ // const total = money * studentNum;
|
|
|
|
+ // arr.push({ ...obj, coach_id, money: total });
|
|
|
|
+ // }
|
|
|
|
+ // } else {
|
|
|
|
+ // // 私教课, 按学生实际缴费
|
|
|
|
+ // const lessonCoach = await this.lessonCoachModel.findOne({ lesson_id });
|
|
|
|
+ // const studentList = await this.lessonStudentModel.find({ lesson_id });
|
|
|
|
+ // const obj = { lesson_id, type, school_id };
|
|
|
|
+ // obj.coach_id = lessonCoach.coach_id;
|
|
|
|
+ // const total = studentList.reduce((p, n) => p + (n.money || 0), 0);
|
|
|
|
+ // obj.money = total;
|
|
|
|
+ // arr.push(obj);
|
|
|
|
+ // }
|
|
|
|
+ // // 创建,如果有该学校,这节课的这个教练已经有数据了,就不需要生成了
|
|
|
|
+ // for (const i of arr) {
|
|
|
|
+ // try {
|
|
|
|
+ // await this.coachInBillService.create(i);
|
|
|
|
+ // } catch (error) {
|
|
|
|
+ // // 不是数据有问题,就是有数据了,要不一般不会出错
|
|
|
|
+ // }
|
|
|
|
+ // }
|
|
|
|
+
|
|
|
|
+ return data;
|
|
|
|
+ }
|
|
|
|
+ /**
|
|
|
|
+ * 退课,退款(能退到账户余额就退到账户余额,不能的就直接走退款接口)
|
|
|
|
+ * @param {Lesson} lesson 课程信息
|
|
|
|
+ */
|
|
|
|
+ async refundThisLesson(lesson) {
|
|
|
|
+ const lesson_id = _.get(lesson, '_id');
|
|
|
|
+ if (!lesson_id) return;
|
|
|
|
+ try {
|
|
|
|
+ // 取出学生id,支付单id,缴费金额
|
|
|
|
+ const studentList = await this.lessonStudentModel.find({ lesson_id, is_pay: '1', is_try: '0' }, 'student_id, pay_id, money, school_id');
|
|
|
|
+ for (const s of studentList) {
|
|
|
|
+ // 修改支付状态,返回金额
|
|
|
|
+ const r = await this.refundByRrs(s, this.tran);
|
|
|
|
+ // 没有关系,那就直接去用支付订单退款
|
|
|
|
+ if (!r) await this.refundByPayOrder(s, this.tran);
|
|
}
|
|
}
|
|
- } else {
|
|
|
|
- // 私教课, 按学生实际缴费
|
|
|
|
- const lessonCoach = await this.lessonCoachModel.findOne({ lesson_id });
|
|
|
|
- const studentList = await this.lessonStudentModel.find({ lesson_id });
|
|
|
|
- const obj = { lesson_id, type, school_id };
|
|
|
|
- obj.coach_id = lessonCoach.coach_id;
|
|
|
|
- const total = studentList.reduce((p, n) => p + (n.money || 0), 0);
|
|
|
|
- obj.money = total;
|
|
|
|
- arr.push(obj);
|
|
|
|
- }
|
|
|
|
- // 创建,如果有该学校,这节课的这个教练已经有数据了,就不需要生成了
|
|
|
|
- for (const i of arr) {
|
|
|
|
- try {
|
|
|
|
- await this.coachInBillService.create(i);
|
|
|
|
- } catch (error) {
|
|
|
|
- // 不是数据有问题,就是有数据了,要不一般不会出错
|
|
|
|
|
|
+ const tempLessonList = await this.tempLessonApplyModel.find({ lesson_id, is_pay: '1' }, 'student_id, school_id, money,pay_id,');
|
|
|
|
+ for (const t of tempLessonList) {
|
|
|
|
+ // 如果有学生id,说明是有账号的,退余额
|
|
|
|
+ const r = await this.refundByTempLesson(t, this.tran);
|
|
|
|
+ // 没有学生id,需要原路返回
|
|
|
|
+ if (!r) await this.refundByPayOrder(t, this.tran);
|
|
}
|
|
}
|
|
|
|
+ await this.tran.run();
|
|
|
|
+ } catch (error) {
|
|
|
|
+ await this.tran.rollback();
|
|
|
|
+ console.error(error);
|
|
|
|
+ } finally {
|
|
|
|
+ this.tran.clean();
|
|
}
|
|
}
|
|
|
|
+ }
|
|
|
|
+ /**
|
|
|
|
+ * 退款至余额
|
|
|
|
+ * @param {Object} lessonStudent 学生上课报名信息
|
|
|
|
+ * @param {Transaction} tran 数据库事务
|
|
|
|
+ */
|
|
|
|
+ async refundByRrs(lessonStudent, tran) {
|
|
|
|
+ const { school_id, student_id, pay_id, money, _id } = lessonStudent;
|
|
|
|
+ const rss = await this.rssModel.find({ school_id, student_id });
|
|
|
|
+ if (!rss) return false;
|
|
|
|
+ const surplus = _.get(rss, 'money');
|
|
|
|
+ const newMoney = this.ctx.plus(surplus, money);
|
|
|
|
+ // 退款
|
|
|
|
+ tran.update('RelationStudentSchool', rss._id, { money: newMoney });
|
|
|
|
+ // 改状态
|
|
|
|
+ tran.update('LessonStudent', lessonStudent._id, { is_pay: '-3' });
|
|
|
|
+ tran.update('PayOrder', pay_id, { is_pay: '-3' });
|
|
|
|
+ // 生成账单数据
|
|
|
|
+ const billData = {
|
|
|
|
+ school_id,
|
|
|
|
+ payer_id: student_id,
|
|
|
|
+ payer_role: 'Student',
|
|
|
|
+ pay_for: 'LessonStudent',
|
|
|
|
+ from_id: _id,
|
|
|
|
+ type: '2',
|
|
|
|
+ pay_id,
|
|
|
|
+ is_pay: '1',
|
|
|
|
+ time: moment().format('YYYY-MM-DD HH:mm:ss'),
|
|
|
|
+ money,
|
|
|
|
+ };
|
|
|
|
+ tran.insert('Bill', billData);
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
+ /**
|
|
|
|
+ * 退临时上课申请至余额
|
|
|
|
+ * @param {Object} tempLessonApply 临时上课申请数据
|
|
|
|
+ * @param {Transaction} tran 数据库事务
|
|
|
|
+ */
|
|
|
|
+ async refundByTempLesson(tempLessonApply, tran) {
|
|
|
|
+ const { school_id, student_id, pay_id, money, _id } = tempLessonApply;
|
|
|
|
+ if (!student_id) return false;
|
|
|
|
+ const rss = await this.rssModel.find({ school_id, student_id });
|
|
|
|
+ if (!rss) return false;
|
|
|
|
+ const surplus = _.get(rss, 'money');
|
|
|
|
+ const newMoney = this.ctx.plus(surplus, money);
|
|
|
|
+ // 退款
|
|
|
|
+ tran.update('RelationStudentSchool', rss._id, { money: newMoney });
|
|
|
|
+ // 改状态
|
|
|
|
+ tran.update('TempLessonApply', _id, { is_pay: '-3' });
|
|
|
|
+ tran.update('PayOrder', pay_id, { is_pay: '-3' });
|
|
|
|
+ // 生成账单数据
|
|
|
|
+ const billData = {
|
|
|
|
+ school_id,
|
|
|
|
+ payer_id: student_id,
|
|
|
|
+ payer_role: 'Student',
|
|
|
|
+ pay_for: 'TempLessonApply',
|
|
|
|
+ from_id: _id,
|
|
|
|
+ type: '2',
|
|
|
|
+ pay_id,
|
|
|
|
+ is_pay: '1',
|
|
|
|
+ time: moment().format('YYYY-MM-DD HH:mm:ss'),
|
|
|
|
+ money,
|
|
|
|
+ };
|
|
|
|
+ tran.insert('Bill', billData);
|
|
|
|
+ return true;
|
|
|
|
+ }
|
|
|
|
|
|
- return data;
|
|
|
|
|
|
+ /**
|
|
|
|
+ * 原路退款, 因为没有关系,才走原路退款的,所以别查关系了,没有滴
|
|
|
|
+ * @param {Object} data 学生上课报名信息
|
|
|
|
+ * @param {Transaction} tran 数据库事务
|
|
|
|
+ */
|
|
|
|
+ async refundByPayOrder(data, tran) {
|
|
|
|
+ const { pay_id, school_id } = data;
|
|
|
|
+ const payOrder = await this.payOrderModel.findById(pay_id);
|
|
|
|
+ if (!payOrder) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到支付单信息');
|
|
|
|
+ const order_no = _.get(data, 'order_no');
|
|
|
|
+ const pay_for = _.get(payOrder, 'pay_for');
|
|
|
|
+ const from_id = _.get(payOrder, 'from_id');
|
|
|
|
+ if (!order_no) throw new BusinessError(ErrorCode.DATA_NOT_EXIST, '未找到支付单号');
|
|
|
|
+ await this.payService.refund(order_no, '课程取消');
|
|
|
|
+ // 修改状态
|
|
|
|
+ tran.update('PayOrder', pay_id, { is_pay: '-3' });
|
|
|
|
+ tran.update(pay_for, from_id, { is_pay: '-3' });
|
|
|
|
+ // 生成账单
|
|
|
|
+ const billData = {
|
|
|
|
+ school_id,
|
|
|
|
+ pay_for,
|
|
|
|
+ from_id,
|
|
|
|
+ type: '2',
|
|
|
|
+ pay_id,
|
|
|
|
+ is_pay: '1',
|
|
|
|
+ time: moment().format('YYYY-MM-DD HH:mm:ss'),
|
|
|
|
+ };
|
|
|
|
+ tran.insert('Bill', billData);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|