|
@@ -2,25 +2,22 @@ package com.ym.mec.biz.service.impl;
|
|
|
|
|
|
import com.alibaba.fastjson.JSON;
|
|
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|
|
-import com.ym.mec.auth.api.client.SysUserFeignService;
|
|
|
-import com.ym.mec.auth.api.entity.SysUser;
|
|
|
import com.ym.mec.biz.dal.dao.TenantAssetsInfoDao;
|
|
|
import com.ym.mec.biz.dal.entity.*;
|
|
|
import com.ym.mec.biz.dal.entity.TenantConfigDetail.CloudRoomRule;
|
|
|
import com.ym.mec.biz.dal.enums.TeachModeEnum;
|
|
|
+import com.ym.mec.biz.dal.vo.TenantCloudCourseRecordVo;
|
|
|
import com.ym.mec.biz.service.TenantAssetsInfoService;
|
|
|
import com.ym.mec.biz.service.TenantCloudCourseRecordService;
|
|
|
import com.ym.mec.biz.service.TenantConfigService;
|
|
|
import com.ym.mec.common.exception.BizException;
|
|
|
import com.ym.mec.common.page.WrapperUtil;
|
|
|
-import com.ym.mec.common.tenant.TenantContextHolder;
|
|
|
import com.ym.mec.thirdparty.yqpay.DateUtils;
|
|
|
import org.apache.commons.collections.CollectionUtils;
|
|
|
import org.slf4j.Logger;
|
|
|
import org.slf4j.LoggerFactory;
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
import org.springframework.stereotype.Service;
|
|
|
-import org.springframework.transaction.annotation.Transactional;
|
|
|
|
|
|
import java.math.BigDecimal;
|
|
|
import java.math.MathContext;
|
|
@@ -43,151 +40,124 @@ public class TenantAssetsInfoServiceImpl extends ServiceImpl<TenantAssetsInfoDao
|
|
|
@Autowired
|
|
|
private TenantConfigService tenantConfigService;
|
|
|
@Autowired
|
|
|
- private SysUserFeignService sysUserFeignService;
|
|
|
- @Autowired
|
|
|
private TenantCloudCourseRecordService tenantCloudCourseRecordService;
|
|
|
|
|
|
/**
|
|
|
- * 课程
|
|
|
- * 扣除冻结的金额
|
|
|
+ * 手动执行未扣费的流水
|
|
|
*
|
|
|
- * @param courseId 课程id
|
|
|
+ * @param ids 流水表id集合
|
|
|
*/
|
|
|
- @Override
|
|
|
- @Transactional(rollbackFor = Exception.class)
|
|
|
- public void courseDeductAmount(Integer courseId) {
|
|
|
- TenantCloudCourseRecord lastRecord = checkLastRecord(courseId);
|
|
|
- if (Objects.isNull(lastRecord)) {
|
|
|
+ public void manualDeductAmount(List<Integer> ids) {
|
|
|
+ if (CollectionUtils.isEmpty(ids)) {
|
|
|
return;
|
|
|
}
|
|
|
- //写入流水
|
|
|
- lastRecord.setDeductState(1);
|
|
|
- tenantCloudCourseRecordService.save(lastRecord);
|
|
|
- if (baseMapper.deductAmount(lastRecord.getAmount()) != 1) {
|
|
|
- throw new BizException("解除冻结金额失败!");
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 课程
|
|
|
- * 恢复/取消 冻结的金额
|
|
|
- *
|
|
|
- * @param courseId 课程id
|
|
|
- */
|
|
|
- @Override
|
|
|
- @Transactional(rollbackFor = Exception.class)
|
|
|
- public void courseRecoverAmount(Integer courseId) {
|
|
|
- TenantCloudCourseRecord lastRecord = checkLastRecord(courseId);
|
|
|
- if (Objects.isNull(lastRecord)) {
|
|
|
+ List<TenantCloudCourseRecordVo> records = tenantCloudCourseRecordService.queryList(new HashMap<String, Object>() {{
|
|
|
+ put("ids", ids);
|
|
|
+ put("deductState", 3);
|
|
|
+ }});
|
|
|
+ if (CollectionUtils.isEmpty(records)) {
|
|
|
return;
|
|
|
}
|
|
|
- //写入流水
|
|
|
- lastRecord.setDeductState(2);
|
|
|
- tenantCloudCourseRecordService.save(lastRecord);
|
|
|
- //解除冻结金额,恢复余额
|
|
|
- if (baseMapper.recoverAmount(lastRecord.getAmount()) != 1) {
|
|
|
- throw new BizException("解除冻结金额失败!");
|
|
|
- }
|
|
|
- }
|
|
|
+ records.forEach(record -> {
|
|
|
+ log.info("manualDeductAmount >>>>>> {}", record);
|
|
|
+ //获取总人数 ,+1是算上老师
|
|
|
+ Integer totalPeople = record.getStudentNum() + 1;
|
|
|
+ //获取云教室规则 String人数-BigDecimal每分钟扣费标准
|
|
|
+ Map<String, BigDecimal> rule = getRule(record.getTenantId());
|
|
|
+ if (Objects.isNull(rule)) {
|
|
|
+ throw new BizException("未查询到该机构的课程收费标准!");
|
|
|
+ }
|
|
|
+ //获取每分钟扣费标准
|
|
|
+ BigDecimal minutePrice = rule.get(String.valueOf(totalPeople));
|
|
|
+ if (Objects.isNull(minutePrice)) {
|
|
|
+ throw new BizException("未查到 [" + totalPeople + "人(含老师)] 的课程收费标准!");
|
|
|
+ }
|
|
|
+ //计算总上课时间
|
|
|
+ BigDecimal courseDate = getCourseDate(record.getClassDate(), record.getStartClassTime(), record.getEndClassTime());
|
|
|
+ //课程总价 = 每分钟扣费标准 * 总上课时间
|
|
|
+ BigDecimal coursePrice = minutePrice.multiply(courseDate, new MathContext(2, RoundingMode.HALF_UP));
|
|
|
+ //修改流水
|
|
|
+ TenantCloudCourseRecord sourceCord = new TenantCloudCourseRecord();
|
|
|
+ sourceCord.setId(record.getId());
|
|
|
+ sourceCord.setAmount(coursePrice);
|
|
|
+ sourceCord.setDeductState(1);
|
|
|
+ tenantCloudCourseRecordService.updateById(sourceCord);
|
|
|
+ //扣余额
|
|
|
+ if (baseMapper.checkDeductAmount(coursePrice, record.getTenantId()) == 0) {
|
|
|
+ throw new BizException("余额不足!");
|
|
|
+ }
|
|
|
+ });
|
|
|
|
|
|
- private TenantCloudCourseRecord checkLastRecord(Integer courseId) {
|
|
|
- TenantCloudCourseRecord lastRecord = tenantCloudCourseRecordService.queryLastRecord(courseId);
|
|
|
- if (Objects.isNull(lastRecord)) {
|
|
|
- return null;
|
|
|
- }
|
|
|
- //判断是否是冻结的状态
|
|
|
- if (lastRecord.getDeductState() != 0) {
|
|
|
- //只有冻结的才能取消冻结 或者 扣费
|
|
|
- throw new BizException("该课程非线上课!");
|
|
|
- }
|
|
|
- lastRecord.setCreatedBy(getUserId());
|
|
|
- lastRecord.setCreatedTime(new Date());
|
|
|
- return lastRecord;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
- * 课程组金额冻结
|
|
|
+ * 上课时间到了后扣除账户余额,可以为负数
|
|
|
*
|
|
|
- * @param vipGroup 课程组信息
|
|
|
- * @param dto 课程组中的课程
|
|
|
- */
|
|
|
- @Override
|
|
|
- @Transactional(rollbackFor = Exception.class)
|
|
|
- public void groupFrozenAmount(VipGroup vipGroup, List<CourseSchedule> dto) {
|
|
|
-
|
|
|
- }
|
|
|
-
|
|
|
- /**
|
|
|
- * 冻结课程的总价格
|
|
|
- * 1.线上排课计算出的总价格不能超过账户余额(注意多人同时操作账户余额多扣问题)
|
|
|
- * 2.若符合规则冻结部分账户
|
|
|
+ * @param dto 课程集合
|
|
|
*/
|
|
|
- @Override
|
|
|
- @Transactional(rollbackFor = Exception.class)
|
|
|
- public void courseFrozenAmount(List<CourseSchedule> dto) {
|
|
|
- Integer tenantId = TenantContextHolder.getTenantId();
|
|
|
-
|
|
|
+ public void deductAmount(List<CourseSchedule> dto) {
|
|
|
//校验课程 筛选出线上课
|
|
|
dto = getOnlineCourse(dto);
|
|
|
if (CollectionUtils.isEmpty(dto)) {
|
|
|
return;
|
|
|
}
|
|
|
-
|
|
|
- TenantAssetsInfo assetsInfo = this.getOne(new WrapperUtil<TenantAssetsInfo>()
|
|
|
- .hasEq("tenant_id_", tenantId).queryWrapper());
|
|
|
- if (Objects.isNull(assetsInfo)) {
|
|
|
- throw new BizException("未查询到该账户资产信息!");
|
|
|
- }
|
|
|
-
|
|
|
- //获取云教室规则 String人数-BigDecimal每分钟扣费标准
|
|
|
- Map<String, BigDecimal> rule = getRule(tenantId);
|
|
|
- BigDecimal frozenAmount = BigDecimal.ZERO;
|
|
|
-
|
|
|
- for (CourseSchedule course : dto) {
|
|
|
- TenantCloudCourseRecord lastRecord = tenantCloudCourseRecordService.queryLastRecord(course.getId().intValue());
|
|
|
- if (Objects.nonNull(lastRecord) && lastRecord.getDeductState() == 0) {
|
|
|
- //该课程id最后一条记录也是冻结状态
|
|
|
- throw new BizException("该课程已是线上课!");
|
|
|
+ //开始扣费
|
|
|
+ dto.forEach(course -> {
|
|
|
+ log.info("deductAmount >>>>>> {}", course);
|
|
|
+ if (Objects.isNull(course.getTenantId())) {
|
|
|
+ return;
|
|
|
}
|
|
|
-
|
|
|
//获取总人数 ,+1是算上老师
|
|
|
Integer totalPeople = course.getStudentNum() + 1;
|
|
|
+ //获取云教室规则 String人数-BigDecimal每分钟扣费标准
|
|
|
+ Map<String, BigDecimal> rule = getRule(course.getTenantId());
|
|
|
+ if (Objects.isNull(rule)) {
|
|
|
+ //没有这个扣费标准,写未扣费流水记录
|
|
|
+ insertRecord(course, BigDecimal.ZERO, 3);
|
|
|
+ return;
|
|
|
+ }
|
|
|
//获取每分钟扣费标准
|
|
|
BigDecimal minutePrice = rule.get(String.valueOf(totalPeople));
|
|
|
if (Objects.isNull(minutePrice)) {
|
|
|
- //没有这个扣费标准
|
|
|
- throw new BizException("课程人数已达上限,请联系教务老师!");
|
|
|
+ //没有这个扣费标准,写未扣费流水记录
|
|
|
+ insertRecord(course, BigDecimal.ZERO, 3);
|
|
|
+ return;
|
|
|
}
|
|
|
//计算总上课时间
|
|
|
- BigDecimal courseDate = getCourseDate(course);
|
|
|
- //课程单价 = 每分钟扣费标准 * 总上课时间
|
|
|
+ BigDecimal courseDate = getCourseDate(course.getClassDate(), course.getStartClassTime(), course.getEndClassTime());
|
|
|
+ //课程总价 = 每分钟扣费标准 * 总上课时间
|
|
|
BigDecimal coursePrice = minutePrice.multiply(courseDate, new MathContext(2, RoundingMode.HALF_UP));
|
|
|
- frozenAmount = frozenAmount.add(coursePrice);
|
|
|
-
|
|
|
- //写入流水
|
|
|
- TenantCloudCourseRecord record = new TenantCloudCourseRecord();
|
|
|
- record.setCourseId(course.getId().intValue());
|
|
|
- record.setAmount(coursePrice);
|
|
|
- record.setTenantId(tenantId);
|
|
|
- record.setDeductState(0);
|
|
|
- record.setCreatedBy(getUserId());
|
|
|
- record.setCreatedTime(new Date());
|
|
|
- tenantCloudCourseRecordService.save(record);
|
|
|
- }
|
|
|
+ //写流水
|
|
|
+ insertRecord(course, coursePrice, 1);
|
|
|
+ //扣余额
|
|
|
+ baseMapper.deductAmount(coursePrice, course.getTenantId());
|
|
|
+ });
|
|
|
|
|
|
- //直接修改余额,利用数据库的规则来防ABA的出现
|
|
|
- if (baseMapper.frozenAmount(frozenAmount) != 1) {
|
|
|
- //可能是余额不足
|
|
|
- throw new BizException("线上课预约火爆,请联系教务老师!");
|
|
|
- }
|
|
|
+ }
|
|
|
|
|
|
+ /**
|
|
|
+ * 写入流水
|
|
|
+ *
|
|
|
+ * @param course 课程
|
|
|
+ * @param coursePrice 课程总价
|
|
|
+ * @param state 扣费状态 1扣费 3未扣费
|
|
|
+ */
|
|
|
+ private void insertRecord(CourseSchedule course, BigDecimal coursePrice, Integer state) {
|
|
|
+ //写入流水
|
|
|
+ TenantCloudCourseRecord record = new TenantCloudCourseRecord();
|
|
|
+ record.setCourseId(course.getId().intValue());
|
|
|
+ record.setTenantId(course.getTenantId());
|
|
|
+ record.setAmount(coursePrice);
|
|
|
+ record.setDeductState(state);
|
|
|
+ record.setCreatedTime(new Date());
|
|
|
+ tenantCloudCourseRecordService.save(record);
|
|
|
}
|
|
|
|
|
|
private List<CourseSchedule> getOnlineCourse(List<CourseSchedule> dto) {
|
|
|
- return Optional.ofNullable(dto)
|
|
|
- .filter(CollectionUtils::isNotEmpty)
|
|
|
- .orElseThrow(() -> new BizException("请传入课程数据!"))
|
|
|
- .stream()
|
|
|
+ if (CollectionUtils.isEmpty(dto)) {
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ return dto.stream()
|
|
|
.filter(c -> c.getTeachMode().equals(TeachModeEnum.ONLINE))
|
|
|
.collect(Collectors.toList());
|
|
|
}
|
|
@@ -197,41 +167,35 @@ public class TenantAssetsInfoServiceImpl extends ServiceImpl<TenantAssetsInfoDao
|
|
|
TenantConfig tenantConfig = tenantConfigService.getOne(new WrapperUtil<TenantConfig>()
|
|
|
.hasEq("tenant_id_", tenantId).queryWrapper());
|
|
|
if (Objects.isNull(tenantConfig)) {
|
|
|
- throw new BizException("未查询到云教室规则信息!");
|
|
|
+ return null;
|
|
|
}
|
|
|
return Optional.ofNullable(tenantConfig.getConfig())
|
|
|
.map(c -> JSON.parseObject(c, TenantConfigDetail.class))
|
|
|
.map(TenantConfigDetail::getCloud_room_rule)
|
|
|
.map(CloudRoomRule::getCloud_room_config)
|
|
|
- .orElseThrow(() -> new BizException("未查询到云教室规则!"));
|
|
|
+ .orElse(null);
|
|
|
}
|
|
|
|
|
|
- private BigDecimal getCourseDate(CourseSchedule course) {
|
|
|
- String date = DateUtils.formatDate(course.getClassDate(), DateUtils.YYYY_MM_DD_DEF);
|
|
|
- Date startDT = getDateTime(date, course.getStartClassTime());
|
|
|
- Date endDT = getDateTime(date, course.getEndClassTime());
|
|
|
- //课程结束时间-课程开始时间
|
|
|
- long durationTime = endDT.getTime() - startDT.getTime();
|
|
|
- //相差多少分钟
|
|
|
- int durationMinute = new Long(durationTime / 1000 / 60).intValue();
|
|
|
- return BigDecimal.valueOf(durationMinute);
|
|
|
- }
|
|
|
-
|
|
|
- private Date getDateTime(String dateStr, Date time) {
|
|
|
- String timeStr = DateUtils.formatDate(time, "HH:mm:ss");
|
|
|
- String s = dateStr + " " + timeStr;
|
|
|
+ private BigDecimal getCourseDate(Date date, Date startTime, Date endTime) {
|
|
|
+ String dateStr = DateUtils.formatDate(date, DateUtils.YYYY_MM_DD_DEF);
|
|
|
+ int durationMinute = 0;
|
|
|
try {
|
|
|
- return DateUtils.parseDate(s, DateUtils.DATE_WEB_FORMAT);
|
|
|
+ Date startDT = getDateTime(dateStr, startTime);
|
|
|
+ Date endDT = getDateTime(dateStr, endTime);
|
|
|
+ //课程结束时间-课程开始时间
|
|
|
+ long durationTime = endDT.getTime() - startDT.getTime();
|
|
|
+ //相差多少分钟
|
|
|
+ durationMinute = new Long(durationTime / 1000 / 60).intValue();
|
|
|
} catch (ParseException e) {
|
|
|
- throw new BizException("课程时间格式错误!");
|
|
|
+ log.error("deductAmount >>>>>> 计算时间出错 : {} {} {}", date, startTime, endTime);
|
|
|
}
|
|
|
+ return BigDecimal.valueOf(durationMinute);
|
|
|
}
|
|
|
|
|
|
- private Integer getUserId() {
|
|
|
- //修改机构基础信息
|
|
|
- return Optional.ofNullable(sysUserFeignService.queryUserInfo())
|
|
|
- .map(SysUser::getId)
|
|
|
- .orElseThrow(() -> new BizException("用户信息获取失败,请刷新页面或者重新登录!"));
|
|
|
+ private Date getDateTime(String dateStr, Date time) throws ParseException {
|
|
|
+ String timeStr = DateUtils.formatDate(time, "HH:mm:ss");
|
|
|
+ String s = dateStr + " " + timeStr;
|
|
|
+ return DateUtils.parseDate(s, DateUtils.DATE_WEB_FORMAT);
|
|
|
}
|
|
|
|
|
|
}
|