package com.ym.mec.biz.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.ym.mec.auth.api.client.SysUserFeignService;
import com.ym.mec.auth.api.entity.SysUser;
import com.ym.mec.auth.api.entity.SysUserRole;
import com.ym.mec.auth.api.enums.CertificateTypeEnum;
import com.ym.mec.biz.dal.dao.*;
import com.ym.mec.biz.dal.dto.*;
import com.ym.mec.biz.dal.entity.*;
import com.ym.mec.biz.dal.entity.StudentApplyRefunds.StudentApplyRefundsStatus;
import com.ym.mec.biz.dal.enums.*;
import com.ym.mec.biz.dal.page.*;
import com.ym.mec.biz.service.*;
import com.ym.mec.common.constant.CommonConstants;
import com.ym.mec.common.dal.BaseDAO;
import com.ym.mec.common.entity.ImGroupMember;
import com.ym.mec.common.entity.ImGroupModel;
import com.ym.mec.common.exception.BizException;
import com.ym.mec.common.page.PageInfo;
import com.ym.mec.common.service.IdGeneratorService;
import com.ym.mec.common.service.impl.BaseServiceImpl;
import com.ym.mec.im.ImFeignService;
import com.ym.mec.thirdparty.message.MessageSenderPluginContext;
import com.ym.mec.util.collection.MapUtil;
import com.ym.mec.util.date.DateUtil;
import com.ym.mec.util.string.MessageFormatter;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class VipGroupServiceImpl extends BaseServiceImpl<Long, VipGroup> implements VipGroupService {

	@Autowired
	private VipGroupDao vipGroupDao;
	@Autowired
	private ClassGroupDao classGroupDao;
	@Autowired
	private ClassGroupTeacherMapperDao classGroupTeacherMapperDao;
	@Autowired
	@Lazy
	private CourseScheduleService courseScheduleService;
	@Autowired
	private CourseScheduleDao courseScheduleDao;
	@Autowired
	private VipGroupDefaultClassesUnitPriceDao vipGroupDefaultClassesUnitPriceDao;
	@Autowired
	private VipGroupActivityDao vipGroupActivityDao;
	@Autowired
	private VipGroupCategoryDao vipGroupCategoryDao;
	@Autowired
	private MusicGroupDao musicGroupDao;
    @Autowired
    private SysUserFeignService sysUserFeignService;
    @Autowired
    private TeacherDefaultVipGroupSalaryDao teacherDefaultVipGroupSalaryDao;
    @Autowired
    private StudentPaymentOrderDao studentPaymentOrderDao;
    @Autowired
	private StudentApplyRefundsDao studentApplyRefundsDao;
	@Autowired
	private SysUserCashAccountService sysUserCashAccountService;
    @Autowired
	private SysUserCashAccountDetailDao sysUserCashAccountDetailDao;
    @Autowired
	private ClassGroupTeacherSalaryDao classGroupTeacherSalaryDao;
    @Autowired
	private CourseScheduleStudentPaymentDao courseScheduleStudentPaymentDao;
    @Autowired
	private CourseScheduleTeacherSalaryDao courseScheduleTeacherSalaryDao;
    @Autowired
	private ImGroupMemberService imGroupMemberService;
    @Autowired
	private ImUserFriendService imUserFriendService;
    
    @Autowired
    private ImGroupService imGroupService;
    @Autowired
	private SubjectDao subjectDao;
    @Autowired
    @Lazy
	private CourseScheduleTeacherSalaryService courseScheduleTeacherSalaryService;
    @Autowired
	private CourseScheduleStudentPaymentService courseScheduleStudentPaymentService;
	@Autowired
	private PayService payService;
	@Autowired
	private ClassGroupStudentMapperDao classGroupStudentMapperDao;
	@Autowired
	private CourseScheduleRewardsRulesService courseScheduleRewardsRulesService;
	@Autowired
	private SysConfigDao sysConfigDao;
	@Autowired
	private SysUserCashAccountDetailService sysUserCashAccountDetailService;
	@Autowired
	private SysMessageService sysMessageService;
	@Autowired
	private VipGroupDefaultClassesCycleDao vipGroupDefaultClassesCycleDao;
	@Autowired
	private TeacherDao teacherDao;
	@Autowired
	private TeacherAttendanceDao teacherAttendanceDao;
	@Autowired
	private ClassGroupService classGroupService;
	@Autowired
	private StudentPaymentOrderService studentPaymentOrderService;
	@Autowired
	private ContractService contractService;
	@Autowired
    private TeacherService teacherService;
	@Autowired
	private StudentPauseInfoDao studentPauseInfoDao;
	@Autowired
	private IdGeneratorService idGeneratorService;
	@Autowired
	private StudentAttendanceDao studentAttendanceDao;
	@Autowired
	private EmployeeDao employeeDao;
	@Autowired
	private GroupDao groupDao;
	@Autowired
	private TeacherCourseRewardService teacherCourseRewardService;
	@Autowired
	private StudentDao studentDao;
	@Autowired
	private OrganizationDao organizationDao;
	@Autowired
	private GroupClassService groupClassService;
	@Autowired
	private StudentPaymentRouteOrderService studentPaymentRouteOrderService;

	private static final Logger LOGGER = LoggerFactory
			.getLogger(VipGroup.class);

	@Override
	public BaseDAO<Long, VipGroup> getDAO() {
		return vipGroupDao;
	}

	@Transactional(rollbackFor = Exception.class, isolation = Isolation.READ_COMMITTED)
	@Override
	public String createVipGroup(VipGroupApplyDto vipGroup) {

		if (Objects.isNull(vipGroup.getVipGroupApplyBaseInfo().getUserId())){
			throw new BizException("请选择指导老师");
		}

	    if(vipGroup.getCourseSchedules().size()!=(vipGroup.getVipGroupApplyBaseInfo().getOfflineClassesNum()+vipGroup.getVipGroupApplyBaseInfo().getOnlineClassesNum())){
	        throw new BizException("建课失败，当前课程存在未排课课程，请调整相关设置");
        }

		Map<TeachModeEnum, List<CourseSchedule>> courseScheduleGroup;
		try {
			courseScheduleGroup = vipGroup.getCourseSchedules().stream().collect(Collectors.groupingBy(CourseSchedule::getTeachMode));
		} catch (Exception e) {
			throw new BizException("教学模式错误");
		}

		if((Objects.isNull(courseScheduleGroup.get(TeachModeEnum.OFFLINE))&&vipGroup.getVipGroupApplyBaseInfo().getOfflineClassesNum()!=0)
				||(!Objects.isNull(courseScheduleGroup.get(TeachModeEnum.OFFLINE))&&(courseScheduleGroup.get(TeachModeEnum.OFFLINE).size()<vipGroup.getVipGroupApplyBaseInfo().getOfflineClassesNum()))){
	        throw new BizException("线下课课时数量安排有误");
        }

        if((Objects.isNull(courseScheduleGroup.get(TeachModeEnum.ONLINE))&&vipGroup.getVipGroupApplyBaseInfo().getOnlineClassesNum()!=0)
				||(!Objects.isNull(courseScheduleGroup.get(TeachModeEnum.ONLINE))&&(courseScheduleGroup.get(TeachModeEnum.ONLINE).size()<vipGroup.getVipGroupApplyBaseInfo().getOnlineClassesNum()))){
            throw new BizException("线上课课时数量安排有误");
        }

		if(vipGroup.getVipGroupApplyBaseInfo().getOfflineClassesNum()>0
			&&Objects.isNull(vipGroup.getVipGroupApplyBaseInfo().getTeacherSchoolId())){
			throw new BizException("请设置教学点");
		}

        String studentIds=vipGroup.getStudentIds();
		List<String> studentIdList=new ArrayList<>();

        if(StringUtils.isNotBlank(studentIds)){
			studentIdList = Arrays.asList(studentIds.split(","));
		}

        Date now=new Date();

		VipGroupApplyBaseInfoDto vipGroupApplyBaseInfoDto=vipGroup.getVipGroupApplyBaseInfo();

        if(Objects.isNull(vipGroupApplyBaseInfoDto.getOfflineClassesUnitPrice())
            &&Objects.isNull(vipGroupApplyBaseInfoDto.getOnlineClassesUnitPrice())){
            throw new BizException("请设置教师课酬");
        }

		if(StringUtils.isBlank(vipGroupApplyBaseInfoDto.getStudentIdList())){
			throw new BizException("请选择学员");
		}

        if(Objects.isNull(vipGroupApplyBaseInfoDto.getOnlineTeacherSalary())){
        	vipGroupApplyBaseInfoDto.setOnlineTeacherSalary(new BigDecimal(0));
		}

		if(Objects.isNull(vipGroupApplyBaseInfoDto.getOfflineTeacherSalary())){
			vipGroupApplyBaseInfoDto.setOfflineTeacherSalary(new BigDecimal(0));
		}

		//获取活动信息
		VipGroupActivity vipGroupActivity = vipGroupActivityDao.get(vipGroup.getVipGroupApplyBaseInfo().getVipGroupActivityId().intValue());
		Integer totalClassTimes=vipGroupApplyBaseInfoDto.getOnlineClassesNum()+vipGroupApplyBaseInfoDto.getOfflineClassesNum();
		//获取第一节课
		CourseSchedule firstCourseSchedule = vipGroup.getCourseSchedules().stream().min(Comparator.comparing(CourseSchedule::getStartClassTime)).get();
		//获取最后一节课
		CourseSchedule latestCourseSchedule = vipGroup.getCourseSchedules().stream().max(Comparator.comparing(CourseSchedule::getEndClassTime)).get();

		if(firstCourseSchedule.getStartClassTime().before(now)){
			throw new BizException("开课时间不能小于当前时间");
		}

		if(vipGroupApplyBaseInfoDto.getRegistrationStartTime().after(vipGroupApplyBaseInfoDto.getPaymentExpireDate())){
		    throw new BizException("报名开始时间必须在报名截至时间之前");
        }

		if(vipGroupApplyBaseInfoDto.getPaymentExpireDate().after(firstCourseSchedule.getStartClassTime())
            ||DateUtil.isSameDay(vipGroupApplyBaseInfoDto.getPaymentExpireDate(),firstCourseSchedule.getEndClassTime())){
		    throw new BizException("创建失败，报名截止时间必须在开课时间前一天");
        }

		//判断课程安排是否超出范围
		if(Objects.nonNull(vipGroupActivity.getCoursesEndTime())||Objects.nonNull(vipGroupActivity.getCoursesStartTime())){
			if(latestCourseSchedule.getEndClassTime().after(vipGroupActivity.getCoursesEndTime())
					||firstCourseSchedule.getStartClassTime().before(vipGroupActivity.getCoursesStartTime())){
				throw new BizException("课时安排时间超出范围!");
			}
		}else{
			VipGroupDefaultClassesCycle vipGroupDefaultClassesCycle = vipGroupDefaultClassesCycleDao.findByOrganAndClassTimes(totalClassTimes);

			if (vipGroupDefaultClassesCycle != null) {
				int month = DateUtil.monthsBetween(firstCourseSchedule.getStartClassTime(), latestCourseSchedule.getEndClassTime());
				if (month > vipGroupDefaultClassesCycle.getMonth()) {
					throw new BizException("课时安排时间超出范围!");
				}
			}
		}

		int repeatVipGroups = vipGroupDao.countUserRepeatVipGroupInCourseStartEndTime(vipGroupApplyBaseInfoDto.getUserId(), firstCourseSchedule.getStartClassTime(), latestCourseSchedule.getEndClassTime());
		if(repeatVipGroups>0){
			throw new BizException("请勿重复提交");
		}

		VipGroupCategory vipGroupCategory = vipGroupCategoryDao.get(vipGroupApplyBaseInfoDto.getVipGroupCategoryId());
		if(Objects.isNull(vipGroupCategory)){
			throw new BizException("课程形式不存在");
		}

		List<Integer> canBuyStudentIds = Arrays.stream(vipGroupApplyBaseInfoDto.getStudentIdList().split(",")).map(e -> Integer.valueOf(e)).collect(Collectors.toList());

		List<String> studentNames = studentDao.getStudentNames(canBuyStudentIds);

		//生成vip课信息
		List<String> bySubIds = subjectDao.findBySubIds(vipGroupApplyBaseInfoDto.getSubjectIdList());
		StringBuffer className=new StringBuffer(StringUtils.join(bySubIds,","));
		className.append(vipGroupCategory.getName());
		className.append(StringUtils.join(studentNames, ","));
		vipGroupApplyBaseInfoDto.setName(className.toString());

		//计算课程相关费用信息
		Map<String, BigDecimal> costInfo = countVipGroupPredictFee(vipGroupApplyBaseInfoDto,
				vipGroupApplyBaseInfoDto.getUserId(),
				vipGroupApplyBaseInfoDto.getOnlineClassesUnitPrice(),
				vipGroupApplyBaseInfoDto.getOfflineClassesUnitPrice());

//		BigDecimal offlineClassNum=new BigDecimal(vipGroupApplyBaseInfoDto.getOfflineClassesNum());
//		BigDecimal onlineClassNum=new BigDecimal(vipGroupApplyBaseInfoDto.getOnlineClassesNum());
//
//		if(vipGroupActivity.getType().equals(VipGroupActivityTypeEnum.GIVE_CLASS)){
//			if(vipGroupApplyBaseInfoDto.getGiveTeachMode()==TeachModeEnum.OFFLINE){
//				if(new BigDecimal(totalClassTimes).compareTo(new BigDecimal(vipGroupActivity.getAttribute1()))>-1){
//					offlineClassNum=offlineClassNum.subtract(new BigDecimal(vipGroupActivity.getAttribute2()));
//				}
//			}else if(vipGroupApplyBaseInfoDto.getGiveTeachMode()==TeachModeEnum.ONLINE){
//				if(new BigDecimal(totalClassTimes).compareTo(new BigDecimal(vipGroupActivity.getAttribute1()))>-1){
//					onlineClassNum=onlineClassNum.subtract(new BigDecimal(vipGroupActivity.getAttribute2()));
//				}
//			}else{
//				throw new BizException("请指定赠送课程类型!");
//			}
//		}

//		BigDecimal tempFee = costInfo.get("totalPrice").multiply(new BigDecimal(0.6));
//		BigDecimal totalSalary = vipGroupApplyBaseInfoDto.getOfflineTeacherSalary().multiply(offlineClassNum)
//				.add(vipGroupApplyBaseInfoDto.getOnlineTeacherSalary().multiply(onlineClassNum));
//		if(totalSalary.compareTo(tempFee)>0){
//			throw new BizException("教师总课酬不能高于课程总价60%");
//		}

        vipGroupApplyBaseInfoDto.setAuditStatus(AuditStatusEnum.PASS);

		//如果默认课酬与实际课酬不匹配则需要审批
		if(costInfo.get("offlineTeacherSalary").compareTo(vipGroupApplyBaseInfoDto.getOfflineTeacherSalary())<0||
			costInfo.get("onlineTeacherSalary").compareTo(vipGroupApplyBaseInfoDto.getOnlineTeacherSalary())<0
			&&StringUtils.isBlank(studentIds)){
			vipGroupApplyBaseInfoDto.setAuditStatus(AuditStatusEnum.ING);
		}

		vipGroupApplyBaseInfoDto.setTotalPrice(costInfo.get("totalPrice"));
		if(StringUtils.isNotBlank(studentIds)){
			vipGroupApplyBaseInfoDto.setStatus(VipGroupStatusEnum.PROGRESS);
		}else{
			vipGroupApplyBaseInfoDto.setStatus(VipGroupStatusEnum.APPLYING);
		}
        Teacher teacher = teacherService.get(vipGroupApplyBaseInfoDto.getUserId());
		if(Objects.isNull(teacher)){
		    throw new BizException("教师不存在");
        }
		if(Objects.isNull(teacher.getTeacherOrganId())){
		    throw new BizException("教师部门异常");
        }
//        vipGroupApplyBaseInfoDto.setOrganId(Integer.parseInt(teacher.getOrganId()));
		//开课时间为排课的第一节课的开始时间
		vipGroupApplyBaseInfoDto.setCourseStartDate(firstCourseSchedule.getStartClassTime());
		//课程结束时间为排课的最后一节课的结束时间
		vipGroupApplyBaseInfoDto.setCoursesExpireDate(latestCourseSchedule.getEndClassTime());

		vipGroupApplyBaseInfoDto.setPaymentExpireDate(DateUtil.getLastSecondWithDay(vipGroupApplyBaseInfoDto.getPaymentExpireDate()));

        VipGroupDefaultClassesUnitPrice vipGroupDefaultClassesUnitPrice = vipGroupDefaultClassesUnitPriceDao.getByVipGroupCategory(vipGroup.getVipGroupApplyBaseInfo().getVipGroupCategoryId(), vipGroup.getVipGroupApplyBaseInfo().getOrganId());

        if(Objects.isNull(vipGroupDefaultClassesUnitPrice)){
            vipGroupApplyBaseInfoDto.setAuditStatus(AuditStatusEnum.ING);
        }else{
            if(Objects.nonNull(vipGroupApplyBaseInfoDto.getOfflineClassesUnitPrice())
                    &&vipGroupApplyBaseInfoDto.getOfflineClassesUnitPrice().compareTo(vipGroupDefaultClassesUnitPrice.getOfflineClassesUnitPrice())!=0){
                vipGroupApplyBaseInfoDto.setAuditStatus(AuditStatusEnum.ING);
            }
            if(Objects.nonNull(vipGroupApplyBaseInfoDto.getOnlineClassesUnitPrice())
                    &&vipGroupApplyBaseInfoDto.getOnlineClassesUnitPrice().compareTo(vipGroupDefaultClassesUnitPrice.getOnlineClassesUnitPrice())!=0){
                vipGroupApplyBaseInfoDto.setAuditStatus(AuditStatusEnum.ING);
            }
        }

        if(vipGroup.getOnlyProgress()){
			vipGroupApplyBaseInfoDto.setAuditStatus(AuditStatusEnum.PASS);
		}

		vipGroupDao.insert(vipGroupApplyBaseInfoDto);

        vipGroup.getVipGroupApplyBaseInfo().setId(vipGroupApplyBaseInfoDto.getId());

		//创建班级信息
		ClassGroup classGroup=new ClassGroup();
		classGroup.setSubjectIdList(vipGroupApplyBaseInfoDto.getSubjectIdList());
		classGroup.setExpectStudentNum(vipGroupCategory.getStudentNum());
		if(StringUtils.isNotBlank(studentIds)){
			classGroup.setStudentNum(studentIdList.size());
		}
		classGroup.setName(vipGroupApplyBaseInfoDto.getName());
		classGroup.setExpectStudentNum(vipGroupApplyBaseInfoDto.getStudentNum());
		classGroup.setTotalClassTimes(totalClassTimes);
		classGroup.setType(ClassGroupTypeEnum.VIP);
		classGroup.setDelFlag(1);
		classGroup.setGroupType(GroupType.VIP);
		classGroup.setMusicGroupId(vipGroupApplyBaseInfoDto.getId().toString());
		classGroup.setCreateTime(now);
		classGroup.setUpdateTime(now);
		classGroupDao.insert(classGroup);

		//创建班级老师关联记录
		ClassGroupTeacherMapper classGroupTeacherMapper=new ClassGroupTeacherMapper();
		classGroupTeacherMapper.setMusicGroupId(vipGroupApplyBaseInfoDto.getId().toString());
		classGroupTeacherMapper.setClassGroupId(classGroup.getId());
		classGroupTeacherMapper.setTeacherRole(TeachTypeEnum.BISHOP);
		classGroupTeacherMapper.setUserId(vipGroupApplyBaseInfoDto.getUserId());
		classGroupTeacherMapper.setGroupType(GroupType.VIP);
		classGroupTeacherMapper.setCreateTime(now);
		classGroupTeacherMapper.setUpdateTime(now);
		classGroupTeacherMapperDao.insert(classGroupTeacherMapper);

		//创建班级与老师课酬记录
		ClassGroupTeacherSalary classGroupTeacherSalary=new ClassGroupTeacherSalary();
		classGroupTeacherSalary.setMusicGroupId(vipGroupApplyBaseInfoDto.getId().toString());
		classGroupTeacherSalary.setClassGroupId(classGroup.getId());
		classGroupTeacherSalary.setTeacherRole(TeachTypeEnum.BISHOP);
		classGroupTeacherSalary.setUserId(vipGroupApplyBaseInfoDto.getUserId());
		classGroupTeacherSalary.setSalary(vipGroupApplyBaseInfoDto.getOfflineTeacherSalary());
		classGroupTeacherSalary.setOnlineClassesSalary(vipGroupApplyBaseInfoDto.getOnlineTeacherSalary());
		classGroupTeacherSalary.setGroupType(GroupType.VIP);
		classGroupTeacherSalary.setCreateTime(now);
		classGroupTeacherSalary.setUpdateTime(now);
		classGroupTeacherSalaryDao.insert(classGroupTeacherSalary);

		//课程信息调整
		vipGroup.getCourseSchedules().forEach(courseSchedule -> {
			courseSchedule.setGroupType(GroupType.VIP);
			courseSchedule.setMusicGroupId(vipGroupApplyBaseInfoDto.getId().toString());
		    if(courseSchedule.getTeachMode().equals(TeachModeEnum.OFFLINE)){
				courseSchedule.setSchoolId(vipGroup.getVipGroupApplyBaseInfo().getTeacherSchoolId());
			}
		    courseSchedule.setTeacherId(vipGroupApplyBaseInfoDto.getUserId());
			courseSchedule.setActualTeacherId(vipGroupApplyBaseInfoDto.getUserId());
			courseSchedule.setStatus(CourseStatusEnum.NOT_START);
		    courseSchedule.setType(CourseSchedule.CourseScheduleType.VIP);
			courseSchedule.setClassGroupId(classGroup.getId());
			courseSchedule.setName(vipGroupApplyBaseInfoDto.getName());
			courseSchedule.setOrganId(vipGroupApplyBaseInfoDto.getOrganId());
		});
		courseScheduleService.checkNewCourseSchedules(vipGroup.getCourseSchedules(),false,false);
		vipGroupApplyBaseInfoDto.setCourseSchedulesJson(JSON.toJSONString(vipGroup.getCourseSchedules()));
		vipGroupDao.update(vipGroupApplyBaseInfoDto);

		if(StringUtils.isNotBlank(studentIds)){
			List<Integer> collect = studentIdList.stream().mapToInt(Integer::parseInt).boxed().collect(Collectors.toList());
			classGroupService.addStudentIntoClassGroup(vipGroupApplyBaseInfoDto.getId().toString(),classGroup.getId(),collect);
			createVipGroupCourseScheInfo(vipGroupApplyBaseInfoDto.getId(),classGroup);
		}

		Set<Integer> roleIds = new HashSet<>(1);
		roleIds.add(SysUserRole.OPERATION_EXECUTIVE);
		Map<String,Long> memo = new HashMap<>(1);
		memo.put("vipGroupId",vipGroupApplyBaseInfoDto.getId());
//		SysUser sysUser = sysUserFeignService.queryUserById(vipGroup.getVipGroupApplyBaseInfo().getUserId());
		if(Objects.isNull(teacher)){
			throw new BizException("该用户不存在");
		}
		Set<Integer> userIds = musicGroupDao.queryUserIdByRoleId(roleIds,teacher.getTeacherOrganId());
		if(CollectionUtils.isEmpty(userIds)){
			throw new BizException("当前分部没有运营主管，无法创建，请联系总部工作人员！");
		}
//		if (vipGroup.getVipGroupApplyBaseInfo().getUserId() != null){
//			sysMessageService.batchSeoMessage(userIds,MessageTypeEnum.BACKSTAGE_VIP_COURSE_APPLY, JSONObject.toJSONString(memo),sysUser.getUsername(),sysUser.getUsername());
//		}else {
		sysMessageService.batchSeoMessage(userIds,MessageTypeEnum.BACKSTAGE_TEACHER_APPLY_VIP, JSONObject.toJSONString(memo),teacher.getRealName());
//		}
		return vipGroupApplyBaseInfoDto.getAuditStatus().getCode();
	}

	@Override
	public List<Organization> getPublicOrgans(Integer eduTeacherId, Integer teacherId) {
		if(Objects.isNull(eduTeacherId)){
			throw new BizException("教务老师不存在");
		}
		if(Objects.isNull(teacherId)){
			throw new BizException("请指定指导老师");
		}
		Employee employee = employeeDao.get(eduTeacherId);
		if(Objects.isNull(employee)){
			throw new BizException("教务老师不存在");
		}
		Teacher teacher = teacherDao.get(teacherId);
		if(Objects.isNull(teacher)){
			throw new BizException("指导老师不存在");
		}
		List<Integer> employeeOrganIds=new ArrayList<>();
		if(StringUtils.isNotBlank(employee.getOrganIdList())){
			employeeOrganIds= Arrays.stream(employee.getOrganIdList().split(",")).map(e->Integer.valueOf(e)).collect(Collectors.toList());
		}
		List<Integer> teacherOrganIds=new ArrayList<>();
		if(Objects.nonNull(teacher.getTeacherOrganId())){
			teacherOrganIds.add(teacher.getTeacherOrganId());
		}
		if(StringUtils.isNotBlank(teacher.getFlowOrganRange())){
			Arrays.stream(teacher.getFlowOrganRange().split(","))
					.map(e->Integer.valueOf(e)).collect(Collectors.toSet())
					.forEach(organId->{
						teacherOrganIds.add(organId);
					});
		}
		List<Integer> publicOrganIds = employeeOrganIds.stream().filter(employeeOrganId -> teacherOrganIds.contains(employeeOrganId)).collect(Collectors.toList());
		if(CollectionUtils.isEmpty(publicOrganIds)){
			return Collections.emptyList();
		}
		return organizationDao.findOrgans(publicOrganIds);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void deleteVipGroup(Long vipGroupId) {
		if(Objects.isNull(vipGroupId)){
			throw new BizException("请指定课程组");
		}
		VipGroup vipGroup = vipGroupDao.get(vipGroupId);
		if(Objects.isNull(vipGroup)){
			throw new BizException("课程组不存在");
		}
		Integer courseEndNum = courseScheduleDao.findCourseEndNum(vipGroupId);
		if(courseEndNum>0){
			throw new BizException("此状态课程组不支持删除");
		}
		vipGroup.setStatus(VipGroupStatusEnum.DELETE);
		vipGroupDao.update(vipGroup);
		groupClassService.hideGroupInfo(vipGroupId.toString(), GroupType.VIP);
	}

	@Override
    @Transactional(rollbackFor = Exception.class)
    public void checkVipCourseIsInScore(Long vipGroupId) {
	    if(Objects.isNull(vipGroupId)){
	        return;
        }
	    VipGroup vipGroup=vipGroupDao.get(vipGroupId);
	    if(Objects.isNull(vipGroup)){
	        throw new BizException("课程不存在");
        }
        Date groupCourseStartTime=courseScheduleDao.findGroupCourseStartTime(GroupType.VIP,vipGroupId.toString());
        Date groupCourseEndTime=courseScheduleDao.findGroupCourseEndTime(GroupType.VIP,vipGroupId.toString());

        //获取活动信息
        if(Objects.nonNull(vipGroup.getVipGroupActivityId())){
			VipGroupActivity vipGroupActivity = vipGroupActivityDao.get(vipGroup.getVipGroupActivityId().intValue());
			if(Objects.nonNull(vipGroupActivity)&&(Objects.nonNull(vipGroupActivity.getCoursesEndTime())||Objects.nonNull(vipGroupActivity.getCoursesStartTime()))){
				if(groupCourseEndTime.after(vipGroupActivity.getCoursesEndTime())
						||groupCourseStartTime.before(vipGroupActivity.getCoursesStartTime())){
					throw new BizException("课时安排时间超出范围!");
				}
			}else {
				int totalClassTimes = courseScheduleDao.countGroupAllCourses(GroupType.VIP, vipGroupId.toString());
				VipGroupDefaultClassesCycle vipGroupDefaultClassesCycle = vipGroupDefaultClassesCycleDao.findByOrganAndClassTimes(totalClassTimes);

				if (vipGroupDefaultClassesCycle != null) {
					Date expectEndCourseTime = DateUtil.addMonths(groupCourseStartTime, vipGroupDefaultClassesCycle.getMonth());
					if (groupCourseEndTime.after(expectEndCourseTime)) {
						throw new BizException("课时安排时间超出范围!");
					}
				}
			}
        }
    }

	@Override
	public void vipApplyAudit(Long vipGroupId, AuditStatusEnum auditStatus, String reason) {
		if(Objects.isNull(vipGroupId)||Objects.isNull(auditStatus)){
			throw new BizException("请指定vip课及审核结果");
		}
		VipGroup vipGroup = vipGroupDao.get(vipGroupId);
		if(Objects.isNull(vipGroup)){
			throw new BizException("vip课不存在");
		}
		if(vipGroup.getAuditStatus()!=AuditStatusEnum.ING){
			throw new BizException("该课程已被审核");
		}
		if(StringUtils.isBlank(reason)){
			throw new BizException("请填写拒绝原因");
		}
		/*if(vipGroup.getAuditStatus() == AuditStatusEnum.PASS){
			ImGroupMember[] imGroupMembers = new ImGroupMember[]{new ImGroupMember(vipGroup.getUserId().toString())};
			// 创建群组
			imFeignService.groupCreate(new ImGroupModel(vipGroupId.toString(), imGroupMembers, vipGroup.getName()));
		}*/
		vipGroup.setAuditStatus(auditStatus);
		vipGroup.setMemo(reason);
		vipGroupDao.update(vipGroup);
		//给老师推送审批短信
		Teacher teacher = teacherDao.get(vipGroup.getUserId());
		if(teacher != null){
			Map<Integer,String> map = new HashMap<>(1);
			map.put(vipGroup.getUserId(),vipGroup.getUserId().toString());
			sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG,MessageTypeEnum.TEACHER_SMS_VIP_COURSE_APPLY_RESULT,
					map,null,0,"7","TEACHER",vipGroup.getName(),vipGroup.getAuditStatus().getMsg());
			Map<Integer,String> map1 = new HashMap<>(1);
			map1.put(vipGroup.getUserId(),teacher.getPhone());
			sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.AWSMS,MessageTypeEnum.TEACHER_SMS_VIP_COURSE_APPLY_RESULT,
					map1,null,0,"7","",vipGroup.getName(),vipGroup.getAuditStatus().getMsg());
		}
	}

	@Override
	public PageInfo findStudentVipGroupList(StudentVipGroupQueryInfo queryInfo) {
		PageInfo pageInfo = new PageInfo<>(queryInfo.getPage(), queryInfo.getRows());
		Map<String, Object> params = new HashMap<String, Object>();
		MapUtil.populateMap(params, queryInfo);

		List dataList = null;
		int count = vipGroupDao.countVipGorups(params);
		if (count > 0) {
			pageInfo.setTotal(count);
			params.put("offset", pageInfo.getOffset());
			dataList = vipGroupDao.findVipGroups(params);
		}
		if (count == 0) {
			dataList = new ArrayList<>();
		}
		pageInfo.setRows(dataList);
		return pageInfo;
	}

	@Override
	public PageInfo<VipGroup> findVipGroups(VipGroupQueryInfo queryInfo) {
		PageInfo pageInfo = new PageInfo<>(queryInfo.getPage(), queryInfo.getRows());
		Map<String, Object> params = new HashMap<>();
		MapUtil.populateMap(params, queryInfo);

		List<VipGroup> dataList = null;
		int count = vipGroupDao.countVipGroupByOrgan(params);
		if(queryInfo.getIsExport() && count > 50000){
			throw new BizException("数据集太大，不能导出.最大数据集不能超过50000");
		}
		if (count > 0) {
			pageInfo.setTotal(count);
			params.put("offset", pageInfo.getOffset());
			dataList = vipGroupDao.findAllByOrgan(params);
			if(dataList != null && dataList.size() > 0){
				List<String> vipGroupIds = dataList.stream().map(vipGroup -> String.valueOf(vipGroup.getId())).distinct().collect(Collectors.toList());
				List<Map<Long, Integer>> vipGroupOverCourses = courseScheduleDao.countGroupOverCourse(vipGroupIds,"VIP");
				List<Map<String, Integer>> groupStudentNumMaps = classGroupStudentMapperDao.countGroupAllStudentNum(vipGroupIds, GroupType.VIP);
				Map<String,Integer> vipGroupOverCourseMaps = JSONObject.parseObject(JSONObject.toJSONString(MapUtil.convertIntegerMap(vipGroupOverCourses)),HashMap.class);
				List<Integer> educationalTeacherIds=dataList.stream().filter(data -> Objects.nonNull(data.getEducationalTeacherId())).map(VipGroup::getEducationalTeacherId).collect(Collectors.toList());

				List<ClassGroup> classGroupsByVipGroups = classGroupDao
						.findByMusicGroupsAndType(vipGroupIds.stream().map(vipGroupId->String.valueOf(vipGroupId)).collect(Collectors.toList()),
								GroupType.VIP.getCode());

				Map<String, ClassGroup> vipGroupClassGroupMap = classGroupsByVipGroups.stream().collect(Collectors.toMap(ClassGroup::getMusicGroupId, classGroup -> classGroup));

				Map<String,Long> totalClassTimeMap = MapUtil.convertIntegerMap(courseScheduleDao.countTotalCourseScheduleNum(vipGroupIds,"VIP"));
				Map<String,Long> currentClassTimeMap = MapUtil.convertIntegerMap(courseScheduleDao.countCourseScheduleNum(vipGroupIds,"VIP"));
				Map<String,String> lastOverTimeMap = MapUtil.convertIntegerMap(courseScheduleDao.findLastOverTime(vipGroupIds));
				Map<String,Long> groupStudentNumMap = MapUtil.convertIntegerMap(groupStudentNumMaps);

				List<Map<String, BigDecimal>> groupCoursesUnitPriceMaps = courseScheduleStudentPaymentDao.findGroupCoursesUnitPrice(GroupType.VIP, vipGroupIds);
				Map<String,BigDecimal> groupCoursesUnitPrice=new HashMap<>();
				if(!CollectionUtils.isEmpty(groupCoursesUnitPriceMaps)){
					groupCoursesUnitPrice=MapUtil.convertIntegerMap(groupCoursesUnitPriceMaps);
				}

				List<Integer> organIds = dataList.stream().map(VipGroup::getOrganId).collect(Collectors.toList());
				List<Organization> organs = organizationDao.findOrgans(organIds);
				Map<Integer, String> organNameMap = new HashMap<>();
				if(!CollectionUtils.isEmpty(organs)){
					organNameMap = organs.stream().collect(Collectors.toMap(Organization::getId, o->o.getName(), (o1, o2)->o1));
				}

				Map<Integer, String> idNameMap=new HashMap<>();
				if(!CollectionUtils.isEmpty(educationalTeacherIds)){
					List<SimpleUserDto> educationalUsers = employeeDao.findByIds(educationalTeacherIds);
					idNameMap = educationalUsers.stream().filter(e->Objects.nonNull(e.getUserId())&&Objects.nonNull(e.getUserName())).collect(Collectors.toMap(SimpleUserDto::getUserId, user -> user.getUserName()));
				}

				Map<String, List<GroupUserDto>> groupStudentsMap = new HashMap<>();
				if(queryInfo.getIsExport()){
					List<GroupUserDto> groupsStudents = groupDao.findGroupsStudents(vipGroupIds, GroupType.VIP);
					groupStudentsMap=groupsStudents.stream().collect(Collectors.groupingBy(GroupUserDto::getGroupId));
				}

				for (VipGroup vipGroup : dataList) {
					Integer overCourses = vipGroupOverCourseMaps.get(vipGroup.getId().toString());
					ClassGroup classGroup = vipGroupClassGroupMap.get(vipGroup.getId().toString());
					if(Objects.nonNull(classGroup)){
						vipGroup.setStudentNum(classGroup.getStudentNum());
					}
					vipGroup.setLastOverTime(lastOverTimeMap.get(vipGroup.getId().toString()));
					Long aLong = totalClassTimeMap.get(vipGroup.getId() + "");
					vipGroup.setTotalClassTimes(aLong==null?0:aLong.intValue());
					Long aLong1 = currentClassTimeMap.get(vipGroup.getId() + "");
					vipGroup.setCurrentClassTimes(aLong1==null?0:aLong1.intValue());

					vipGroup.setOrganName(organNameMap.get(vipGroup.getOrganId()));

					Long allStudentNum=groupStudentNumMap.get(vipGroup.getId().toString());
					if(Objects.isNull(allStudentNum)){
						allStudentNum=Long.valueOf(0);
					}

					if((Objects.isNull(aLong1)||aLong1<=0)
							&&(classGroup.getStudentNum()<=0)){
						vipGroup.setEnableDelete(1);
					}

					vipGroup.setEducationalTeacherName(idNameMap.get(vipGroup.getEducationalTeacherId()));

					vipGroup.setCourseUnitPrice(groupCoursesUnitPrice.get(String.valueOf(vipGroup.getId())));

					if(queryInfo.getIsExport()){
						List<GroupUserDto> groupStudents = groupStudentsMap.get(vipGroup.getId().toString());
						if(!CollectionUtils.isEmpty(groupStudents)){
							List<String> userInfos = groupStudents.stream().map(u->u.getUserName()+ "(" + u.getUserId() + ")").collect(Collectors.toList());
							vipGroup.setUserInfo(StringUtils.join(userInfos, ","));
						}
					}

					Integer totalClassTimes=vipGroup.getTotalClassTimes();
					if(Objects.isNull(totalClassTimes) || Objects.isNull(overCourses)){
						vipGroup.setMonthConsumeRate(0);
					}else{
						if(totalClassTimes<=0){
							vipGroup.setMonthConsumeRate(0);
						}else{
							BigDecimal overCoursesOfMonth=new BigDecimal(overCourses),allClassTimes=new BigDecimal(totalClassTimes);

							Integer monthConsumeRate=overCoursesOfMonth.divide(allClassTimes,CommonConstants.DECIMAL_FINAL_PLACE,BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100)).intValue();
							vipGroup.setMonthConsumeRate(monthConsumeRate);
						}
					}
				}
			}
		}
		if (count == 0) {
			dataList = new ArrayList<>();
		}
		pageInfo.setRows(dataList);
		return pageInfo;
	}

	@Override
	public Map<String, Object> findVipGroupTeachingRecord(VipGroupTeachingRecordQueryInfo queryInfo) {
		Long vipGroupId = queryInfo.getVipGroupId();
		if(Objects.isNull(vipGroupId)){
			throw new BizException("请指定vip课程!");
		}
		PageInfo pageInfo = new PageInfo<>(queryInfo.getPage(), queryInfo.getRows());
		Map<String, Object> params = new HashMap<>();
		MapUtil.populateMap(params, queryInfo);

		List<VipGroupCourseSchduleRecordDto> dataList = null;
		int count = vipGroupDao.countTeachingRecord(params);
		if (count > 0) {
			pageInfo.setTotal(count);
			params.put("offset", pageInfo.getOffset());
			dataList = vipGroupDao.findTeachingRecord(params);
			List<Long> courseScheduleIds = dataList.stream().map(VipGroupCourseSchduleRecordDto::getId).collect(Collectors.toList());
			List<Map<Integer, Integer>> maps = studentAttendanceDao.countStudentAttendancesByCoursesAndStatus(courseScheduleIds, StudentAttendanceStatusEnum.NORMAL);
			if(!CollectionUtils.isEmpty(maps)){
				Map<Long, Long> courseStudentNumMap= MapUtil.convertIntegerMap(maps);
				for (VipGroupCourseSchduleRecordDto vipGroupCourseSchduleRecordDto : dataList) {
					if(Objects.nonNull(courseStudentNumMap.get(vipGroupCourseSchduleRecordDto.getId()))){
						vipGroupCourseSchduleRecordDto.setAttendanceNum(courseStudentNumMap.get(vipGroupCourseSchduleRecordDto.getId()).intValue());
					}
				}
			}
		}
		if (count == 0) {
			dataList = new ArrayList<>();
		}
		pageInfo.setRows(dataList);
//		TeachingRecordBaseInfo classTimes = vipGroupDao.getClassTimes(queryInfo.getVipGroupId());
		TeachingRecordBaseInfo classTimes = new TeachingRecordBaseInfo();
		classTimes.setCourseNoStartNum(courseScheduleDao.findCourseNoStartNum(vipGroupId));
		classTimes.setCourseEndNum(courseScheduleDao.findCourseEndNum(vipGroupId));
		classTimes.setIsSalaryNum(vipGroupDao.countIsSalaryNum(vipGroupId));
		classTimes.setComplaintsNum(vipGroupDao.countComplaintsNum(vipGroupId));
		Map<String,Object> result=new HashMap<>();
		result.put("pageInfo",pageInfo);
		result.put("baseInfo",classTimes);
		return result;
	}

	@Override
	public TeachingRecordBaseInfo findTeachingRecordBaseInfo(Long vipGroupId) {
        TeachingRecordBaseInfo classTimes = vipGroupDao.getClassTimes(vipGroupId);
        classTimes.setIsSalaryNum(vipGroupDao.countIsSalaryNum(vipGroupId));
        classTimes.setComplaintsNum(vipGroupDao.countComplaintsNum(vipGroupId));
        return classTimes;
	}

	@Override
	public PageInfo findVipGroupStudents(VipGroupQueryInfo queryInfo) {
		PageInfo pageInfo = new PageInfo<>(queryInfo.getPage(), queryInfo.getRows());
		Map<String, Object> params = new HashMap<String, Object>();
		MapUtil.populateMap(params, queryInfo);

		List<VipGroupStudentDto> dataList = null;
		int count = vipGroupDao.countVipGroupStudents(params);
		if (count > 0) {
			pageInfo.setTotal(count);
			params.put("offset", pageInfo.getOffset());
			dataList = vipGroupDao.findVipGroupStudents(params);
			List<StudentApplyRefunds> applyRefunds = studentApplyRefundsDao.findByGroupAndType(queryInfo.getVipGroupId().toString(), GroupType.VIP.getCode());
			Map<Integer, List<StudentApplyRefunds>> studentApplyRefundsMap = applyRefunds.stream()
					.collect(Collectors.groupingBy(StudentApplyRefunds::getUserId));
			dataList.forEach(data->{
				List<StudentApplyRefunds> studentApplyRefunds = studentApplyRefundsMap.get(data.getId());
				if(!CollectionUtils.isEmpty(studentApplyRefunds)){
					StudentApplyRefunds studentApplyRefund = studentApplyRefunds.get(0);
					if(data.getStudentStatus()==0&&studentApplyRefund.getStatus().equals(StudentApplyRefundsStatus.ING)){
						data.setStudentStatus(2);
					}
				}else if(data.getStudentStatus()==0){
					data.setRefundDate(null);
				}
			});
		}
		if (count == 0) {
			dataList = new ArrayList<>();
		}
		pageInfo.setRows(dataList);
		return pageInfo;
	}

	@Override
	public PageInfo findHaveCourseBalanceStudents(VipGroupQueryInfo queryInfo) {
		PageInfo pageInfo = new PageInfo<>(queryInfo.getPage(), queryInfo.getRows());
		Map<String, Object> params = new HashMap<String, Object>();
		MapUtil.populateMap(params, queryInfo);

		List dataList = null;
		int count = vipGroupDao.countHaveCourseBalanceStudentNum(params);
		if (count > 0) {
			pageInfo.setTotal(count);
			params.put("offset", pageInfo.getOffset());
			dataList = vipGroupDao.findHaveCourseBalanceStudents(params);
		}
		if (count == 0) {
			dataList = new ArrayList<>();
		}
		pageInfo.setRows(dataList);
		return pageInfo;
	}

	@Override
	public VipGroupManageDetailDto getVipGroupDetail(Long vipGroupId) {
		if(Objects.isNull(vipGroupId)){
			throw new BizException("请指定vip课程");
		}
		VipGroupManageDetailDto vipGroupBaseInfo = vipGroupDao.getVipGroupBaseInfo(vipGroupId);
		if(Objects.nonNull(vipGroupBaseInfo.getEducationalTeacherId())){
			SysUser eduUser = sysUserFeignService.queryUserById(vipGroupBaseInfo.getEducationalTeacherId());
			if(Objects.nonNull(eduUser)){
				vipGroupBaseInfo.setEducationalTeacherName(eduUser.getRealName());
			}
		}
		vipGroupBaseInfo.setSubjectName(StringUtils.join(subjectDao.findBySubIds(vipGroupBaseInfo.getSubjectIdList()),","));
		ClassGroupTeacherSalary byVipGoupAndTeacher = classGroupTeacherSalaryDao.findByVipGoupAndTeacher(vipGroupId.intValue(), vipGroupBaseInfo.getUserId());
		Integer onlineNum = courseScheduleDao.countCourseNum(vipGroupId,"ONLINE");
		Integer offlineNum = courseScheduleDao.countCourseNum(vipGroupId,"OFFLINE");
		vipGroupBaseInfo.setOnlineClassesNum(onlineNum);
		vipGroupBaseInfo.setOfflineClassesNum(offlineNum);
		if(Objects.nonNull(byVipGoupAndTeacher)){
			vipGroupBaseInfo.setOnlineTeacherSalary(byVipGoupAndTeacher.getOnlineClassesSalary());
			vipGroupBaseInfo.setOfflineTeacherSalary(byVipGoupAndTeacher.getSalary());
		}
		return vipGroupBaseInfo;
	}

	@Override
	public VipGroupManageDetailDto getVipGroupDetailForAudit(Long vipGroupId) {
		if(Objects.isNull(vipGroupId)){
			throw new BizException("请指定vip课程");
		}
		VipGroupManageDetailDto vipGroupBaseInfo = vipGroupDao.getVipGroupBaseInfo(vipGroupId);
		vipGroupBaseInfo.setSubjectName(StringUtils.join(subjectDao.findBySubIds(vipGroupBaseInfo.getSubjectIdList()),","));
		ClassGroupTeacherSalary byVipGoupAndTeacher = classGroupTeacherSalaryDao.findByVipGoupAndTeacher(vipGroupId.intValue(), vipGroupBaseInfo.getUserId());
		if(Objects.nonNull(byVipGoupAndTeacher)){
			vipGroupBaseInfo.setOnlineTeacherSalary(byVipGoupAndTeacher.getOnlineClassesSalary());
			vipGroupBaseInfo.setOfflineTeacherSalary(byVipGoupAndTeacher.getSalary());
		}
		return vipGroupBaseInfo;
	}

	@Override
	public PageInfo findVipGroupAttendances(VipGroupAttendanceQueryInfo queryInfo) {
		PageInfo pageInfo = new PageInfo<>(queryInfo.getPage(), queryInfo.getRows());
		Map<String, Object> params = new HashMap<String, Object>();
		MapUtil.populateMap(params, queryInfo);

		List dataList = null;
		int count = vipGroupDao.countVipGroupAttendance(params);
		if (count > 0) {
			pageInfo.setTotal(count);
			params.put("offset", pageInfo.getOffset());
			dataList = vipGroupDao.findVipGroupAttendances(params);
		}
		if (count == 0) {
			dataList = new ArrayList<>();
		}
		pageInfo.setRows(dataList);
		return pageInfo;
	}

	@Override
	public StudentVipGroupDetailDto getVipGroupShowDetail(Long vipGroupId) {
		if(Objects.isNull(vipGroupId)){
			throw new BizException("请指定vip课程");
		}
		VipGroup vipGroup = vipGroupDao.get(vipGroupId);
		if(Objects.isNull(vipGroup)){
			throw new BizException("未找到指定课程");
		}
		StudentVipGroupDetailDto vipGroupDetail = vipGroupDao.getVipGroupDetail(vipGroupId);
		if(StringUtils.isNotEmpty(vipGroup.getCourseSchedulesJson())){
			vipGroupDetail.setCourseSchedules(JSON.parseArray(vipGroup.getCourseSchedulesJson(),CourseSchedule.class));
			List<CourseSchedule> collect = vipGroupDetail.getCourseSchedules().stream()
					.sorted(Comparator.comparing(CourseSchedule::getStartClassTime))
					.collect(Collectors.toList());
			vipGroupDetail.setCourseSchedules(collect);
			vipGroupDetail.setTotalClassTimes(collect.size());
		}

        vipGroupDetail.setNumberOfClasses(vipGroupDao.countTeacherVipGroups(vipGroupDetail.getTeacherId().longValue()));
        return vipGroupDetail;
	}

	@Override
	public VipGroupCostCountDto vipGroupCostCount(VipGroupCostCountParamsDto vipGroupCostCountParamsDto) {
        SysUser user = sysUserFeignService.queryUserInfo();
        TeacherDefaultVipGroupSalary teacherDefaultVipGroupSalary = teacherDefaultVipGroupSalaryDao.findByTeacherAndCategory(user.getId(), vipGroupCostCountParamsDto.getVipGroupCategoryId());
        VipGroupDefaultClassesUnitPrice vipGroupDefaultClassesUnitPrice = vipGroupDefaultClassesUnitPriceDao.get(vipGroupCostCountParamsDto.getVipGroupDefaultClassesUnitPriceId().intValue());
		VipGroupActivity vipGroupActivity = vipGroupActivityDao.get(vipGroupCostCountParamsDto.getVipGroupActivityId().intValue());
        VipGroupSalarySettlementDto vipGroupSalarySettlementDto = JSON.parseObject(vipGroupActivity.getSalarySettlementJson(), VipGroupSalarySettlementDto.class);
        BigDecimal offlineClassNum=new BigDecimal(vipGroupCostCountParamsDto.getOfflineClassesNum());
        BigDecimal onlineClassNum=new BigDecimal(vipGroupCostCountParamsDto.getOnlineClassesNum());


        //教师课酬
        BigDecimal teacherOnlineSalary,teacherOfflineSalary,teacherSalary;
        switch (vipGroupSalarySettlementDto.getOnlineSalarySettlement().getSalarySettlementType()){
            case TEACHER_DEFAULT:
                teacherOnlineSalary=teacherDefaultVipGroupSalary.getOfflineClassesSalary().multiply(onlineClassNum);
                break;
            case RATIO_DISCOUNT:
                teacherOnlineSalary=vipGroupDefaultClassesUnitPrice.getOnlineClassesUnitPrice().multiply(vipGroupSalarySettlementDto.getOnlineSalarySettlement().getSettlementValue()).multiply(onlineClassNum);
                break;
            case FIXED_SALARY:
                teacherOnlineSalary=vipGroupSalarySettlementDto.getOnlineSalarySettlement().getSettlementValue().multiply(onlineClassNum);
                break;
             default:
                 throw new BizException("未指定课酬结算标准!");
        }
        switch (vipGroupSalarySettlementDto.getOfflineSalarySettlement().getSalarySettlementType()){
            case TEACHER_DEFAULT:
                teacherOfflineSalary=teacherDefaultVipGroupSalary.getOfflineClassesSalary().multiply(offlineClassNum);
                break;
            case RATIO_DISCOUNT:
                teacherOfflineSalary=vipGroupDefaultClassesUnitPrice.getOfflineClassesUnitPrice().multiply(vipGroupSalarySettlementDto.getOfflineSalarySettlement().getSettlementValue()).multiply(offlineClassNum);
                break;
            case FIXED_SALARY:
                teacherOfflineSalary=vipGroupSalarySettlementDto.getOfflineSalarySettlement().getSettlementValue().multiply(offlineClassNum);
                break;
            default:
                throw new BizException("未指定课酬结算标准!");
        }
        teacherSalary=teacherOnlineSalary.add(teacherOfflineSalary);
        return new VipGroupCostCountDto(null,teacherSalary);
    }

    @Override
    public <K extends VipGroup> Map<String,BigDecimal> countVipGroupPredictFee(K vipGroup,
																			   Integer teacherId,
																			   BigDecimal onlineClassesUnitPrice,
																			   BigDecimal offlineClassesUnitPrice){

		if(Objects.isNull(teacherId)){
			throw new BizException("请指定教师");
		}

		if(Objects.isNull(vipGroup.getVipGroupCategoryId())){
			throw new BizException("请指定课程形式");
		}

		VipGroupCategory vipGroupCategory = vipGroupCategoryDao.get(vipGroup.getVipGroupCategoryId().intValue());
		if(Objects.isNull(vipGroupCategory)){
			throw new BizException("未找到课程形式");
		}

		TeacherDefaultVipGroupSalary teacherDefaultVipGroupSalary = teacherDefaultVipGroupSalaryDao.findByTeacherAndCategory(teacherId,
				vipGroup.getVipGroupCategoryId());

		if(Objects.isNull(teacherDefaultVipGroupSalary)){
			throw new BizException("请设置教师课酬");
		}

		if(Objects.isNull(vipGroup.getVipGroupActivityId())){
			throw new BizException("请指定活动方案");
		}

		VipGroupActivity vipGroupActivity = vipGroupActivityDao.get(vipGroup.getVipGroupActivityId().intValue());

		if(Objects.isNull(vipGroupActivity)){
			throw new BizException("指定的活动方案不存在");
		}

		VipGroupSalarySettlementDto vipGroupSalarySettlementDto = JSON.parseObject(vipGroupActivity.getSalarySettlementJson(), VipGroupSalarySettlementDto.class);

		if(Objects.isNull(vipGroupSalarySettlementDto)){
			throw new BizException("课酬结算方案错误");
		}

		Map<String,BigDecimal> results=new HashMap<>(1);

		BigDecimal offlineClassNum=new BigDecimal(vipGroup.getOfflineClassesNum());
		BigDecimal onlineClassNum=new BigDecimal(vipGroup.getOnlineClassesNum());
		onlineClassesUnitPrice=Objects.isNull(onlineClassesUnitPrice)?vipGroup.getOnlineClassesUnitPrice():onlineClassesUnitPrice;
		if(Objects.isNull(onlineClassesUnitPrice)){
			onlineClassesUnitPrice = BigDecimal.ZERO;
		}
		BigDecimal onlineVipGroupCharge = onlineClassesUnitPrice.multiply(onlineClassNum);
		offlineClassesUnitPrice=Objects.isNull(offlineClassesUnitPrice)?vipGroup.getOfflineClassesUnitPrice():offlineClassesUnitPrice;
		if(Objects.isNull(offlineClassesUnitPrice)){
			offlineClassesUnitPrice = BigDecimal.ZERO;
		}
		BigDecimal offlineVipGroupCharge = offlineClassesUnitPrice.multiply(offlineClassNum);
		BigDecimal totalClassNum=offlineClassNum.add(onlineClassNum);
		BigDecimal teacherOnlineSalary=null,teacherOfflineSalary=null;

		if(Objects.isNull(vipGroupActivity.getType())){
			throw new BizException("此活动未设置活动类型");
		}

		//课程购买费用计算
		BigDecimal totalPrice;
		switch (vipGroupActivity.getType()){
			case BASE_ACTIVITY:
				totalPrice=onlineVipGroupCharge.add(offlineVipGroupCharge);
				break;
			case DISCOUNT:
				BigDecimal discount=new BigDecimal(vipGroupActivity.getAttribute1());
				totalPrice=onlineVipGroupCharge.add(offlineVipGroupCharge);
				totalPrice=totalPrice.multiply(discount).divide(new BigDecimal(100), CommonConstants.DECIMAL_PLACE, BigDecimal.ROUND_DOWN);
				break;
			case GIVE_CLASS:
				if(totalClassNum.compareTo(new BigDecimal(vipGroupActivity.getAttribute1()))<0){

				}else if(vipGroup.getGiveTeachMode()==TeachModeEnum.OFFLINE){
					if(totalClassNum.compareTo(new BigDecimal(vipGroupActivity.getAttribute1()))>-1){
						offlineClassNum=offlineClassNum.subtract(new BigDecimal(vipGroupActivity.getAttribute2()));
					}
					offlineVipGroupCharge = offlineClassesUnitPrice.multiply(offlineClassNum);
				}else if(vipGroup.getGiveTeachMode()==TeachModeEnum.ONLINE){
					if(totalClassNum.compareTo(new BigDecimal(vipGroupActivity.getAttribute1()))>-1){
						onlineClassNum=onlineClassNum.subtract(new BigDecimal(vipGroupActivity.getAttribute2()));
					}
					onlineVipGroupCharge = onlineClassesUnitPrice.multiply(onlineClassNum);
				}else{
					throw new BizException("请指定赠送课程类型!");
				}
				totalPrice=onlineVipGroupCharge.add(offlineVipGroupCharge);
				break;
			default:
				throw new BizException("活动类型错误!");
		}

		results.put("totalPrice",totalPrice.setScale(0,BigDecimal.ROUND_CEILING));

		int normalStudentNum = 0;
		if(Objects.nonNull(vipGroup.getId())){
			normalStudentNum = classGroupStudentMapperDao.countGroupNormalStudentNum(GroupType.VIP, vipGroup.getId().toString());
		}

//		if(JobNatureEnum.PART_TIME.equals(teacher.getJobNature())){
//			BigDecimal ots = teacherDefaultVipGroupSalary.getOfflineClassesSalary();
//			BigDecimal ofts = teacherDefaultVipGroupSalary.getOfflineClassesSalary();
//			if(normalStudentNum>0&&normalStudentNum!=vipGroupCategory.getStudentNum()){
//				ots = ots.divide(new BigDecimal(vipGroupCategory.getStudentNum()),CommonConstants.DECIMAL_PLACE, BigDecimal.ROUND_DOWN).multiply(new BigDecimal(normalStudentNum)).setScale(CommonConstants.DECIMAL_FINAL_PLACE, BigDecimal.ROUND_HALF_UP);
//				ofts = ofts.divide(new BigDecimal(vipGroupCategory.getStudentNum()),CommonConstants.DECIMAL_PLACE, BigDecimal.ROUND_DOWN).multiply(new BigDecimal(normalStudentNum)).setScale(CommonConstants.DECIMAL_FINAL_PLACE, BigDecimal.ROUND_HALF_UP);
//			}
//
//			results.put("onlineTeacherSalary", ots);
//			results.put("offlineTeacherSalary", ofts);
//			return results;
//		}

		//教师课酬线上单课酬计算
		if(Objects.nonNull(vipGroupSalarySettlementDto.getOnlineSalarySettlement())){
			if(Objects.isNull(teacherOnlineSalary)){
				switch (vipGroupSalarySettlementDto.getOnlineSalarySettlement().getSalarySettlementType()){
					case TEACHER_DEFAULT:
						if(Objects.isNull(teacherDefaultVipGroupSalary)||Objects.isNull(teacherDefaultVipGroupSalary.getOfflineClassesSalary())){
							teacherOnlineSalary=new BigDecimal(0);
						}else{
							teacherOnlineSalary=teacherDefaultVipGroupSalary.getOfflineClassesSalary();
						}
						results.put("onlineTeacherSalary",teacherOnlineSalary.setScale(0, BigDecimal.ROUND_HALF_UP));
						break;
					case RATIO_DISCOUNT:
						results.put("onlineTeacherSalary",totalPrice.multiply(new BigDecimal(vipGroupCategory.getStudentNum()))
								.divide(totalClassNum, CommonConstants.DECIMAL_PLACE, BigDecimal.ROUND_DOWN)
								.multiply(vipGroupSalarySettlementDto.getOnlineSalarySettlement().getSettlementValue())
								.divide(new BigDecimal(100), CommonConstants.DECIMAL_PLACE, BigDecimal.ROUND_DOWN)
								.setScale(0,BigDecimal.ROUND_HALF_UP));

						break;
					case FIXED_SALARY:
						results.put("onlineTeacherSalary",vipGroupSalarySettlementDto.getOnlineSalarySettlement().getSettlementValue().setScale(0, BigDecimal.ROUND_HALF_UP));
						break;
					default:
						throw new BizException("未指定课酬结算标准!");
				}

			}
		}

		//教师线下单课酬计算
		if(Objects.nonNull(vipGroupSalarySettlementDto.getOfflineSalarySettlement())){
			if(Objects.isNull(teacherOfflineSalary)){
				switch (vipGroupSalarySettlementDto.getOfflineSalarySettlement().getSalarySettlementType()){
					case TEACHER_DEFAULT:
						if(Objects.isNull(teacherDefaultVipGroupSalary)||Objects.isNull(teacherDefaultVipGroupSalary.getOfflineClassesSalary())){
							teacherOfflineSalary=new BigDecimal(0);
						}else{
							teacherOfflineSalary=teacherDefaultVipGroupSalary.getOfflineClassesSalary();
						}
						results.put("offlineTeacherSalary",teacherOfflineSalary.setScale(0, BigDecimal.ROUND_HALF_UP));
						break;
					case RATIO_DISCOUNT:
						results.put("offlineTeacherSalary",totalPrice.multiply(new BigDecimal(vipGroupCategory.getStudentNum())).divide(totalClassNum, CommonConstants.DECIMAL_PLACE, BigDecimal.ROUND_DOWN).multiply(vipGroupSalarySettlementDto.getOfflineSalarySettlement().getSettlementValue()).divide(new BigDecimal(100), CommonConstants.DECIMAL_PLACE, BigDecimal.ROUND_DOWN).setScale(0,BigDecimal.ROUND_HALF_UP));

						break;
					case FIXED_SALARY:
						results.put("offlineTeacherSalary",vipGroupSalarySettlementDto.getOfflineSalarySettlement().getSettlementValue().setScale(0, BigDecimal.ROUND_HALF_UP));
						break;
					default:
						throw new BizException("未指定课酬结算标准!");
				}
			}
		}

		BigDecimal ots = results.get("onlineTeacherSalary");
		if(Objects.isNull(ots)){
			ots = teacherDefaultVipGroupSalary.getOfflineClassesSalary();
		}
		if(Objects.isNull(ots)){
			ots = BigDecimal.ZERO;
		}
		BigDecimal ofts = results.get("offlineTeacherSalary");
		if(Objects.isNull(ofts)){
			ofts = teacherDefaultVipGroupSalary.getOfflineClassesSalary();
		}
		if(Objects.isNull(ofts)){
			ofts = BigDecimal.ZERO;
		}
		if(Objects.nonNull(vipGroup.getStatus())&&normalStudentNum!=vipGroupCategory.getStudentNum()){
			ots = ots.divide(new BigDecimal(vipGroupCategory.getStudentNum()),CommonConstants.DECIMAL_PLACE, BigDecimal.ROUND_DOWN).multiply(new BigDecimal(normalStudentNum)).setScale(CommonConstants.DECIMAL_FINAL_PLACE, BigDecimal.ROUND_HALF_UP);
			ofts = ofts.divide(new BigDecimal(vipGroupCategory.getStudentNum()),CommonConstants.DECIMAL_PLACE, BigDecimal.ROUND_DOWN).multiply(new BigDecimal(normalStudentNum)).setScale(CommonConstants.DECIMAL_FINAL_PLACE, BigDecimal.ROUND_HALF_UP);
		}

		results.put("onlineTeacherSalary", ots);
		results.put("offlineTeacherSalary", ofts);

        return results;
    }

	@Override
	public <K extends VipGroup> Map<String,BigDecimal> countVipGroupCoursePredictFee(K vipGroup,
																			   Integer teacherId,
																					 Long courseId){

		if(Objects.isNull(teacherId)){
			throw new BizException("请指定教师");
		}

		if(Objects.isNull(vipGroup.getVipGroupCategoryId())){
			throw new BizException("请指定课程形式");
		}

		VipGroupCategory vipGroupCategory = vipGroupCategoryDao.get(vipGroup.getVipGroupCategoryId().intValue());
		if(Objects.isNull(vipGroupCategory)){
			throw new BizException("未找到课程形式");
		}

		TeacherDefaultVipGroupSalary teacherDefaultVipGroupSalary = teacherDefaultVipGroupSalaryDao.findByTeacherAndCategory(teacherId,
				vipGroup.getVipGroupCategoryId());

		if(Objects.isNull(teacherDefaultVipGroupSalary)){
			throw new BizException("请设置教师课酬");
		}

		if(Objects.isNull(vipGroup.getVipGroupActivityId())){
			throw new BizException("请指定活动方案");
		}

		VipGroupActivity vipGroupActivity = vipGroupActivityDao.get(vipGroup.getVipGroupActivityId().intValue());

		if(Objects.isNull(vipGroupActivity)){
			throw new BizException("指定的活动方案不存在");
		}

		VipGroupSalarySettlementDto vipGroupSalarySettlementDto = JSON.parseObject(vipGroupActivity.getSalarySettlementJson(), VipGroupSalarySettlementDto.class);

		if(Objects.isNull(vipGroupSalarySettlementDto)){
			throw new BizException("课酬结算方案错误");
		}

		Map<String,BigDecimal> results=new HashMap<>(1);

		BigDecimal offlineClassNum=new BigDecimal(vipGroup.getOfflineClassesNum());
		BigDecimal onlineClassNum=new BigDecimal(vipGroup.getOnlineClassesNum());
		BigDecimal onlineClassesUnitPrice=vipGroup.getOnlineClassesUnitPrice();
		if(Objects.isNull(onlineClassesUnitPrice)){
			onlineClassesUnitPrice = BigDecimal.ZERO;
		}
		BigDecimal onlineVipGroupCharge = onlineClassesUnitPrice.multiply(onlineClassNum);
		BigDecimal offlineClassesUnitPrice=vipGroup.getOfflineClassesUnitPrice();
		if(Objects.isNull(offlineClassesUnitPrice)){
			offlineClassesUnitPrice = BigDecimal.ZERO;
		}
		BigDecimal offlineVipGroupCharge = offlineClassesUnitPrice.multiply(offlineClassNum);
		BigDecimal totalClassNum=offlineClassNum.add(onlineClassNum);
		BigDecimal teacherOnlineSalary=null,teacherOfflineSalary=null;

		if(Objects.isNull(vipGroupActivity.getType())){
			throw new BizException("此活动未设置活动类型");
		}

		//课程购买费用计算
		BigDecimal totalPrice;
		switch (vipGroupActivity.getType()){
			case BASE_ACTIVITY:
				totalPrice=onlineVipGroupCharge.add(offlineVipGroupCharge);
				break;
			case DISCOUNT:
				BigDecimal discount=new BigDecimal(vipGroupActivity.getAttribute1());
				totalPrice=onlineVipGroupCharge.add(offlineVipGroupCharge);
				totalPrice=totalPrice.multiply(discount).divide(new BigDecimal(100), CommonConstants.DECIMAL_PLACE, BigDecimal.ROUND_DOWN);
				break;
			case GIVE_CLASS:
				if(totalClassNum.compareTo(new BigDecimal(vipGroupActivity.getAttribute1()))<0){

				}else if(vipGroup.getGiveTeachMode()==TeachModeEnum.OFFLINE){
					if(totalClassNum.compareTo(new BigDecimal(vipGroupActivity.getAttribute1()))>-1){
						offlineClassNum=offlineClassNum.subtract(new BigDecimal(vipGroupActivity.getAttribute2()));
					}
					offlineVipGroupCharge = offlineClassesUnitPrice.multiply(offlineClassNum);
				}else if(vipGroup.getGiveTeachMode()==TeachModeEnum.ONLINE){
					if(totalClassNum.compareTo(new BigDecimal(vipGroupActivity.getAttribute1()))>-1){
						onlineClassNum=onlineClassNum.subtract(new BigDecimal(vipGroupActivity.getAttribute2()));
					}
					onlineVipGroupCharge = onlineClassesUnitPrice.multiply(onlineClassNum);
				}else{
					throw new BizException("请指定赠送课程类型!");
				}
				totalPrice=onlineVipGroupCharge.add(offlineVipGroupCharge);
				break;
			default:
				throw new BizException("活动类型错误!");
		}

		results.put("totalPrice",totalPrice.setScale(0,BigDecimal.ROUND_CEILING));

		int normalStudentNum = 0;
		if(Objects.nonNull(vipGroup.getId())){
			normalStudentNum = courseScheduleStudentPaymentDao.countStudentNum(courseId.intValue());
		}

		//教师课酬线上单课酬计算
		if(Objects.nonNull(vipGroupSalarySettlementDto.getOnlineSalarySettlement())){
			if(Objects.isNull(teacherOnlineSalary)){
				switch (vipGroupSalarySettlementDto.getOnlineSalarySettlement().getSalarySettlementType()){
					case TEACHER_DEFAULT:
						if(Objects.isNull(teacherDefaultVipGroupSalary)||Objects.isNull(teacherDefaultVipGroupSalary.getOfflineClassesSalary())){
							teacherOnlineSalary=new BigDecimal(0);
						}else{
							teacherOnlineSalary=teacherDefaultVipGroupSalary.getOfflineClassesSalary();
						}
						results.put("onlineTeacherSalary",teacherOnlineSalary.setScale(0, BigDecimal.ROUND_HALF_UP));
						break;
					case RATIO_DISCOUNT:
						results.put("onlineTeacherSalary",totalPrice.multiply(new BigDecimal(vipGroupCategory.getStudentNum()))
								.divide(totalClassNum, CommonConstants.DECIMAL_PLACE, BigDecimal.ROUND_DOWN)
								.multiply(vipGroupSalarySettlementDto.getOnlineSalarySettlement().getSettlementValue())
								.divide(new BigDecimal(100), CommonConstants.DECIMAL_PLACE, BigDecimal.ROUND_DOWN)
								.setScale(0,BigDecimal.ROUND_HALF_UP));

						break;
					case FIXED_SALARY:
						results.put("onlineTeacherSalary",vipGroupSalarySettlementDto.getOnlineSalarySettlement().getSettlementValue().setScale(0, BigDecimal.ROUND_HALF_UP));
						break;
					default:
						throw new BizException("未指定课酬结算标准!");
				}

			}
		}

		//教师线下单课酬计算
		if(Objects.nonNull(vipGroupSalarySettlementDto.getOfflineSalarySettlement())){
			if(Objects.isNull(teacherOfflineSalary)){
				switch (vipGroupSalarySettlementDto.getOfflineSalarySettlement().getSalarySettlementType()){
					case TEACHER_DEFAULT:
						if(Objects.isNull(teacherDefaultVipGroupSalary)||Objects.isNull(teacherDefaultVipGroupSalary.getOfflineClassesSalary())){
							teacherOfflineSalary=new BigDecimal(0);
						}else{
							teacherOfflineSalary=teacherDefaultVipGroupSalary.getOfflineClassesSalary();
						}
						results.put("offlineTeacherSalary",teacherOfflineSalary.setScale(0, BigDecimal.ROUND_HALF_UP));
						break;
					case RATIO_DISCOUNT:
						results.put("offlineTeacherSalary",totalPrice.multiply(new BigDecimal(vipGroupCategory.getStudentNum())).divide(totalClassNum, CommonConstants.DECIMAL_PLACE, BigDecimal.ROUND_DOWN).multiply(vipGroupSalarySettlementDto.getOfflineSalarySettlement().getSettlementValue()).divide(new BigDecimal(100), CommonConstants.DECIMAL_PLACE, BigDecimal.ROUND_DOWN).setScale(0,BigDecimal.ROUND_HALF_UP));

						break;
					case FIXED_SALARY:
						results.put("offlineTeacherSalary",vipGroupSalarySettlementDto.getOfflineSalarySettlement().getSettlementValue().setScale(0, BigDecimal.ROUND_HALF_UP));
						break;
					default:
						throw new BizException("未指定课酬结算标准!");
				}
			}
		}

		BigDecimal ots = results.get("onlineTeacherSalary");
		if(Objects.isNull(ots)){
			ots = teacherDefaultVipGroupSalary.getOfflineClassesSalary();
		}
		if(Objects.isNull(ots)){
			ots = BigDecimal.ZERO;
		}
		BigDecimal ofts = results.get("offlineTeacherSalary");
		if(Objects.isNull(ofts)){
			ofts = teacherDefaultVipGroupSalary.getOfflineClassesSalary();
		}
		if(Objects.isNull(ofts)){
			ofts = BigDecimal.ZERO;
		}
		if(Objects.nonNull(vipGroup.getStatus())&&normalStudentNum!=vipGroupCategory.getStudentNum()){
			ots = ots.divide(new BigDecimal(vipGroupCategory.getStudentNum()),CommonConstants.DECIMAL_PLACE, BigDecimal.ROUND_DOWN).multiply(new BigDecimal(normalStudentNum)).setScale(CommonConstants.DECIMAL_FINAL_PLACE, BigDecimal.ROUND_HALF_UP);
			ofts = ofts.divide(new BigDecimal(vipGroupCategory.getStudentNum()),CommonConstants.DECIMAL_PLACE, BigDecimal.ROUND_DOWN).multiply(new BigDecimal(normalStudentNum)).setScale(CommonConstants.DECIMAL_FINAL_PLACE, BigDecimal.ROUND_HALF_UP);
		}

		results.put("onlineTeacherSalary", ots);
		results.put("offlineTeacherSalary", ofts);

		return results;
	}

	@Override
	public void enableBuyVipGroup(Integer vipGroupId, Integer userId) {
		if (Objects.isNull(vipGroupId)){
			throw new BizException("请指定VIP课");
		}
		VipGroup vipGroup = get(vipGroupId.longValue());
		if(Objects.nonNull(vipGroup.getStudentIdList())){
			Set<Integer> userIds = Arrays.asList(vipGroup.getStudentIdList().split(",")).stream().mapToInt(Integer::parseInt).boxed().collect(Collectors.toSet());
			if(!userIds.contains(userId)){
				throw new BizException("您无法购买此课程");
			}
		}

		ClassGroup classGroup = classGroupDao.findByVipGroup(vipGroupId.longValue(), null);

		if(classGroup.getStudentNum()>0&&(VipGroupStatusEnum.APPLYING.equals(vipGroup.getStatus()))){
			int i = studentPaymentOrderDao.countGroupOrderWithoutFailed(vipGroupId.toString(), GroupType.VIP);
			if(i<=0){
				throw new BizException("该课程已经无法通过购买加入，请联系教务老师!");
			}
		}

		List<CourseSchedule> courseSchedules = JSON.parseArray(vipGroup.getCourseSchedulesJson(),CourseSchedule.class);
		courseScheduleService.checkNewCourseSchedules(courseSchedules,false,false);
	}

	@Override
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
	public void updateVipGroupStudentNumAndStatus(Long vipGroupId , ClassGroup classGroup, Integer num, boolean updateVipStatus) {
		VipGroup vipGroup = vipGroupDao.get(vipGroupId);
		if(Objects.isNull(vipGroup)){
			throw new BizException("指定的vip课程不存在");
		}
		if(Objects.isNull(classGroup)){
			throw new BizException("未找到关联班级");
		}
		if(classGroup.getStudentNum()+num<0){
			classGroup.setStudentNum(0);
		}else{
			classGroup.setStudentNum(classGroup.getStudentNum()+num);
		}

//		Integer studentPaymentNum=studentPaymentOrderDao.countStudentPaymentNum(vipGroupId.toString());

		Integer studentPaymentNum = classGroupStudentMapperDao.countClassGroupStudentNum(classGroup.getId());

		if(studentPaymentNum.equals(classGroup.getExpectStudentNum())&&updateVipStatus){
			classGroup.setStudentNum(studentPaymentNum);
			classGroup.setDelFlag(0);
			classGroupDao.update(classGroup);
			createVipGroupCourseScheInfo(vipGroupId,classGroup);
		}
		if(num!=0||updateVipStatus){
			int i = courseScheduleDao.countVipGroupCourses(vipGroupId.intValue(),"VIP");
			classGroup.setTotalClassTimes(i);
			classGroupDao.update(classGroup);
		}
	}

	@Override
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
	public void createVipGroupCourseScheInfo(Long vipGroupId,ClassGroup classGroup){
		VipGroup vipGroupApplyBaseInfoDto = vipGroupDao.get(vipGroupId);
		List<CourseSchedule> courseSchedules = JSON.parseArray(vipGroupApplyBaseInfoDto.getCourseSchedulesJson(),CourseSchedule.class);
		int courseNum = courseScheduleDao.countVipGroupCourses(vipGroupId.intValue(),"VIP");
		if(courseNum==0){
			courseScheduleService.batchAddCourseSchedule(courseSchedules);

			ClassGroupTeacherSalary classGroupTeacherSalary = classGroupTeacherSalaryDao.findByVipGoupAndTeacher(vipGroupId.intValue(), vipGroupApplyBaseInfoDto.getUserId());

			//创建老师单节课课酬信息
			courseScheduleTeacherSalaryService.createCourseScheduleTeacherVipSalary(vipGroupApplyBaseInfoDto,
					courseSchedules,
					classGroupTeacherSalary.getOnlineClassesSalary(),
					classGroupTeacherSalary.getSalary());
		}

		SysUser sysUser = sysUserFeignService.queryUserById(vipGroupApplyBaseInfoDto.getUserId());

		List<ClassGroupStudentMapper> classGroupStudents = classGroupStudentMapperDao.findByClassGroup(classGroup.getId());

		Map<Integer,String> userRoleMap = new HashMap<Integer, String>();
		if(Objects.nonNull(vipGroupApplyBaseInfoDto.getEducationalTeacherId())){
            userRoleMap.put(vipGroupApplyBaseInfoDto.getEducationalTeacherId(),"乐团主管");
        }
		userRoleMap.put(vipGroupApplyBaseInfoDto.getUserId(),"指导老师");
		//生成学生单课缴费信息
		for (ClassGroupStudentMapper classGroupStudent : classGroupStudents) {
			courseScheduleStudentPaymentService.createCourseScheduleStudentPaymentForVipGroup(vipGroupId,classGroupStudent.getUserId());
			try {
				if(vipGroupApplyBaseInfoDto.getOnlineClassesNum()>0){
					teacherCourseRewardService.addConvertReward(classGroupStudent.getUserId(), vipGroupApplyBaseInfoDto.getUserId());
				}
			} catch (Exception e) {
				e.printStackTrace();
			}
			userRoleMap.put(classGroupStudent.getUserId(),null);
			studentDao.updateStudentServiceTag(classGroupStudent.getUserId(), null, YesOrNoEnum.YES.getCode());
		}

		courseScheduleService.checkNewCourseSchedules(courseSchedules, false,false);

		try {
			imGroupService.create(classGroup.getId().longValue(), null, classGroup.getName(), classGroup.getName(), vipGroupApplyBaseInfoDto.getName(), null, null, GroupType.VIP.getCode());
			imGroupMemberService.join(classGroup.getId().longValue(), userRoleMap);
			imUserFriendService.refreshGroupImUserFriend(classGroup.getMusicGroupId(),classGroup.getGroupType());
			//发送推送短信
			Map<Integer,String> map = new HashMap<>(1);
			map.put(vipGroupApplyBaseInfoDto.getUserId(),sysUser.getPhone());
			sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.AWSMS,MessageTypeEnum.TEACHER_SMS_VIP_COURSE_ADD,
					map,null,0,"","",vipGroupApplyBaseInfoDto.getName());
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Override
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class, isolation = Isolation.READ_COMMITTED)
	public Map buyVipGroup(VipGroupBuyParamsDto vipGroupBuyParams) throws Exception {
		SysUser user = sysUserFeignService.queryUserInfo();
		if(user == null){
			throw new BizException("用户信息获取失败");
		}

		ClassGroup classGroup =classGroupDao.findByMusicGroupAndType(vipGroupBuyParams.getVipGroupId().toString(),ClassGroupTypeEnum.VIP.getCode());

		classGroup= classGroupDao.lockClassGroup(classGroup.getId());

		if(Objects.isNull(classGroup)){
			throw new BizException("课程信息错误");
		}

		Date date=new Date();

        VipGroup vipGroup = vipGroupDao.get(vipGroupBuyParams.getVipGroupId());


		if(classGroup.getStudentNum()>0&&(VipGroupStatusEnum.APPLYING.equals(vipGroup.getStatus()))){
			int i = studentPaymentOrderDao.countGroupOrderWithoutFailed(vipGroupBuyParams.getVipGroupId().toString(), GroupType.VIP);
			if(i<=0){
				throw new BizException("该课程已经无法通过购买加入，请联系教务老师!");
			}
		}

		if(vipGroup.getPaymentExpireDate().before(date)){
			throw new BizException("该课程已结束报名!");
		}

		if(Objects.nonNull(vipGroup.getStudentIdList())){
			Set<Integer> userIds = Arrays.asList(vipGroup.getStudentIdList().split(",")).stream().mapToInt(Integer::parseInt).boxed().collect(Collectors.toSet());
			if(!userIds.contains(user.getId())){
				throw new BizException("您无法购买此课程");
			}
		}

		List<StudentPaymentOrder> oldOrders = studentPaymentOrderDao.findNotFailedOrderByStudentVipGroup(vipGroupBuyParams.getVipGroupId(),
				user.getId());
		Map<DealStatusEnum, Long> statusCountMap = oldOrders.stream().collect(Collectors.groupingBy(StudentPaymentOrder::getStatus, Collectors.counting()));

		if(Objects.nonNull(statusCountMap.get(DealStatusEnum.SUCCESS))&&statusCountMap.get(DealStatusEnum.SUCCESS)>0){
			if("36".equals(user.getOrganId())){
				throw new BizException("您已预约过此课程");
			}
			throw new BizException("您已购买过此课程");
		}else if(CollectionUtils.isEmpty(oldOrders)){
			if(classGroup.getStudentNum()>=classGroup.getExpectStudentNum()){
				throw new BizException("该课程人数已达上限");
			}
			//更新班级人数，如果订单支付失败则减少
			this.updateVipGroupStudentNumAndStatus(vipGroup.getId(),classGroup,1,false);

			ClassGroupStudentMapper classGroupStudentMapper=classGroupStudentMapperDao.query(classGroup.getId(),user.getId());
			if(Objects.isNull(classGroupStudentMapper)){
				classGroupStudentMapper=new ClassGroupStudentMapper(classGroup.getId(),user.getId().intValue());
				classGroupStudentMapper.setGroupType(GroupType.VIP);
				classGroupStudentMapper.setMusicGroupId(vipGroup.getId().toString());
				classGroupStudentMapperDao.insert(classGroupStudentMapper);
			}else{
				classGroupStudentMapper.setStatus(ClassGroupStudentStatusEnum.NORMAL);
			}
		}

		List<CourseSchedule> courseSchedules = JSON.parseArray(vipGroup.getCourseSchedulesJson(),CourseSchedule.class);
		courseScheduleService.checkNewCourseSchedules(courseSchedules,false,false);

		StudentPaymentOrder studentPaymentOrder=new StudentPaymentOrder();
		studentPaymentOrder.setUserId(user.getId());
        studentPaymentOrder.setGroupType(GroupType.VIP);
		String orderNo=idGeneratorService.generatorId("payment") + "";
		studentPaymentOrder.setOrderNo(orderNo);
		studentPaymentOrder.setStatus(DealStatusEnum.ING);
		studentPaymentOrder.setType(OrderTypeEnum.SMALL_CLASS_TO_BUY);
		studentPaymentOrder.setExpectAmount(vipGroup.getTotalPrice());
		studentPaymentOrder.setMusicGroupId(vipGroup.getId().toString());
		studentPaymentOrder.setActualAmount(studentPaymentOrder.getExpectAmount());
		studentPaymentOrder.setMusicGroupId(vipGroup.getId().toString());
		studentPaymentOrder.setClassGroupId(classGroup.getId());
		studentPaymentOrder.setOrganId(vipGroup.getOrganId());
		studentPaymentOrder.setVersion(0);
		studentPaymentOrderDao.insert(studentPaymentOrder);

		BigDecimal amount=vipGroup.getTotalPrice();
		BigDecimal balance = BigDecimal.ZERO;
		if("36".equals(user.getOrganId())){
			studentPaymentRouteOrderService.addRouteOrder(orderNo, vipGroup.getOrganId(), vipGroup.getTotalPrice());
			studentPaymentOrder.setPaymentChannel("BALANCE");
			studentPaymentOrder.setActualAmount(new BigDecimal(0));
			studentPaymentOrder.setBalancePaymentAmount(amount);
			studentPaymentOrder.setStatus(DealStatusEnum.SUCCESS);
			studentPaymentOrder.setUpdateTime(date);
			this.orderCallback(studentPaymentOrder);
			Map<String,Object> result=new HashMap<>();
			result.put("orderNo",studentPaymentOrder.getOrderNo());
			return result;
		}else if(vipGroupBuyParams.isUseBalancePayment() || amount.doubleValue() == 0){
			SysUserCashAccount userCashAccount = sysUserCashAccountService.getLocked(user.getId());
			if(userCashAccount == null){
				throw new BizException("用户账户找不到");
			}
			studentPaymentOrder.setPaymentChannel("BALANCE");
			if(userCashAccount.getBalance().subtract(vipGroup.getTotalPrice()).doubleValue() >= 0){
				studentPaymentRouteOrderService.addRouteOrder(orderNo, vipGroup.getOrganId(), vipGroup.getTotalPrice());
				// 更新订单信息
				studentPaymentOrder.setActualAmount(new BigDecimal(0));
				studentPaymentOrder.setBalancePaymentAmount(amount);
				studentPaymentOrder.setStatus(DealStatusEnum.SUCCESS);
				studentPaymentOrder.setUpdateTime(date);
				studentPaymentOrder.setOrganId(vipGroup.getOrganId());
		        studentPaymentOrder.setRoutingOrganId(vipGroup.getOrganId());

				this.orderCallback(studentPaymentOrder);

				sysUserCashAccountService.updateBalance(user.getId(), amount.negate(),PlatformCashAccountDetailTypeEnum.PAY_FEE,"VIP课购买");

				Map<String,Object> result=new HashMap<>();
				result.put("orderNo",studentPaymentOrder.getOrderNo());

				return result;
			}else{
				if (userCashAccount.getBalance().doubleValue() > 0) {
					balance = userCashAccount.getBalance();
					sysUserCashAccountService.updateBalance(user.getId(), balance.negate(), PlatformCashAccountDetailTypeEnum.PAY_FEE, "VIP课购买");
					amount = amount.subtract(userCashAccount.getBalance());
					studentPaymentOrder.setActualAmount(amount);
					studentPaymentOrder.setBalancePaymentAmount(userCashAccount.getBalance());
				} else {
					studentPaymentOrder.setBalancePaymentAmount(new BigDecimal(0));
				}
			}
		}
		if(!"36".equals(user.getOrganId())&& CertificateTypeEnum.IDENTITY.getCode().equals(user.getCertificateType())){
			try {
				contractService.register(user.getId(),user.getRealName(),user.getIdCardNo(),user.getPhone());
			} catch (Exception e) {
				LOGGER.error("[{}]小课购买协议生成错误：{}", vipGroup.getId(), e.getCause());
			}
		}

		String baseApiUrl = sysConfigDao.findConfigValue("base_api_url");
		//分类费用 course，instrument，accessories，other
		Map<String, BigDecimal> classFee = new HashMap<>();
		classFee.put("course",amount);
		classFee.put("instrument",BigDecimal.ZERO);
		classFee.put("accessories",BigDecimal.ZERO);
		classFee.put("other",BigDecimal.ZERO);
			Map<String,Object> payMap = payService.getPayMap(
					amount,
					balance,
					orderNo,
					baseApiUrl+"/api-student/studentOrder/notify",
					baseApiUrl+"/api-student/studentOrder/paymentResult?orderNo=" + orderNo,
					"vip课购买",
					vipGroup.getName(),
					vipGroup.getOrganId(),
					"vipBuy"
			);

			studentPaymentOrder.setOrganId(vipGroup.getOrganId());
			studentPaymentOrder.setRoutingOrganId(vipGroup.getOrganId());
			studentPaymentOrder.setMerNos((String) payMap.get("routingMerNos"));
			studentPaymentOrder.setPaymentChannel((String) payMap.get("type"));
			studentPaymentOrder.setUpdateTime(date);
			studentPaymentOrderService.update(studentPaymentOrder);

			return payMap;

	}

	@Override
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class, isolation = Isolation.READ_COMMITTED)
	public void orderCallback(StudentPaymentOrder order) {
		/*
		根据回调信息调整订单状态及vip课程状态等相关信息
		 */
		Long vipGroupId=Long.parseLong(order.getMusicGroupId());
		Integer userId = order.getUserId();
		boolean isOk=order.getStatus().equals(DealStatusEnum.SUCCESS);

		StudentPaymentOrder studentPaymentOrder = studentPaymentOrderDao.lockOrder(order.getId());

		List<StudentPaymentOrder> userOrders = studentPaymentOrderDao.findUserBuyVipGroupOrder(userId, vipGroupId.intValue());
		Map<DealStatusEnum, List<StudentPaymentOrder>> statusOrdersMap = userOrders.stream().collect(Collectors.groupingBy(StudentPaymentOrder::getStatus));
		if(!CollectionUtils.isEmpty(statusOrdersMap.get(DealStatusEnum.SUCCESS))){
			studentPaymentOrderDao.update(order);
			return;
		}

		if(studentPaymentOrder.getStatus().equals(DealStatusEnum.SUCCESS)){
			return;
		}

		studentPaymentOrderDao.update(order);

		ClassGroup classGroup=classGroupDao.get(order.getClassGroupId());

		//将学生加入到班级，更新班级报名状态及人数信息
		if(!isOk){
			if(CollectionUtils.isEmpty(statusOrdersMap.get(DealStatusEnum.ING))||(!CollectionUtils.isEmpty(statusOrdersMap.get(DealStatusEnum.ING))&&statusOrdersMap.get(DealStatusEnum.ING).size()<=1)){
				updateVipGroupStudentNumAndStatus(vipGroupId,classGroup,-1,false);
				classGroupStudentMapperDao.deleteClassGroupStudent(classGroup.getId().longValue(),userId);
			}
			if (studentPaymentOrder.getBalancePaymentAmount() != null && studentPaymentOrder.getBalancePaymentAmount().doubleValue() > 0) {
				sysUserCashAccountService.updateBalance(userId, studentPaymentOrder.getBalancePaymentAmount(), PlatformCashAccountDetailTypeEnum.REFUNDS,
						"VIP课购买失败");
			}
			return;
		}

		try {
			if(classGroup.getDelFlag()==1){
				updateVipGroupStudentNumAndStatus(vipGroupId, classGroup,0,true);
			}
		} catch (Exception e) {
			LOGGER.error("小课[{}]开课失败：{}",vipGroupId,e.getCause());
		}

		SysUserCashAccount sysUserCashAccount = sysUserCashAccountService.get(userId);

		VipGroup vipGroup = vipGroupDao.get(vipGroupId);

		//插入缴费明细
		//收入
		if(Objects.nonNull(order.getActualAmount())&&order.getActualAmount().compareTo(BigDecimal.ZERO)!=0){
			SysUserCashAccountDetail sysUserIncomeCashAccountDetail = new SysUserCashAccountDetail();
			sysUserIncomeCashAccountDetail.setUserId(userId);
			sysUserIncomeCashAccountDetail.setType(PlatformCashAccountDetailTypeEnum.RECHARGE);
			sysUserIncomeCashAccountDetail.setStatus(DealStatusEnum.SUCCESS);
			sysUserIncomeCashAccountDetail.setAmount(order.getActualAmount());
			sysUserIncomeCashAccountDetail.setBalance(sysUserCashAccount.getBalance().add(order.getActualAmount()));
			sysUserIncomeCashAccountDetail.setAttribute(order.getTransNo());
			sysUserIncomeCashAccountDetail.setChannel(studentPaymentOrder.getPaymentChannel());
			sysUserIncomeCashAccountDetail.setComAmount(studentPaymentOrder.getComAmount());
			sysUserIncomeCashAccountDetail.setPerAmount(studentPaymentOrder.getPerAmount());

			//支出
			SysUserCashAccountDetail sysUserExpendCashAccountDetail = new SysUserCashAccountDetail();
			sysUserExpendCashAccountDetail.setUserId(userId);
			sysUserExpendCashAccountDetail.setType(PlatformCashAccountDetailTypeEnum.PAY_FEE);
			sysUserExpendCashAccountDetail.setStatus(DealStatusEnum.SUCCESS);
			sysUserExpendCashAccountDetail.setAmount(order.getActualAmount().negate());
			sysUserExpendCashAccountDetail.setBalance(sysUserCashAccount.getBalance());
			sysUserExpendCashAccountDetail.setAttribute(order.getTransNo());
			sysUserExpendCashAccountDetail.setChannel(studentPaymentOrder.getPaymentChannel());
			if(studentPaymentOrder.getComAmount() != null){
				sysUserExpendCashAccountDetail.setComAmount(studentPaymentOrder.getComAmount().negate());
			}
			if(studentPaymentOrder.getPerAmount() != null){
				sysUserExpendCashAccountDetail.setPerAmount(studentPaymentOrder.getPerAmount().negate());
			}

			sysUserCashAccountDetailService.insert(sysUserIncomeCashAccountDetail);
			sysUserCashAccountDetailService.insert(sysUserExpendCashAccountDetail);
		}
		Map<Integer,String> map = new HashMap<>(1);
		map.put(userId,userId.toString());
		sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG, MessageTypeEnum.STUDENT_PUSH_VIP_BUY, map, null, 0, "2","STUDENT",
				vipGroup.getName());

		//更新所属分部列表
		List<Integer> organIds = classGroupDao.findStudentOrganIdsByClassGroup(classGroup.getId().longValue());
		organIds.add(vipGroup.getOrganId());
		HashSet<Integer> hashSet = new HashSet<>(organIds);
		String organIdsString = StringUtils.join(hashSet, ",");
		vipGroup.setOrganIdList(organIdsString);
		classGroup=classGroupDao.get(order.getClassGroupId());
		if(classGroup.getDelFlag()==0&&classGroup.getExpectStudentNum().equals(classGroup.getStudentNum())){
			vipGroup.setStatus(VipGroupStatusEnum.PROGRESS);
		}
		vipGroupDao.update(vipGroup);

		try {
			contractService.transferVipGroupCoursesContract(userId,vipGroupId);
		} catch (Exception e) {
			LOGGER.error(MessageFormatter.arrayFormat("小课[{}]购买协议错误:{}", vipGroupId, e.getMessage()), e);
		}
	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public void applyRefund(Long vipGroupId) {
        if(true){
            throw new BizException("暂不支持退课");
        }
		SysUser sysUser = sysUserFeignService.queryUserInfo();
		if (null == sysUser) {
			throw new BizException("获取用户信息失败");
		}
		Integer userId = sysUser.getId();
		StudentApplyRefunds studentApplyRefunds=new StudentApplyRefunds();
		StudentPaymentOrder studentPaymentOrder = studentPaymentOrderDao.findByStudentVipGroup(vipGroupId,userId,DealStatusEnum.SUCCESS.getCode());
		if(null==studentPaymentOrder){
			throw new BizException("未找到相关订单信息！");
		}
		VipGroup vipGroup=vipGroupDao.get(vipGroupId);
		//剩余课时数
		int surplusCourses = studentPaymentOrderDao.countSurplusCourseByMusicGroupAndUser(vipGroup.getId().toString(), userId);
		if(surplusCourses<=0){
			throw new BizException("此vip课程没有剩余排课");
		}
		Date now=new Date();
        BigDecimal surplusCourseFee;
        List<StudentCourseInfoDto> userCourseInfos = courseScheduleDao.findUserCourseInfos(GroupType.VIP, vipGroupId.toString(), userId, null);
        if(CollectionUtils.isEmpty(userCourseInfos)&&vipGroup.getStatus().equals(VipGroupStatusEnum.APPLYING)){
            if(Objects.isNull(studentPaymentOrder)){
                surplusCourseFee=new BigDecimal(0);
            }else{
                surplusCourseFee=studentPaymentOrder.getActualAmount();
            }
        }else if(!CollectionUtils.isEmpty(userCourseInfos)){
            BigDecimal historyPrice=new BigDecimal(0);
            BigDecimal allPrice=new BigDecimal(0);
            for (StudentCourseInfoDto userCourseInfo : userCourseInfos) {
                allPrice=allPrice.add(userCourseInfo.getExpectPrice());
                if(now.after(userCourseInfo.getStartClassTime())){
                    historyPrice=historyPrice.add(userCourseInfo.getTeachMode().equals(TeachModeEnum.ONLINE)?vipGroup.getOnlineClassesUnitPrice():vipGroup.getOfflineClassesUnitPrice());
                }
            }
            surplusCourseFee=allPrice.subtract(historyPrice);
            if(surplusCourseFee.longValue()<0){
                surplusCourseFee=new BigDecimal(0);
            }
        }else{
            surplusCourseFee=new BigDecimal(0);
        }
        if(Objects.isNull(surplusCourseFee)){
            surplusCourseFee = new BigDecimal(0);
        }
        VipGroupCategory vipGroupCategory = vipGroupCategoryDao.get(vipGroup.getVipGroupCategoryId().intValue());

        if(vipGroupCategory.getStudentNum()<=1){
            surplusCourseFee = surplusCourseFee.multiply(new BigDecimal(0.8)).setScale(CommonConstants.DECIMAL_FINAL_PLACE, BigDecimal.ROUND_HALF_UP);
        }else{
            surplusCourseFee = surplusCourseFee.multiply(new BigDecimal(0.7)).setScale(CommonConstants.DECIMAL_FINAL_PLACE, BigDecimal.ROUND_HALF_UP);
        }

		studentApplyRefunds.setExpectAmount(surplusCourseFee);
		studentApplyRefunds.setStatus(StudentApplyRefundsStatus.ING);
		String orderNo=StringUtils.join(new String[]{userId.toString(),String.valueOf(System.currentTimeMillis())});
		studentApplyRefunds.setOrderNo(orderNo);
		studentApplyRefunds.setOrigPaymentOrderId(studentPaymentOrder.getId());
		studentApplyRefunds.setUserId(userId);
		studentApplyRefundsDao.insert(studentApplyRefunds);
		Set<Integer> roleIds = new HashSet<>(1);
		roleIds.add(SysUserRole.EDUCATIONAL_TEACHER);
		Map<String,Object> memo = new HashMap<>(2);
		memo.put("Id",studentApplyRefunds.getId());
		memo.put("type","VIPGROUP");
		sysMessageService.batchSeoMessage(musicGroupDao.queryUserIdByRoleId(roleIds,sysUser.getOrganId()),MessageTypeEnum.BACKSTAGE_STUDENT_APPLY_QUIT_COURSE,JSONObject.toJSONString(memo),sysUser.getUsername());
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void applyRefundForStudent(Long vipGroupId, Integer studentId, BigDecimal amount) {
		if(Objects.isNull(vipGroupId)||Objects.isNull(studentId)){
			throw new BizException("请指定小课与学生");
		}
		VipGroup vipGroup=vipGroupDao.get(vipGroupId);
		if(Objects.isNull(vipGroup)){
			throw new BizException("指定的课程不存在");
		}
		if(vipGroup.getStatus().equals(VipGroupStatusEnum.CANCEL)){
			throw new BizException("不能对已停止的课程进行此操作");
		}

        List<StudentApplyRefunds> studentApplyRefunds = studentApplyRefundsDao.findByGroupAndUser(vipGroupId.toString(), GroupType.VIP.getCode(), studentId);
		if(!CollectionUtils.isEmpty(studentApplyRefunds)){
		    throw new BizException("此学生存在退课申请，请到系统日志中查看");
        }

        ClassGroup classGroup = classGroupDao.findByVipGroup(vipGroupId, null);

		ClassGroupStudentMapper classStudentMapperByUserIdAndClassGroupId = classGroupStudentMapperDao.query(classGroup.getId(),
				studentId);

		if(Objects.isNull(classStudentMapperByUserIdAndClassGroupId)){
			throw new BizException("指定学生不在此课程中");
		}

		if(classStudentMapperByUserIdAndClassGroupId.getStatus().equals(ClassGroupStudentStatusEnum.QUIT)){
			throw new BizException("当前学生已经是退学状态");
		}

        if(classStudentMapperByUserIdAndClassGroupId.getStatus().equals(ClassGroupStudentStatusEnum.QUIT_SCHOOL)){
			classStudentMapperByUserIdAndClassGroupId.setStatus(ClassGroupStudentStatusEnum.QUIT);
			classGroupStudentMapperDao.update(classStudentMapperByUserIdAndClassGroupId);
			studentPauseInfoDao.deleteUserPauseInfoWithGroup(GroupType.VIP, vipGroupId.toString(), studentId);

			classGroup.setStudentNum(classGroup.getStudentNum()-1);
			classGroupDao.update(classGroup);
			return;
        }
		if(Objects.isNull(amount)){
			throw new BizException("请确定退费金额");
		}

		Map<String, BigDecimal> studentSurplusCourseFee = getStudentSurplusCourseFee(vipGroupId, studentId);
		BigDecimal suplusCourseFee = studentSurplusCourseFee.get("suplusCourseOriginalFee");
		if(amount.compareTo(suplusCourseFee)>0){
			throw new BizException("学员最大可退费金额为{}元", suplusCourseFee.toString());
		}

		sysUserCashAccountService.updateBalance(studentId, amount);
		SysUserCashAccount sysUserCashAccount = sysUserCashAccountService.get(studentId);
		SysUserCashAccountDetail sysUserCashAccountDetail = new SysUserCashAccountDetail();
		sysUserCashAccountDetail.setUserId(studentId);
		sysUserCashAccountDetail.setType(PlatformCashAccountDetailTypeEnum.REFUNDS);
		sysUserCashAccountDetail.setStatus(DealStatusEnum.SUCCESS);
		sysUserCashAccountDetail.setAmount(amount);
		sysUserCashAccountDetail.setBalance(sysUserCashAccount.getBalance());
		sysUserCashAccountDetail.setAttribute(studentId.toString());
		sysUserCashAccountDetailDao.insert(sysUserCashAccountDetail);

		classStudentMapperByUserIdAndClassGroupId.setStatus(ClassGroupStudentStatusEnum.QUIT);
		classGroupStudentMapperDao.update(classStudentMapperByUserIdAndClassGroupId);

		courseScheduleService.batchDeleteMusicGroupCourseWithStudent(vipGroupId.toString(),studentId,GroupType.VIP);

        List<Integer> studentPaymentIds = courseScheduleStudentPaymentDao.findNotStartCourseStudentPaymentIdsWithClassGroupAndStudent(classGroup.getId(), studentId);
        if(!CollectionUtils.isEmpty(studentPaymentIds)){
            courseScheduleStudentPaymentDao.batchDeleteWithID(studentPaymentIds);
        }

        if(!vipGroup.getStatus().equals(VipGroupStatusEnum.APPLYING)){
			courseScheduleTeacherSalaryService.updateVipGroupCourseTeacherSalary(vipGroupId.intValue(), vipGroup.getUserId());
		}

		classGroup.setStudentNum(classGroup.getStudentNum()-1);

        classGroupDao.update(classGroup);

		//学员退出班级群
		imGroupMemberService.quit(classGroup.getId().longValue(), studentId);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void pauseForStudent(Long vipGroupId, Integer studentId) {
		if(Objects.isNull(vipGroupId)||Objects.isNull(studentId)){
			throw new BizException("请指定小课与学生");
		}
		VipGroup vipGroup=vipGroupDao.get(vipGroupId);
		if(Objects.isNull(vipGroup)){
			throw new BizException("指定的课程不存在");
		}
		if(!VipGroupStatusEnum.PROGRESS.equals(vipGroup.getStatus())){
			throw new BizException("当前课程组状态非进行中，无法进行该操作");
		}
		List<StudentApplyRefunds> studentApplyRefunds = studentApplyRefundsDao.findByGroupAndUser(vipGroupId.toString(), GroupType.VIP.getCode(), studentId);
		if(!CollectionUtils.isEmpty(studentApplyRefunds)){
			throw new BizException("此学生存在退课申请，请到系统日志中查看");
		}

		ClassGroup classGroup = classGroupDao.findByVipGroup(vipGroupId, null);

		ClassGroupStudentMapper classStudentMapperByUserIdAndClassGroupId = classGroupStudentMapperDao.query(classGroup.getId(),
				studentId);

		if(Objects.isNull(classStudentMapperByUserIdAndClassGroupId)){
			throw new BizException("指定学生不在此课程中");
		}

		if(classStudentMapperByUserIdAndClassGroupId.getStatus().equals(ClassGroupStudentStatusEnum.QUIT)){
			throw new BizException("当前学生已经退学");
		}

		if(classStudentMapperByUserIdAndClassGroupId.getStatus().equals(ClassGroupStudentStatusEnum.QUIT_SCHOOL)){
			throw new BizException("当前学生已是休学状态");
		}

        BigDecimal surplusCourseFee = courseScheduleStudentPaymentDao.countSurplusCourseFee(classGroup.getId(), studentId);

		if(Objects.isNull(surplusCourseFee)){
			surplusCourseFee=new BigDecimal(0);
		}

		Map<String, Object> pauseInfos = new HashMap<>();
		//学生剩余课时
        List<StudentCourseInfoDto> userSurplusCourseInfoByGroup = courseScheduleDao.findUserSurplusCourseInfoByGroup(GroupType.VIP, vipGroupId.toString(), studentId);

        int[] teachModeSequence=new int[userSurplusCourseInfoByGroup.size()];
        List<BigDecimal> coursePrices = new ArrayList<>();
        List<Long> courseScheduleIds=new ArrayList<>();
        for (int i=0;i<userSurplusCourseInfoByGroup.size();i++) {
            teachModeSequence[i] = userSurplusCourseInfoByGroup.get(i).getTeachMode().equals(TeachModeEnum.ONLINE)?1:0;
			coursePrices.add(userSurplusCourseInfoByGroup.get(i).getExpectPrice());
			courseScheduleIds.add(userSurplusCourseInfoByGroup.get(i).getId());
        }
        pauseInfos.put("teaChModeSequence", teachModeSequence);
        pauseInfos.put("coursePriceInfo",coursePrices);

        StudentPauseInfo  studentPauseInfo=new StudentPauseInfo();
		studentPauseInfo.setUserId(studentId);
		studentPauseInfo.setGroupType(GroupType.VIP);
		studentPauseInfo.setMusicGroupId(vipGroup.getId().intValue());
		studentPauseInfo.setClassGroupId(classGroup.getId());
        studentPauseInfo.setCoursesJson(JSON.toJSONString(pauseInfos));
        studentPauseInfo.setSurplusCourseNum(userSurplusCourseInfoByGroup.size());

        studentPauseInfoDao.insert(studentPauseInfo);

        sysUserCashAccountService.appendCourseBalance(studentId, surplusCourseFee,PlatformCashAccountDetailTypeEnum.REFUNDS,"学生休学剩余课时转化为课程余额");
		classStudentMapperByUserIdAndClassGroupId.setStatus(ClassGroupStudentStatusEnum.QUIT_SCHOOL);
		classGroupStudentMapperDao.update(classStudentMapperByUserIdAndClassGroupId);

		if(!CollectionUtils.isEmpty(courseScheduleIds)){
			studentAttendanceDao.deleteByCourseAndUser(courseScheduleIds,studentId);
		}

		List<Integer> studentPaymentIds = courseScheduleStudentPaymentDao.findNotStartCourseStudentPaymentIdsWithClassGroupAndStudent(classGroup.getId(), studentId);
		if(!CollectionUtils.isEmpty(studentPaymentIds)){
			courseScheduleStudentPaymentDao.batchDeleteWithID(studentPaymentIds);
		}

		int studentCourseNum = classGroupStudentMapperDao.countClassGroupNormalStudentNum(classGroup.getId());
		if(studentCourseNum<=0&&classGroup.getStudentNum().equals(classGroup.getExpectStudentNum())){
			vipGroup.setStatus(VipGroupStatusEnum.PAUSE);
			List<CourseSchedule> groupNotFinishCourses = courseScheduleDao.findGroupNotFinishCourses(vipGroupId.toString(), GroupType.VIP);
			List<Long> csIds = groupNotFinishCourses.stream().map(CourseSchedule::getId).collect(Collectors.toList());
			if(!CollectionUtils.isEmpty(csIds)){
				courseScheduleTeacherSalaryDao.batchDeleteByCourseScheduleIds(csIds);
				courseScheduleDao.batchDeleteCourseSchedules(csIds);
				teacherAttendanceDao.batchDeleteByCourseSchedules(csIds);
			}
			vipGroupDao.update(vipGroup);
		}

		courseScheduleTeacherSalaryService.updateVipGroupCourseTeacherSalary(vipGroupId.intValue(), vipGroup.getUserId());
	}

    @Override
	@Transactional(rollbackFor = Exception.class)
    public void recoverForStudent(StudentRecoverDto studentRecoverInfo) {
		if(Objects.isNull(studentRecoverInfo.getVipGroupId())||Objects.isNull(studentRecoverInfo.getUserId())){
			throw new BizException("请指定小课与学生");
		}
		Date now=new Date();
		VipGroup vipGroup=vipGroupDao.get(studentRecoverInfo.getVipGroupId().longValue());
		if(Objects.isNull(vipGroup)){
			throw new BizException("指定的课程不存在");
		}
		if(vipGroup.getStatus().equals(VipGroupStatusEnum.CANCEL)){
			throw new BizException("不能对已停止的课程进行此操作");
		}
		if(vipGroup.getStatus().equals(VipGroupStatusEnum.FINISHED)){
			throw new BizException("此课程已结束");
		}
		List<StudentApplyRefunds> studentApplyRefunds = studentApplyRefundsDao.findByGroupAndUser(studentRecoverInfo.getVipGroupId().toString(), GroupType.VIP.getCode(), studentRecoverInfo.getUserId());
		if(!CollectionUtils.isEmpty(studentApplyRefunds)){
			throw new BizException("此学生存在退课申请，请到系统日志中查看");
		}
		VipGroupDefaultClassesUnitPrice vipGroupDefaultClassesUnitPrice = vipGroupDefaultClassesUnitPriceDao.getByVipGroup(vipGroup.getId());
		if(Objects.isNull(vipGroupDefaultClassesUnitPrice)){
			throw new BizException("课程单价设置错误");
		}

		ClassGroup classGroup = classGroupDao.findByVipGroup(studentRecoverInfo.getVipGroupId().longValue(), null);

		Integer oldTeacherId=vipGroup.getUserId();
		if(Objects.nonNull(studentRecoverInfo.getTeacherId())&&!studentRecoverInfo.getTeacherId().equals(vipGroup.getUserId())){
			vipGroup.setUserId(studentRecoverInfo.getTeacherId());
			
			imGroupMemberService.quit(classGroup.getId().longValue(), oldTeacherId);

			imGroupMemberService.join(classGroup.getId().longValue(), vipGroup.getUserId(), "指导老师", false);
		}

		ClassGroupStudentMapper classStudentMapperByUserIdAndClassGroupId = classGroupStudentMapperDao.query(classGroup.getId(),
				studentRecoverInfo.getUserId());

		if(Objects.isNull(classStudentMapperByUserIdAndClassGroupId)){
			throw new BizException("指定学生不在此课程中");
		}

		if(!classStudentMapperByUserIdAndClassGroupId.getStatus().equals(ClassGroupStudentStatusEnum.QUIT_SCHOOL)){
			throw new BizException("当前学生不是休学状态");
		}

		StudentPauseInfo studentPauseInfo = studentPauseInfoDao.findByGroupAndUser(GroupType.VIP, studentRecoverInfo.getVipGroupId().toString(), studentRecoverInfo.getUserId());
		if(Objects.isNull(studentPauseInfo)){
			throw new BizException("未找到休学信息");
		}

		classStudentMapperByUserIdAndClassGroupId.setStatus(ClassGroupStudentStatusEnum.NORMAL);
		classGroupStudentMapperDao.update(classStudentMapperByUserIdAndClassGroupId);

		if(Objects.nonNull(studentRecoverInfo.getTeacherId())){
			vipGroup.setUserId(studentRecoverInfo.getTeacherId());
		}

		Map<String, Object> courseInfo = JSON.parseObject(studentPauseInfo.getCoursesJson(), Map.class);
		List<BigDecimal> coursePrices = (List<BigDecimal>) courseInfo.get("coursePriceInfo");
		coursePrices.sort(Comparator.naturalOrder());
		Collections.reverse(coursePrices);

		if(vipGroup.getStatus().equals(VipGroupStatusEnum.PAUSE)){
			List<StudentPauseInfo> studentPauseInfos=studentPauseInfoDao.findByGroup(GroupType.VIP, vipGroup.getId().toString());
			StudentPauseInfo studentPauseInfo1 = studentPauseInfos.stream().min(Comparator.comparing(StudentPauseInfo::getSurplusCourseNum)).get();
			Map<String, Object> courseInfo1 = JSON.parseObject(studentPauseInfo1.getCoursesJson(), Map.class);
			Integer[] teachModeSequence1=JSON.parseArray(courseInfo1.get("teaChModeSequence").toString(), Integer.class).stream().toArray(Integer[]::new);
			if(teachModeSequence1.length<=0){
				throw new BizException("此学员无剩余课时");
			}
			studentRecoverInfo.setCourseCount(teachModeSequence1.length);
			List<CourseSchedule> newCourseSchedules = courseScheduleService.createCourses(studentRecoverInfo,false);
			for(int i=0;i<newCourseSchedules.size();i++){
				if(newCourseSchedules.get(i).getStartClassTime().before(now)){
					throw new BizException("排课起始时间不得小于当前时间");
				}
				newCourseSchedules.get(i).setName(vipGroup.getName());
				newCourseSchedules.get(i).setGroupType(GroupType.VIP);
				newCourseSchedules.get(i).setMusicGroupId(vipGroup.getId().toString());
				newCourseSchedules.get(i).setClassGroupId(classGroup.getId());
				newCourseSchedules.get(i).setStatus(CourseStatusEnum.NOT_START);
				newCourseSchedules.get(i).setActualTeacherId(vipGroup.getUserId());
				newCourseSchedules.get(i).setTeacherId(vipGroup.getUserId());
				newCourseSchedules.get(i).setType(CourseSchedule.CourseScheduleType.VIP);
				newCourseSchedules.get(i).setTeachMode(teachModeSequence1[i]==0?TeachModeEnum.OFFLINE:TeachModeEnum.ONLINE);
				if(newCourseSchedules.get(i).getTeachMode().equals(TeachModeEnum.OFFLINE)){
					newCourseSchedules.get(i).setSchoolId(vipGroup.getTeacherSchoolId());
				}
				newCourseSchedules.get(i).setOrganId(vipGroup.getOrganId());
			}

			CourseSchedule courseSchedule = newCourseSchedules.stream().max(Comparator.comparing(CourseSchedule::getClassDate)).get();
			if(vipGroup.getCoursesExpireDate().compareTo(courseSchedule.getEndClassTime())<=0&&!DateUtil.isSameDay(vipGroup.getCoursesExpireDate(), courseSchedule.getEndClassTime())){
				throw new BizException("排课时间不可超过{}", DateUtil.dateToString(vipGroup.getCoursesExpireDate(), "yyyy年MM月dd日"));
			}

			courseScheduleService.batchAddCourseSchedule(newCourseSchedules);

			ClassGroupTeacherMapper oldClassGroupTeacherMapper = classGroupTeacherMapperDao.findByClassGroupAndTeacher(classGroup.getId(),oldTeacherId);
			if(Objects.nonNull(oldClassGroupTeacherMapper)){
				ClassGroupTeacherMapper classGroupTeacherMapper=new ClassGroupTeacherMapper();
				BeanUtils.copyProperties(oldClassGroupTeacherMapper,classGroupTeacherMapper);
				classGroupTeacherMapper.setUserId(vipGroup.getUserId());
				classGroupTeacherMapper.setCreateTime(now);
				classGroupTeacherMapper.setUpdateTime(now);
				classGroupTeacherMapperDao.delete(oldClassGroupTeacherMapper.getId());
				classGroupTeacherMapperDao.insert(classGroupTeacherMapper);
			}

			Map<String, BigDecimal> salaryMap = countVipGroupPredictFee(vipGroup, vipGroup.getUserId(), null, null);

			//创建老师单节课课酬信息
			courseScheduleTeacherSalaryService.createCourseScheduleTeacherVipSalary(vipGroup,
					newCourseSchedules,
					salaryMap.get("onlineTeacherSalary"),
					salaryMap.get("offlineTeacherSalary"));
		}

		BigDecimal surplusCourseFee = new BigDecimal(0);

		List<CourseSchedule> surplusCourseWithGroup = courseScheduleDao.findSurplusCourseWithGroup(GroupType.VIP, studentRecoverInfo.getVipGroupId().toString());
		surplusCourseWithGroup.sort(Comparator.comparing(CourseSchedule::getStartClassTime));

		if(coursePrices.size()<surplusCourseWithGroup.size()){
			throw new BizException("剩余课时不足,无法与现有课时对齐");
		}


		CourseSchedule lastCourseSchedule = surplusCourseWithGroup.stream().max(Comparator.comparing(CourseSchedule::getClassDate)).get();
		if(vipGroup.getCoursesExpireDate().compareTo(lastCourseSchedule.getEndClassTime())<=0&&!DateUtil.isSameDay(vipGroup.getCoursesExpireDate(), lastCourseSchedule.getEndClassTime())){
			throw new BizException("排课时间不可超过{}", DateUtil.dateToString(vipGroup.getCoursesExpireDate(), "yyyy年MM月dd日"));
		}

		List<CourseScheduleStudentPayment> courseScheduleStudentPaymentList = new ArrayList<>();
		for (int i=0;i<surplusCourseWithGroup.size();i++) {
			CourseScheduleStudentPayment courseScheduleStudentPayment = new CourseScheduleStudentPayment();
			courseScheduleStudentPayment.setGroupType(GroupType.VIP);
			courseScheduleStudentPayment.setMusicGroupId(studentRecoverInfo.getVipGroupId().toString());
			courseScheduleStudentPayment.setMusicGroupId(classGroup.getMusicGroupId());
			courseScheduleStudentPayment.setCourseScheduleId(surplusCourseWithGroup.get(i).getId());
			courseScheduleStudentPayment.setUserId(studentRecoverInfo.getUserId());
			courseScheduleStudentPayment.setExpectPrice(coursePrices.get(i));
			courseScheduleStudentPayment.setActualPrice(coursePrices.get(i));
			courseScheduleStudentPayment.setOriginalPrice(TeachModeEnum.ONLINE.equals(surplusCourseWithGroup.get(i))?vipGroupDefaultClassesUnitPrice.getOnlineClassesUnitPrice():vipGroupDefaultClassesUnitPrice.getOfflineClassesUnitPrice());
			courseScheduleStudentPayment.setCreateTime(now);
			courseScheduleStudentPayment.setUpdateTime(now);
			courseScheduleStudentPayment.setClassGroupId(classGroup.getId());
			courseScheduleStudentPaymentList.add(courseScheduleStudentPayment);
			surplusCourseFee=surplusCourseFee.add(coursePrices.get(i));
		}
		if(!CollectionUtils.isEmpty(courseScheduleStudentPaymentList)){
			courseScheduleStudentPaymentDao.batchInsert(courseScheduleStudentPaymentList);
		}
		sysUserCashAccountService.appendCourseBalance(studentRecoverInfo.getUserId(), surplusCourseFee.negate(),PlatformCashAccountDetailTypeEnum.PAY_FEE, "学生复学扣除课程余额");
		studentPauseInfo.setDelFlag(1);
		studentPauseInfoDao.update(studentPauseInfo);
        vipGroup.setStatus(VipGroupStatusEnum.PROGRESS);
        vipGroupDao.update(vipGroup);
        classGroup.setTotalClassTimes(courseScheduleDao.countClassGroupCourses(classGroup.getId()));
        classGroupDao.update(classGroup);
		courseScheduleTeacherSalaryService.updateVipGroupCourseTeacherSalary(vipGroup.getId().intValue(),oldTeacherId);
		imUserFriendService.refreshGroupImUserFriend(classGroup.getMusicGroupId(),classGroup.getGroupType());
	}

    @Override
    public StudentRecoverInfoDto getStudentPauseInfo(Long vipGroupId, Integer studentId) {
        if(Objects.isNull(vipGroupId)||Objects.isNull(studentId)){
            throw new BizException("请指定小课与学生");
        }
        VipGroup vipGroup=vipGroupDao.get(vipGroupId);
        if(Objects.isNull(vipGroup)){
            throw new BizException("指定的课程不存在");
        }
        if(vipGroup.getStatus().equals(VipGroupStatusEnum.CANCEL)){
            throw new BizException("不能对已停止的课程进行此操作");
        }

        ClassGroup classGroup = classGroupDao.findByVipGroup(vipGroupId, null);

        ClassGroupStudentMapper classStudentMapperByUserIdAndClassGroupId = classGroupStudentMapperDao.query(classGroup.getId(),studentId);

        if(Objects.isNull(classStudentMapperByUserIdAndClassGroupId)){
            throw new BizException("未找到指定学生");
        }

        if(!classStudentMapperByUserIdAndClassGroupId.getStatus().equals(ClassGroupStudentStatusEnum.QUIT_SCHOOL)){
            throw new BizException("当前学生不是休学状态");
        }

        StudentPauseInfo studentPauseInfo = studentPauseInfoDao.findByGroupAndUser(GroupType.VIP, vipGroupId.toString(), studentId);
        if(Objects.isNull(studentPauseInfo)){
            throw new BizException("未找到此学生休学信息");
        }
        Map<String, Object> courseInfo = JSON.parseObject(studentPauseInfo.getCoursesJson(), Map.class);
        List<BigDecimal> coursePrices = (List<BigDecimal>) courseInfo.get("coursePriceInfo");

        StudentRecoverInfoDto studentRecoverInfoDto=new StudentRecoverInfoDto();
        studentRecoverInfoDto.setVipGroupId(vipGroupId.intValue());
        studentRecoverInfoDto.setTeacherId(vipGroup.getUserId());
        studentRecoverInfoDto.setStudentId(studentPauseInfo.getUserId());
        studentRecoverInfoDto.setIsPause(vipGroup.getStatus().equals(VipGroupStatusEnum.PAUSE)?1:0);
		Map<BigDecimal, Long> collect = coursePrices.stream().collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
		studentRecoverInfoDto.setGiveCourseTimes(Objects.isNull(collect.get(new BigDecimal("0.00")))?0:collect.get(new BigDecimal("0.00")).intValue());
		studentRecoverInfoDto.setTotalCourseTimes(coursePrices.size()-studentRecoverInfoDto.getGiveCourseTimes());
		studentRecoverInfoDto.setExpireDate(vipGroup.getCoursesExpireDate());

		return studentRecoverInfoDto;
    }

    @Override
	@Transactional(rollbackFor = Exception.class)
	public Map<String, BigDecimal> getStudentSurplusCourseFee(Long vipGroupId, Integer studentId) {
		if(Objects.isNull(vipGroupId)||Objects.isNull(studentId)){
			throw new BizException("请指定课程和学生");
		}
		VipGroup vipGroup = vipGroupDao.get(vipGroupId);
		if(Objects.isNull(vipGroup)){
			throw new BizException("未找到指定vip课");
		}
		if(vipGroup.getStatus().equals(VipGroupStatusEnum.CANCEL)){
			throw new BizException("不能对已停止的课程进行退课操作");
		}
		Map<String,BigDecimal> result=new HashMap<>();
		Date now = new Date();
        BigDecimal bigDecimal;
        List<StudentCourseInfoDto> userCourseInfos = courseScheduleDao.findUserCourseInfos(GroupType.VIP, vipGroupId.toString(), studentId, null);
		if(CollectionUtils.isEmpty(userCourseInfos)&&vipGroup.getStatus().equals(VipGroupStatusEnum.APPLYING)){
            StudentPaymentOrder studentPaymentOrder = studentPaymentOrderDao.findByStudentVipGroup(vipGroupId, studentId, DealStatusEnum.SUCCESS.getCode());
            if(Objects.isNull(studentPaymentOrder)){
                bigDecimal=new BigDecimal(0);
            }else{
                bigDecimal=studentPaymentOrder.getActualAmount();
            }

			result.put("suplusCourseOriginalFee", bigDecimal);
        }else if(!CollectionUtils.isEmpty(userCourseInfos)){
            BigDecimal historyPrice=new BigDecimal(0);
            BigDecimal allPrice=new BigDecimal(0);
            for (StudentCourseInfoDto userCourseInfo : userCourseInfos) {
                allPrice=allPrice.add(userCourseInfo.getExpectPrice());
                if(now.after(userCourseInfo.getStartClassTime())){
                    historyPrice=historyPrice.add(userCourseInfo.getTeachMode().equals(TeachModeEnum.ONLINE)?vipGroup.getOnlineClassesUnitPrice():vipGroup.getOfflineClassesUnitPrice());
                }
            }
            bigDecimal=allPrice.subtract(historyPrice);
            if(bigDecimal.longValue()<0){
                bigDecimal=new BigDecimal(0);
            }
			result.put("suplusCourseOriginalFee", allPrice);
        }else{
		    bigDecimal=new BigDecimal(0);
			result.put("suplusCourseOriginalFee", bigDecimal);
        }
		ClassGroup classGroup = classGroupDao.findByVipGroup(vipGroupId, null);
		if(Objects.isNull(classGroup)){
			throw new BizException("未找到对应班级");
		}
		if(Objects.isNull(bigDecimal)){
			bigDecimal = new BigDecimal(0);
		}

        VipGroupCategory vipGroupCategory = vipGroupCategoryDao.get(vipGroup.getVipGroupCategoryId().intValue());

		if(vipGroupCategory.getStudentNum()<=1){
            bigDecimal = bigDecimal.multiply(new BigDecimal(0.8)).setScale(CommonConstants.DECIMAL_FINAL_PLACE, BigDecimal.ROUND_HALF_UP);
        }else{
            bigDecimal = bigDecimal.multiply(new BigDecimal(0.7)).setScale(CommonConstants.DECIMAL_FINAL_PLACE, BigDecimal.ROUND_HALF_UP);
        }

		result.put("suplusCourseFee", bigDecimal);

		if(VipGroupStatusEnum.APPLYING.equals(vipGroup.getStatus())){
			StudentPaymentOrder studentPaymentOrder = studentPaymentOrderDao.findByStudentVipGroup(vipGroupId, studentId, DealStatusEnum.SUCCESS.getCode());
			if(Objects.nonNull(studentPaymentOrder)){
				result.put("suplusCourseOriginalFee", studentPaymentOrder.getExpectAmount());
				if(vipGroupCategory.getStudentNum()<=1){
					result.put("suplusCourseFee", studentPaymentOrder.getExpectAmount().multiply(new BigDecimal(0.8)).setScale(CommonConstants.DECIMAL_FINAL_PLACE, BigDecimal.ROUND_HALF_UP));
				}else{
					result.put("suplusCourseFee", studentPaymentOrder.getExpectAmount().multiply(new BigDecimal(0.7)).setScale(CommonConstants.DECIMAL_FINAL_PLACE, BigDecimal.ROUND_HALF_UP));
				}
			}
		}

		return result;
	}

	@Transactional(rollbackFor = Exception.class)
	@Override
	public void applyRefundAudit(Long id, StudentApplyRefundsStatus status, String remark,BigDecimal amount) {

		StudentApplyRefunds studentApplyRefunds = studentApplyRefundsDao.get(id);
		if (studentApplyRefunds == null) {
			throw new BizException("退课申请记录不存在");
		}

		StudentPaymentOrder studentPaymentOrder = studentPaymentOrderDao.get(studentApplyRefunds.getOrigPaymentOrderId());
		if (null == studentPaymentOrder) {
			throw new BizException("未找到原订单信息！");
		}

		if(status ==StudentApplyRefundsStatus.ING){
			throw new BizException("状态不正确");
		}

		studentApplyRefunds.setStatus(status);
		if (studentApplyRefunds.getStatus() == StudentApplyRefundsStatus.DONE) {
			studentApplyRefunds.setActualAmount(amount);
		}else{
			studentApplyRefunds.setActualAmount(new BigDecimal(0));
		}
		studentApplyRefunds.setRemark(remark);
		studentApplyRefunds.setUpdateTime(new Date());
		studentApplyRefundsDao.update(studentApplyRefunds);
		switch (studentApplyRefunds.getStatus()) {
			case DONE:
				sysUserCashAccountService.updateBalance(studentApplyRefunds.getUserId(), studentApplyRefunds.getActualAmount());
				SysUserCashAccount sysUserCashAccount = sysUserCashAccountService.get(studentApplyRefunds.getUserId().intValue());
				SysUserCashAccountDetail sysUserCashAccountDetail = new SysUserCashAccountDetail();
				sysUserCashAccountDetail.setUserId(studentApplyRefunds.getUserId());
				sysUserCashAccountDetail.setType(PlatformCashAccountDetailTypeEnum.REFUNDS);
				sysUserCashAccountDetail.setStatus(DealStatusEnum.SUCCESS);
				sysUserCashAccountDetail.setAmount(amount);
				sysUserCashAccountDetail.setBalance(sysUserCashAccount.getBalance());
				sysUserCashAccountDetail.setAttribute(studentApplyRefunds.getId().toString());
				sysUserCashAccountDetailDao.insert(sysUserCashAccountDetail);

				ClassGroupStudentMapper classStudentMapperByUserIdAndClassGroupId = classGroupStudentMapperDao.query(studentPaymentOrder.getClassGroupId(),
						studentPaymentOrder.getUserId());

				if(Objects.isNull(classStudentMapperByUserIdAndClassGroupId)){
				    throw new BizException("此学员不在指定班级上");
                }

				classStudentMapperByUserIdAndClassGroupId.setStatus(ClassGroupStudentStatusEnum.QUIT);
				classGroupStudentMapperDao.update(classStudentMapperByUserIdAndClassGroupId);

//				ClassGroup classGroup=new ClassGroup();
//				classGroup.setId(classStudentMapperByUserIdAndClassGroupId.getClassGroupId());
//				classGroup.setStudentNum(classGroupStudentMapperDao.countClassGroupStudentNum(classGroup.getId()));
//				classGroupDao.update(classGroup);

                List<Integer> studentPaymentIds = courseScheduleStudentPaymentDao.findNotStartCourseStudentPaymentIdsWithClassGroupAndStudent(classStudentMapperByUserIdAndClassGroupId.getClassGroupId(), studentApplyRefunds.getUserId());
                if(!CollectionUtils.isEmpty(studentPaymentIds)){
                    courseScheduleStudentPaymentDao.batchDeleteWithID(studentPaymentIds);
                }

				courseScheduleService.batchDeleteMusicGroupCourseWithStudent(studentPaymentOrder.getMusicGroupId(),studentApplyRefunds.getUserId(),GroupType.VIP);


				courseScheduleTeacherSalaryService.updateVipGroupCourseTeacherSalary(Integer.parseInt(studentPaymentOrder.getMusicGroupId()), null);

				//学员退出班级群
				imGroupMemberService.quit(studentPaymentOrder.getClassGroupId().longValue(), studentApplyRefunds.getUserId());

				break;
			case REJECT:

				break;
			default:
				throw new BizException("审核状态错误!");
		}
	}

	@Override
	public Map<String, Object> findVipGroupSalarys(VipGroupSalaryQueryInfo queryInfo) {

    	if(Objects.isNull(queryInfo.getVipGroupId())){
    		throw new BizException("请指定vip课程!");
		}

		VipGroup vipGroup = vipGroupDao.get(queryInfo.getVipGroupId());

    	if(Objects.isNull(vipGroup)){
    		throw new BizException("未找到指定vip课");
		}

		PageInfo pageInfo = new PageInfo<>(queryInfo.getPage(), queryInfo.getRows());
		Map<String, Object> params = new HashMap<String, Object>();
		MapUtil.populateMap(params, queryInfo);

		List<VipGroupSalaryDto> dataList = null;
		int count = courseScheduleTeacherSalaryDao.countVipGroupSalarys(params);
		if (count > 0) {
			pageInfo.setTotal(count);
			params.put("offset", pageInfo.getOffset());
			dataList = courseScheduleTeacherSalaryDao.findVipGroupSalarys(params);
			List<Long> courseScheduleIds = dataList.stream().map(VipGroupSalaryDto::getCourseScheduleId).collect(Collectors.toList());
			List<Map<Integer, BigDecimal>> courseAmountMapList = courseScheduleTeacherSalaryDao.countActualAmount(courseScheduleIds);
			Map<Integer, BigDecimal> courseAmountMap = MapUtil.convertIntegerMap(courseAmountMapList);
			if(!CollectionUtils.isEmpty(dataList)){
				dataList.forEach(vipGroupSalaryDto -> {
					if(Objects.isNull(vipGroupSalaryDto.getExpectSalary())){
						vipGroupSalaryDto.setExpectSalary(new BigDecimal(0));
					}
					if(Objects.isNull(vipGroupSalaryDto.getActualSalary())){
						vipGroupSalaryDto.setActualSalary(new BigDecimal(0));
						vipGroupSalaryDto.setDeductionFee(new BigDecimal(0));
						vipGroupSalaryDto.setIsSalary(YesOrNoEnum.NO);
					}else{
						vipGroupSalaryDto.setDeductionFee(vipGroupSalaryDto.getExpectSalary().subtract(vipGroupSalaryDto.getActualSalary()));
						vipGroupSalaryDto.setIsSalary(YesOrNoEnum.YES);
					}
					BigDecimal actualAmount = courseAmountMap.get(vipGroupSalaryDto.getCourseScheduleId());
					if(Objects.nonNull(actualAmount)){
						vipGroupSalaryDto.setDeductionFee(actualAmount);
					}
				});
			}
		}
		if (count == 0) {
			dataList = new ArrayList<>();
		}
		pageInfo.setRows(dataList);

		VipGroupSalaryBaseInfo vipGroupSalaryBaseInfo = vipGroupDao.getVipGroupSalaryInfo(queryInfo.getVipGroupId());
		if(Objects.isNull(vipGroupSalaryBaseInfo)){
			vipGroupSalaryBaseInfo=new VipGroupSalaryBaseInfo();
		}
		//预计总课酬
		if(Objects.isNull(vipGroupSalaryBaseInfo.getExpectTotalSalary())){
			vipGroupSalaryBaseInfo.setExpectTotalSalary(new BigDecimal(0));
		}
		//实际总课酬
		if(Objects.isNull(vipGroupSalaryBaseInfo.getTotalSalary())){
			vipGroupSalaryBaseInfo.setTotalSalary(new BigDecimal(0));
		}

		ClassGroup classGroup = classGroupDao.findByVipGroup(vipGroup.getId(),null);

		//扣费笔数
		vipGroupSalaryBaseInfo.setFeeDeductionNum(vipGroupDao.countStudentPaymentNum(classGroup.getId()));
		//扣费总额
		if(vipGroupSalaryBaseInfo.getFeeDeductionNum()>0){
			vipGroupSalaryBaseInfo.setTotalFeeDeduction(vipGroupDao.countStudentPaymentFee(classGroup.getId()));
		}else{
			vipGroupSalaryBaseInfo.setTotalFeeDeduction(new BigDecimal(0));
		}

		BigDecimal totalCoursePrice= studentPaymentOrderDao.sumGroupIncomeFee(vipGroup.getId().toString(),GroupType.VIP.getCode());
		if(Objects.isNull(totalCoursePrice)){
			totalCoursePrice=new BigDecimal(0);
		}

		//课程总价
		vipGroupSalaryBaseInfo.setTotalCoursePrice(totalCoursePrice);

		List<Map<String, BigDecimal>> teacherSalaryCount = courseScheduleTeacherSalaryDao.countTeacherOnlineOfflineSalaryByClass(classGroup.getId());
		Map<String,BigDecimal> teacherTeachModeSalaryMap = MapUtil.convertIntegerMap(teacherSalaryCount);
		vipGroupSalaryBaseInfo.setTotalOfflineTeacherSalary(teacherTeachModeSalaryMap.get(TeachModeEnum.OFFLINE.getCode()));
		vipGroupSalaryBaseInfo.setTotalOnlineTeacherSalary(teacherTeachModeSalaryMap.get(TeachModeEnum.ONLINE.getCode()));

		Map<String,Object> result=new HashMap<>();
		result.put("pageInfo",pageInfo);
		result.put("baseInfo",vipGroupSalaryBaseInfo);
		return result;
	}

	@Override
	public List<String> findVipGroupAttendanceStudents(Long courseScheduleId) {
    	if(Objects.isNull(courseScheduleId)){
    		throw new BizException("请指定课程");
		}
		return courseScheduleDao.findStudentNamesByCourseSchedule(courseScheduleId);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void stopGroup(Long vipGroupId,String stopReason) {
    	if(Objects.isNull(vipGroupId)){
    		throw new BizException("请指定vip课");
		}
		VipGroup vipGroup = vipGroupDao.get(vipGroupId);
    	if(Objects.isNull(vipGroup)){
    		throw new BizException("该课程不存在");
		}
    	if(vipGroup.getStatus()==VipGroupStatusEnum.CANCEL){
    		throw new BizException("该课程已结束或者已被停止,无法进行此操作");
		}
		ClassGroup classGroup = classGroupDao.findByMusicGroupAndType(vipGroupId.toString(), "VIP");
    	if(Objects.isNull(classGroup)){
    		throw new BizException("班级不存在");
		}
		vipGroup.setStopReason(stopReason);
		List<Long> courseScheduleIds = courseScheduleDao.findVipGroupNotStartCourseScheduleIds(vipGroupId.toString(),GroupType.VIP.getCode());
    	if(vipGroup.getStatus()==VipGroupStatusEnum.NOT_START){
			vipGroup.setStatus(VipGroupStatusEnum.CANCEL);
    		vipGroupDao.update(vipGroup);
    		classGroup.setDelFlag(1);
    		classGroupDao.update(classGroup);
    		if(courseScheduleIds != null && courseScheduleIds.size() > 0){
				courseScheduleDao.batchDeleteCourseSchedules(courseScheduleIds);
				courseScheduleTeacherSalaryDao.batchDeleteByCourseScheduleIds(courseScheduleIds);
			}
			teacherPush(vipGroup);
//			stopVipPush(vipGroup.getId(),vipGroup.getName());
    		return;
		}

		Integer studentNum = classGroupStudentMapperDao.countClassGroupStudentNum(classGroup.getId());
		if(studentNum>0){
			throw new BizException("无法停止课程，需要全部学员退学后，才能停止，请先操作学员退学。");
		}

		List<Map<Integer, BigDecimal>> maps = vipGroupDao.countSurplusCourseFee(vipGroupId);
    	if(CollectionUtils.isEmpty(maps)||(maps.size()==1&&Objects.isNull(maps.get(0)))){
			if(courseScheduleIds != null && courseScheduleIds.size() > 0){
				courseScheduleDao.batchDeleteCourseSchedules(courseScheduleIds);
				courseScheduleTeacherSalaryDao.batchDeleteByCourseScheduleIds(courseScheduleIds);
			}
			vipGroup.setStatus(VipGroupStatusEnum.CANCEL);
			vipGroupDao.update(vipGroup);
			classGroup.setDelFlag(1);
			classGroupDao.update(classGroup);
			teacherPush(vipGroup);
//			stopVipPush(vipGroup.getId(),vipGroup.getName());
			return;
		}
		Map<Integer, BigDecimal> studentSurplusClassFees = MapUtil.convertIntegerMap(maps);
    	for(Integer userId:studentSurplusClassFees.keySet()){
			StudentPaymentOrder studentPaymentOrder = studentPaymentOrderDao.findByStudentVipGroup(vipGroupId,userId,DealStatusEnum.SUCCESS.getCode());
			if(null==studentPaymentOrder){
				throw new BizException("无法停止课程，需要全部学员退学后，才能停止，请先操作学员退学。");
			}
			sysUserCashAccountService.updateBalance(userId.intValue(),studentSurplusClassFees.get(userId));
			SysUserCashAccount sysUserCashAccount = sysUserCashAccountService.get(userId.intValue());
			SysUserCashAccountDetail sysUserCashAccountDetail=new SysUserCashAccountDetail();
			sysUserCashAccountDetail.setUserId(userId.intValue());
			sysUserCashAccountDetail.setType(PlatformCashAccountDetailTypeEnum.REFUNDS);
			sysUserCashAccountDetail.setStatus(DealStatusEnum.SUCCESS);
			sysUserCashAccountDetail.setAmount(studentSurplusClassFees.get(userId));
			sysUserCashAccountDetail.setBalance(sysUserCashAccount.getBalance());
			sysUserCashAccountDetail.setAttribute(studentPaymentOrder.getOrderNo());
			sysUserCashAccountDetailDao.insert(sysUserCashAccountDetail);
		}

		vipGroup.setStatus(VipGroupStatusEnum.CANCEL);
		vipGroupDao.update(vipGroup);
		classGroup.setDelFlag(1);
		classGroupDao.update(classGroup);

		courseScheduleDao.batchDeleteCourseSchedules(courseScheduleIds);
		courseScheduleTeacherSalaryDao.batchDeleteByCourseScheduleIds(courseScheduleIds);
		courseScheduleStudentPaymentDao.deleteByCourseSchedule(courseScheduleIds);
		teacherAttendanceDao.batchDeleteByCourseSchedules(courseScheduleIds);
		//vip课停止通知
//		Teacher teacher = teacherDao.get(vipGroup.getUserId());
//		Map<Integer,String> map = new HashMap<>(1);
//		map.put(vipGroup.getUserId(),vipGroup.getUserId().toString());
//		sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG,MessageTypeEnum.TEACHER_PUSH_VIP_COURSE_STOP,
//				map,null,0,"1",vipGroup.getName());
		teacherPush(vipGroup);
//		stopVipPush(vipGroup.getId(),vipGroup.getName());
	}

	private void teacherPush(VipGroup vipGroup){
		Map<Integer,String> map = new HashMap<>(1);
		map.put(vipGroup.getUserId(),vipGroup.getUserId().toString());
		sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG,MessageTypeEnum.TEACHER_PUSH_VIP_COURSE_STOP,
				map,null,0,"1","TEACHER",vipGroup.getName());
	}

	private void stopVipPush(Long vipGroupId,String vipGroupName){
		String refundPeriod = sysConfigDao.findConfigValue(SysConfigService.REFUND_PERIOD);
		Map<Integer,String> map1 = MapUtil.convertMybatisMap(classGroupStudentMapperDao.queryStudentIdMap(vipGroupId));
		if(map1 != null && map1.size() > 0){
			sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG,MessageTypeEnum.PUSH_STUDENT_VIP_STOP,
					map1,null,0,null,"STUDENT",vipGroupName,refundPeriod);
		}
//		老师推送消息
		Map<Integer,String> map2 = MapUtil.convertMybatisMap(classGroupStudentMapperDao.queryTeacherIdMap(vipGroupId));
		if(map2 != null && map2.size() > 0){
			sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG,MessageTypeEnum.PUSH_TEACHER_VIP_STOP,
					map2,null,0,null,"TEACHER",vipGroupName);
		}
	}

	@Override
	@Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
	public boolean awardedMonthlyRewards() {
		//获取上个月的时间
		Date months = DateUtil.addMonths(new Date(), -1);
		String firstDayOfMonth = DateUtil.format(DateUtil.getFirstDayOfMonth(months),DateUtil.ISO_EXPANDED_DATE_FORMAT);
		String lastDayOfMonth =  DateUtil.format(DateUtil.getLastDayOfMonth(months),DateUtil.ISO_EXPANDED_DATE_FORMAT);

		List<TaskRewardsRulesDto> rewardsRulesDtos = courseScheduleRewardsRulesService.queryVipGroupTeacherClassTimesByMonth(firstDayOfMonth,lastDayOfMonth);
		if(rewardsRulesDtos != null && rewardsRulesDtos.size() > 0){
			List<Integer> activeIds = rewardsRulesDtos.stream().map(e -> e.getActiveId()).collect(Collectors.toList());
			List<CourseScheduleRewardsRules> rewardsRules = courseScheduleRewardsRulesService.findByIds(activeIds);
			Map<Integer, List<CourseScheduleRewardsRules>> integerListMap = rewardsRules.stream().collect(Collectors.groupingBy(CourseScheduleRewardsRules::getId));
			String currentMonth = DateUtil.format(new Date(),DateUtil.ISO_YEAR_MONTH_FORMAT);
			rewardsRulesDtos.forEach(e->{
				//当前用户是否已经发放过上月奖励
				Integer num = sysUserCashAccountDetailDao.countByTypeAndTime(currentMonth,e.getTeacherId(),e.getActiveId());
				if(num == null || num == 0) {
					CourseScheduleRewardsRules rewardsRule = integerListMap.get(e.getActiveId()).get(0);
					List<RewardsRulesJsonDto> rulesJsonDtos = JSONObject.parseArray(rewardsRule.getRewardsRulesJson(), RewardsRulesJsonDto.class);
					BigDecimal money = BigDecimal.ZERO;
					//STAIR 阶梯, PER 累计, TOTAL
					RewardsRulesJsonDto dto;
					int times = e.getTimes();
					switch (rewardsRule.getRewardMode()) {
						case STAIR:
							for (int i = 0;i< rulesJsonDtos.size();i++){
								dto = rulesJsonDtos.get(i);
								if (e.getTimes() >= dto.getMin()) {
									//最后一个梯度
									if(rulesJsonDtos.size()-1 == i){
										money = money.add(dto.getMoney().multiply(new BigDecimal(times)));
									}else if(e.getTimes() >= dto.getMax()){
										times = Math.abs(dto.getMax() - times);
										money = money.add(dto.getMoney().multiply(new BigDecimal(dto.getMax()-dto.getMin()+1)));
									}else {
										money = money.add(dto.getMoney().multiply(new BigDecimal(times)));
									}
								}
							}
							break;
						case PER:
							for (int i = 0;i< rulesJsonDtos.size();i++){
								dto = rulesJsonDtos.get(i);
								if (e.getTimes() >= dto.getMin()) {
									money = dto.getMoney().multiply(new BigDecimal(times));
								}
							}
							break;
						case TOTAL:
							break;
					}
					if (money.doubleValue() > 0) {
						sysUserCashAccountDetailService.addCashAccountDetail(e.getTeacherId(), money, "", SysUserCashAccountDetailService.ORGAN,
								PlatformCashAccountDetailTypeEnum.REWARDS, null, DealStatusEnum.SUCCESS, "分部奖励", e.getActiveId().toString());
					}
				}
			});
		}
		return true;
	}

	@Override
	public List<School> querySchoolByUserId(Integer userId) {
		return vipGroupDao.querySchoolByUserId(userId);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void updateVipGroupBaseInfo(VipGroupApplyBaseInfoDto vipGroupApplyBaseInfo) {
		if(Objects.isNull(vipGroupApplyBaseInfo.getId())){
			throw new BizException("请指定vip课");
		}
		VipGroup oldVipGroupInfo = vipGroupDao.get(vipGroupApplyBaseInfo.getId());
		if(Objects.isNull(oldVipGroupInfo)){
			throw new BizException("指定的vip课不存在");
		}
		if(Objects.isNull(vipGroupApplyBaseInfo.getId())){
			return;
		}
		Date now=new Date();
		boolean isChange = false;
		if(Objects.nonNull(vipGroupApplyBaseInfo.getOnlineClassesUnitPrice())
				&&vipGroupApplyBaseInfo.getOnlineClassesUnitPrice().compareTo(oldVipGroupInfo.getOnlineClassesUnitPrice())!=0){
			oldVipGroupInfo.setOnlineClassesUnitPrice(vipGroupApplyBaseInfo.getOnlineClassesUnitPrice());
			isChange=true;
		}
		if(Objects.nonNull(vipGroupApplyBaseInfo.getOfflineClassesUnitPrice())
				&&vipGroupApplyBaseInfo.getOfflineClassesUnitPrice().compareTo(oldVipGroupInfo.getOfflineClassesUnitPrice())!=0){
			oldVipGroupInfo.setOfflineClassesUnitPrice(vipGroupApplyBaseInfo.getOfflineClassesUnitPrice());
			isChange=true;
		}
		if(Objects.nonNull(vipGroupApplyBaseInfo.getTeacherSchoolId())){
			oldVipGroupInfo.setTeacherSchoolId(vipGroupApplyBaseInfo.getTeacherSchoolId());
			courseScheduleDao.updateCourseSchoolByGroup(oldVipGroupInfo.getId().toString(), GroupType.VIP.getCode(), oldVipGroupInfo.getTeacherSchoolId());
			isChange=true;
		}
		if(Objects.nonNull(vipGroupApplyBaseInfo.getEducationalTeacherId())&&!vipGroupApplyBaseInfo.getEducationalTeacherId().equals(oldVipGroupInfo.getEducationalTeacherId())){
			ClassGroup classGroup = classGroupDao.findByMusicGroupAndType(oldVipGroupInfo.getId().toString(), GroupType.VIP.getCode());
			if(Objects.nonNull(oldVipGroupInfo.getEducationalTeacherId())){
				
				imGroupMemberService.quit(classGroup.getId().longValue(), oldVipGroupInfo.getEducationalTeacherId());
			}

			oldVipGroupInfo.setEducationalTeacherId(vipGroupApplyBaseInfo.getEducationalTeacherId());
			isChange=true;
			
			imGroupMemberService.join(classGroup.getId().longValue(), oldVipGroupInfo.getEducationalTeacherId(), "乐团主管", false);
		}
		if(Objects.nonNull(vipGroupApplyBaseInfo.getOrganId())&&!vipGroupApplyBaseInfo.getOrganId().equals(oldVipGroupInfo.getOrganId())){
			isChange=true;
			oldVipGroupInfo.setOrganId(vipGroupApplyBaseInfo.getOrganId());
		}
		//更新vip课
		if(isChange){
			oldVipGroupInfo.setUpdateTime(now);
			vipGroupDao.update(oldVipGroupInfo);
		}
		imUserFriendService.refreshGroupImUserFriend(oldVipGroupInfo.getId().toString(),GroupType.VIP);
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void appendVipGroupCourseSchedules(VipGroupApplyDto vipGroupApplyDto) {
		if(Objects.isNull(vipGroupApplyDto.getVipGroupApplyBaseInfo().getId())){
			throw new BizException("请指定vip课");
		}
		VipGroup vipGroup = vipGroupDao.get(vipGroupApplyDto.getVipGroupApplyBaseInfo().getId());
		if(Objects.isNull(vipGroup)){
			throw new BizException("指定的vip课不存在");
		}
		ClassGroup classGroup = classGroupDao.findByVipGroup(vipGroup.getId(), null);
		if(Objects.isNull(classGroup)){
			throw new BizException("班级不存在");
		}

		if(!vipGroup.getStatus().equals(VipGroupStatusEnum.PROGRESS)){
			throw new BizException("此状态的vip课程不支持加课");
		}

		VipGroupDefaultClassesUnitPrice vipGroupDefaultClassesUnitPrice = vipGroupDefaultClassesUnitPriceDao.getByVipGroup(vipGroup.getId());
		if(Objects.isNull(vipGroupDefaultClassesUnitPrice)){
			throw new BizException("课程单价设置错误");
		}

		Date now=new Date();

//		BigDecimal onlineCoursePrice = courseScheduleStudentPaymentDao.findVipGroupCoursePrice(vipGroup.getId().intValue(),TeachModeEnum.ONLINE.getCode());
//		if(Objects.isNull(onlineCoursePrice)||onlineCoursePrice.compareTo(new BigDecimal(0))==0){
//			onlineCoursePrice = vipGroup.getOnlineClassesUnitPrice();
//		}
//		BigDecimal offlineCoursePrice = courseScheduleStudentPaymentDao.findVipGroupCoursePrice(vipGroup.getId().intValue(),TeachModeEnum.OFFLINE.getCode());
//		if(Objects.isNull(offlineCoursePrice)||offlineCoursePrice.compareTo(new BigDecimal(0))==0){
//			offlineCoursePrice = vipGroup.getOfflineClassesUnitPrice();
//		}

		BigDecimal surplusCourseTotalPrice = new BigDecimal(0);
		BigDecimal singleClassPrice=vipGroupApplyDto.getSingleClassPrice();


		//课程信息调整
		for (CourseSchedule courseSchedule : vipGroupApplyDto.getCourseSchedules()) {
			if(courseSchedule.getTeachMode().equals(TeachModeEnum.OFFLINE)){
				courseSchedule.setSchoolId(vipGroup.getTeacherSchoolId());
			}
			courseSchedule.setTeacherId(vipGroup.getUserId());
			courseSchedule.setActualTeacherId(vipGroup.getUserId());
			courseSchedule.setStatus(CourseStatusEnum.NOT_START);
			courseSchedule.setType(CourseSchedule.CourseScheduleType.VIP);
			courseSchedule.setClassGroupId(classGroup.getId());
			courseSchedule.setGroupType(GroupType.VIP);
			courseSchedule.setMusicGroupId(vipGroup.getId().toString());
			courseSchedule.setName(vipGroup.getName());
			courseSchedule.setOrganId(vipGroup.getOrganId());
//			if (courseSchedule.getTeachMode().equals(TeachModeEnum.ONLINE)) {
//				surplusCourseTotalPrice = surplusCourseTotalPrice.add(onlineCoursePrice);
//			} else if (courseSchedule.getTeachMode().equals(TeachModeEnum.OFFLINE)) {
//				surplusCourseTotalPrice = surplusCourseTotalPrice.add(offlineCoursePrice);
//			}
			surplusCourseTotalPrice = surplusCourseTotalPrice.add(singleClassPrice);
		}

		courseScheduleService.batchAddCourseSchedule(vipGroupApplyDto.getCourseSchedules());

		Map<String, BigDecimal> map = countVipGroupPredictFee(vipGroup, vipGroup.getUserId(), null, null);

		BigDecimal teacherSalary=BigDecimal.ZERO;

		BigDecimal onlineTeacherSalary=null,offlineTeacherSalary=null,zero=new BigDecimal(0);

		if(Objects.nonNull(map)){
			onlineTeacherSalary=map.get("onlineTeacherSalary");
			offlineTeacherSalary=map.get("offlineTeacherSalary");
		}

		if(Objects.isNull(onlineTeacherSalary)){
		    onlineTeacherSalary = new BigDecimal(0);
        }

		if(Objects.isNull(offlineTeacherSalary)){
			offlineTeacherSalary = new BigDecimal(0);
		}

		//创建老师单节课课酬信息
		courseScheduleTeacherSalaryService.createCourseScheduleTeacherVipSalary(vipGroup,
				vipGroupApplyDto.getCourseSchedules(),
				onlineTeacherSalary,
				offlineTeacherSalary);


		List<ClassGroupStudentMapper> classGroupStudents = classGroupStudentMapperDao.findByClassGroup(classGroup.getId());

		Map<Integer,String> userRoleMap = new HashMap<Integer, String>();
		//生成学生单课缴费信息
		for (ClassGroupStudentMapper classGroupStudent : classGroupStudents) {
			SysUserCashAccount sysUserCashAccount = sysUserCashAccountService.get(classGroupStudent.getUserId());
			if(sysUserCashAccount.getCourseBalance().compareTo(surplusCourseTotalPrice)<0){
				throw new BizException("学生[{}]的课程余额不足",classGroupStudent.getUserName());
			}
			List<CourseScheduleStudentPayment> courseScheduleStudentPayments=new ArrayList<>();
			for (CourseSchedule vipGroupCourseSchedule : vipGroupApplyDto.getCourseSchedules()) {
				CourseScheduleStudentPayment courseScheduleStudentPayment = new CourseScheduleStudentPayment();
				courseScheduleStudentPayment.setGroupType(GroupType.VIP);
				courseScheduleStudentPayment.setMusicGroupId(vipGroup.getId().toString());
				courseScheduleStudentPayment.setClassGroupId(vipGroupCourseSchedule.getClassGroupId());
				courseScheduleStudentPayment.setCourseScheduleId(vipGroupCourseSchedule.getId());
				courseScheduleStudentPayment.setUserId(classGroupStudent.getUserId());
//				if(vipGroupCourseSchedule.getTeachMode().equals(TeachModeEnum.ONLINE)){
//					courseScheduleStudentPayment.setExpectPrice(onlineCoursePrice);
//				}else if(vipGroupCourseSchedule.getTeachMode().equals(TeachModeEnum.OFFLINE)){
//					courseScheduleStudentPayment.setExpectPrice(offlineCoursePrice);
//				}
				courseScheduleStudentPayment.setOriginalPrice(TeachModeEnum.ONLINE.equals(vipGroupCourseSchedule.getTeachMode())?vipGroupDefaultClassesUnitPrice.getOnlineClassesUnitPrice():vipGroupDefaultClassesUnitPrice.getOfflineClassesUnitPrice());
				courseScheduleStudentPayment.setExpectPrice(singleClassPrice);
				courseScheduleStudentPayment.setActualPrice(singleClassPrice);
				courseScheduleStudentPayment.setCreateTime(now);
				courseScheduleStudentPayment.setUpdateTime(now);
				courseScheduleStudentPayments.add(courseScheduleStudentPayment);
			}
			sysUserCashAccountService.updateCourseBalance(classGroupStudent.getUserId(),sysUserCashAccount.getCourseBalance().subtract(surplusCourseTotalPrice),PlatformCashAccountDetailTypeEnum.PAY_FEE,surplusCourseTotalPrice.negate(),"后台加课扣除课程余额");

			courseScheduleStudentPaymentDao.batchInsert(courseScheduleStudentPayments);
			userRoleMap.put(classGroupStudent.getUserId(), null);
		}

		classGroupService.updateClassGroupInfo(classGroup.getId());

//		courseScheduleStudentPaymentService.updateVipGiveCourse(vipGroup.getId());

		imGroupMemberService.join(classGroup.getId().longValue(), userRoleMap);
	}

	@Override
	@Transactional(rollbackFor = Exception.class, isolation = Isolation.READ_COMMITTED)
	public void addVipGroupStudents(Long vipGroupId, List<Integer> studentIds) {
		if(CollectionUtils.isEmpty(studentIds)){
			throw new BizException("请选择学生");
		}
		if(Objects.isNull(vipGroupId)){
			throw new BizException("请指定vip课程");
		}
		VipGroup vipGroup=vipGroupDao.get(vipGroupId);
		if(Objects.isNull(vipGroup)){
			throw new BizException("未找到指定的vip课程");
		}

		ClassGroup classGroup = classGroupDao.findByVipGroup(vipGroupId, null);

		if(classGroup.getStudentNum()>0&&(VipGroupStatusEnum.APPLYING.equals(vipGroup.getStatus()))){
			int i = studentPaymentOrderDao.countGroupOrderWithoutFailed(vipGroupId.toString(), GroupType.VIP);
			if(i>0){
				throw new BizException("已有学员购买了该课程组，无法添加，请走学员购买流程!");
			}
		}

		VipGroupDefaultClassesUnitPrice vipGroupDefaultClassesUnitPrice = vipGroupDefaultClassesUnitPriceDao.getByVipGroup(vipGroup.getId());
		if(Objects.isNull(vipGroupDefaultClassesUnitPrice)){
			throw new BizException("课程单价设置错误");
		}

		if(VipGroupStatusEnum.PAUSE.equals(vipGroup.getStatus())
				||VipGroupStatusEnum.FINISHED.equals(vipGroup.getStatus())
				||VipGroupStatusEnum.CANCEL.equals(vipGroup.getStatus())){
			throw new BizException("当前课程组已经停止，无法进行添加学员操作。");
		}

        Integer studentNum = classGroupStudentMapperDao.countClassGroupStudentNum(classGroup.getId());
        if(studentNum.compareTo(classGroup.getExpectStudentNum())>=0){
            throw new BizException("该班级人数已达上限");
        }

        Integer exitStudentNum = classGroupStudentMapperDao.countClassGroupExitStudentNum(classGroup.getId(), studentIds);
		if(exitStudentNum>0){
			throw new BizException("选择的学生中存在此课程中已存在的学生");
		}

		Date now=new Date();
        Map<Integer,String> userRoleMap = new HashMap<Integer, String>();

		if(vipGroup.getStatus().equals(VipGroupStatusEnum.APPLYING)||vipGroup.getStatus().equals(VipGroupStatusEnum.NOT_START)){
			List<CourseSchedule> courseSchedules = JSON.parseArray(vipGroup.getCourseSchedulesJson(),CourseSchedule.class);
			int courseNum = courseScheduleDao.countVipGroupCourses(vipGroupId.intValue(),"VIP");
			if(courseNum==0){
				courseScheduleService.batchAddCourseSchedule(courseSchedules);

				Map<String, BigDecimal> salaryMap = countVipGroupPredictFee(vipGroup, vipGroup.getUserId(), null, null);

				//创建老师单节课课酬信息
				courseScheduleTeacherSalaryService.createCourseScheduleTeacherVipSalary(vipGroup,
						courseSchedules,
						salaryMap.get("onlineTeacherSalary"),
						salaryMap.get("offlineTeacherSalary"));
			}
            userRoleMap.put(vipGroup.getUserId(), "指导老师");
            
            if(vipGroup.getEducationalTeacherId() != null){
                userRoleMap.put(vipGroup.getEducationalTeacherId(), "乐团主管");
            }
		}

		List<CourseSchedule> surplusCourses = courseScheduleDao.findByClassGroupAndStatus(classGroup.getId(), CourseStatusEnum.NOT_START.getCode());

		List<ClassGroupStudentMapper> classGroupStudentMappers=new ArrayList<>();

		List<ClassGroupStudentMapper> classGroupStudentsList = classGroupStudentMapperDao.findByClassGroupAndStudent(classGroup.getId(), studentIds);
		Map<Integer, List<ClassGroupStudentMapper>> classGroupStudentsMap = classGroupStudentsList.stream()
				.collect(Collectors.groupingBy(ClassGroupStudentMapper::getUserId));

		if(CollectionUtils.isEmpty(surplusCourses)){
			for (Integer studentId:studentIds) {
				//创建班级学生关联记录
				ClassGroupStudentMapper classGroupStudentMapper;

				List<ClassGroupStudentMapper> classGroupStudents = classGroupStudentsMap.get(studentId);
				if(!CollectionUtils.isEmpty(classGroupStudents)){
					classGroupStudentMapper = classGroupStudents.get(0);
					classGroupStudentMapper.setStatus(ClassGroupStudentStatusEnum.NORMAL);
					classGroupStudentMapperDao.update(classGroupStudentMapper);
				}else{
					classGroupStudentMapper=new ClassGroupStudentMapper();
					classGroupStudentMapper.setGroupType(classGroup.getGroupType());
					classGroupStudentMapper.setMusicGroupId(classGroup.getMusicGroupId());
					classGroupStudentMapper.setClassGroupId(classGroup.getId());
					classGroupStudentMapper.setStatus(ClassGroupStudentStatusEnum.NORMAL);
					classGroupStudentMapper.setUserId(studentId);
					classGroupStudentMappers.add(classGroupStudentMapper);
				}

				userRoleMap.put(studentId, null);
			}

			if(!CollectionUtils.isEmpty(classGroupStudentMappers)){
				classGroupStudentMapperDao.classGroupStudentsInsert(classGroupStudentMappers);
			}

			Integer currentStudentNum = classGroupStudentMapperDao.countClassGroupStudentNum(classGroup.getId());
			if((!vipGroup.getStatus().equals(VipGroupStatusEnum.FINISHED)
					||!vipGroup.getStatus().equals(VipGroupStatusEnum.CANCEL))
					&&currentStudentNum.compareTo(classGroup.getExpectStudentNum())>=0){
				vipGroup.setStatus(VipGroupStatusEnum.PROGRESS);
				vipGroupDao.update(vipGroup);
			}
			classGroup.setStudentNum(currentStudentNum);
			classGroup.setDelFlag(0);
			classGroupDao.update(classGroup);

			try {
				imGroupService.create(classGroup.getId().longValue(), null, classGroup.getName(), classGroup.getName(), vipGroup.getName(), null, null, GroupType.VIP.getCode());
				imGroupMemberService.join(classGroup.getId().longValue(), userRoleMap);
				imUserFriendService.refreshClassImUserFriend(classGroup.getId());
			} catch (Exception e) {
				e.printStackTrace();
			}
			return;
		}

		VipGroupActivity vipGroupActivity = null;
		if(Objects.nonNull(vipGroup.getVipGroupActivityId())){
			vipGroupActivity = vipGroupActivityDao.get(vipGroup.getVipGroupActivityId().intValue());
		}

		BigDecimal surplusCourseNum = new BigDecimal(surplusCourses.size());
		BigDecimal surplusCoursesPrice=new BigDecimal(0);
		boolean hasGiveClass=false;
		int onlineCourseTimes=0,
			offlineCourseTimes=0,
			onlineCourseTotalTimes=0,
			offlineCourseTotalTimes=0,
			giveClassTimes=0;
		if(vipGroup.getStatus().equals(VipGroupStatusEnum.APPLYING)
				&&Objects.nonNull(vipGroupActivity)
			&&vipGroupActivity.getType().equals(VipGroupActivityTypeEnum.GIVE_CLASS)
			&&surplusCourses.size()>=Integer.parseInt(vipGroupActivity.getAttribute1())){
			hasGiveClass=true;
			giveClassTimes=Integer.parseInt(vipGroupActivity.getAttribute2());
			surplusCourseNum=surplusCourseNum.subtract(new BigDecimal(giveClassTimes));
			Map<TeachModeEnum, List<CourseSchedule>> teachModeCourseMap = surplusCourses.stream()
					.collect(Collectors.groupingBy(CourseSchedule::getTeachMode));
			List<CourseSchedule> onlineCourses=teachModeCourseMap.get(TeachModeEnum.ONLINE);
			if(!CollectionUtils.isEmpty(onlineCourses)){
				onlineCourseTotalTimes=onlineCourses.size();
			}
			List<CourseSchedule> offlineCourses=teachModeCourseMap.get(TeachModeEnum.OFFLINE);
			if(!CollectionUtils.isEmpty(offlineCourses)){
				offlineCourseTotalTimes=offlineCourses.size();
			}
		}
		for (int i=0;i<surplusCourses.size();i++) {
			CourseSchedule courseSchedule=surplusCourses.get(i);
			if(courseSchedule.getTeachMode().equals(TeachModeEnum.OFFLINE)){
				offlineCourseTimes+=1;
			}else if(courseSchedule.getTeachMode().equals(TeachModeEnum.ONLINE)){
				onlineCourseTimes+=1;
			}
			if(hasGiveClass
					&&vipGroup.getGiveTeachMode() == courseSchedule.getTeachMode()){
				if(courseSchedule.getTeachMode().equals(TeachModeEnum.OFFLINE)
					&&offlineCourseTimes>(offlineCourseTotalTimes-giveClassTimes)){
					continue;
				}

				if(hasGiveClass
						&&vipGroup.getGiveTeachMode() == courseSchedule.getTeachMode()){
					if(courseSchedule.getTeachMode().equals(TeachModeEnum.ONLINE)
							&&onlineCourseTimes>(onlineCourseTotalTimes-giveClassTimes)){
						continue;
					}
				}
			}
			if(courseSchedule.getTeachMode().equals(TeachModeEnum.OFFLINE)){
				surplusCoursesPrice=surplusCoursesPrice.add(vipGroup.getOfflineClassesUnitPrice());
			}else if(courseSchedule.getTeachMode().equals(TeachModeEnum.ONLINE)){
				surplusCoursesPrice=surplusCoursesPrice.add(vipGroup.getOnlineClassesUnitPrice());
			}
		}

        BigDecimal discount=null;
		if(Objects.nonNull(vipGroupActivity)&&vipGroupActivity.getType().equals(VipGroupActivityTypeEnum.DISCOUNT)){
            discount=new BigDecimal(vipGroupActivity.getAttribute1()).divide(new BigDecimal(100), CommonConstants.DECIMAL_PLACE, BigDecimal.ROUND_DOWN);
            surplusCoursesPrice=surplusCoursesPrice.multiply(discount).setScale(CommonConstants.DECIMAL_FINAL_PLACE,BigDecimal.ROUND_HALF_UP);
        }

		//生成学生单课缴费信息
		for (Integer studentId:studentIds) {
			SysUserCashAccount sysUserCashAccount = sysUserCashAccountService.get(studentId);
			if(sysUserCashAccount.getCourseBalance().compareTo(surplusCoursesPrice)<0){
				throw new BizException("存在课程余额不足的学生");
			}
//			courseScheduleStudentPaymentService.createCourseScheduleStudentPaymentForVipGroup(vipGroupId,studentId);

			List<CourseScheduleStudentPayment> courseScheduleStudentPayments=new ArrayList<>();

			offlineCourseTimes=0;
			onlineCourseTimes=0;
			for (CourseSchedule vipGroupCourseSchedule : surplusCourses) {
				if(vipGroupCourseSchedule.getTeachMode().equals(TeachModeEnum.OFFLINE)){
					offlineCourseTimes+=1;
				}else if(vipGroupCourseSchedule.getTeachMode().equals(TeachModeEnum.ONLINE)){
					onlineCourseTimes+=1;
				}
				CourseScheduleStudentPayment courseScheduleStudentPayment = new CourseScheduleStudentPayment();
				courseScheduleStudentPayment.setGroupType(GroupType.VIP);
				courseScheduleStudentPayment.setMusicGroupId(vipGroupId.toString());
				courseScheduleStudentPayment.setClassGroupId(vipGroupCourseSchedule.getClassGroupId());
				courseScheduleStudentPayment.setCourseScheduleId(vipGroupCourseSchedule.getId());
				courseScheduleStudentPayment.setUserId(studentId);
                if(vipGroupCourseSchedule.getTeachMode().equals(TeachModeEnum.OFFLINE)){
					courseScheduleStudentPayment.setExpectPrice(vipGroup.getOfflineClassesUnitPrice());
					courseScheduleStudentPayment.setOriginalPrice(vipGroupDefaultClassesUnitPrice.getOfflineClassesUnitPrice());
                }else if(vipGroupCourseSchedule.getTeachMode().equals(TeachModeEnum.ONLINE)){
					courseScheduleStudentPayment.setExpectPrice(vipGroup.getOnlineClassesUnitPrice());
					courseScheduleStudentPayment.setOriginalPrice(vipGroupDefaultClassesUnitPrice.getOnlineClassesUnitPrice());
                }
				if(hasGiveClass
						&&vipGroup.getGiveTeachMode() == vipGroupCourseSchedule.getTeachMode()){
					if(vipGroupCourseSchedule.getTeachMode().equals(TeachModeEnum.OFFLINE)
							&&offlineCourseTimes>(offlineCourseTotalTimes-giveClassTimes)){
						courseScheduleStudentPayment.setExpectPrice(new BigDecimal(0));
					}
					if(vipGroupCourseSchedule.getTeachMode().equals(TeachModeEnum.ONLINE)
							&&onlineCourseTimes>(onlineCourseTotalTimes-giveClassTimes)){
						courseScheduleStudentPayment.setExpectPrice(new BigDecimal(0));
					}
				}
				if(Objects.nonNull(discount)){
                    courseScheduleStudentPayment.setExpectPrice(courseScheduleStudentPayment.getExpectPrice().multiply(discount).setScale(CommonConstants.DECIMAL_FINAL_PLACE,BigDecimal.ROUND_HALF_UP));
                }
				courseScheduleStudentPayment.setActualPrice(courseScheduleStudentPayment.getExpectPrice());
				courseScheduleStudentPayment.setCreateTime(now);
				courseScheduleStudentPayment.setUpdateTime(now);
				courseScheduleStudentPayments.add(courseScheduleStudentPayment);
			}
			courseScheduleStudentPaymentDao.batchInsert(courseScheduleStudentPayments);

			sysUserCashAccountService.updateCourseBalance(studentId,sysUserCashAccount.getCourseBalance().subtract(surplusCoursesPrice),PlatformCashAccountDetailTypeEnum.PAY_FEE, surplusCoursesPrice.negate(), "后台添加学员扣除课程余额");

			//创建班级学生关联记录
			ClassGroupStudentMapper classGroupStudentMapper;

			List<ClassGroupStudentMapper> classGroupStudents = classGroupStudentsMap.get(studentId);
			if(!CollectionUtils.isEmpty(classGroupStudents)){
				classGroupStudentMapper = classGroupStudents.get(0);
				classGroupStudentMapper.setStatus(ClassGroupStudentStatusEnum.NORMAL);
				classGroupStudentMapperDao.update(classGroupStudentMapper);
			}else{
				classGroupStudentMapper=new ClassGroupStudentMapper();
				classGroupStudentMapper.setGroupType(classGroup.getGroupType());
				classGroupStudentMapper.setMusicGroupId(classGroup.getMusicGroupId());
				classGroupStudentMapper.setClassGroupId(classGroup.getId());
				classGroupStudentMapper.setStatus(ClassGroupStudentStatusEnum.NORMAL);
				classGroupStudentMapper.setUserId(studentId);
				classGroupStudentMappers.add(classGroupStudentMapper);
			}

			userRoleMap.put(studentId, null);

			if(vipGroup.getOnlineClassesNum()>0){
				try {
					teacherCourseRewardService.addConvertReward(studentId, vipGroup.getUserId());
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}

		if(!CollectionUtils.isEmpty(classGroupStudentMappers)){
			classGroupStudentMapperDao.classGroupStudentsInsert(classGroupStudentMappers);
		}

		courseScheduleService.checkNewCourseSchedules(surplusCourses, false,false);

		VipGroupStatusEnum vipGroupStatus = vipGroup.getStatus();

        Integer currentStudentNum = classGroupStudentMapperDao.countClassGroupStudentNum(classGroup.getId());
		if((!vipGroup.getStatus().equals(VipGroupStatusEnum.FINISHED)
				||!vipGroup.getStatus().equals(VipGroupStatusEnum.CANCEL))
            &&currentStudentNum.compareTo(classGroup.getExpectStudentNum())>=0){
            vipGroup.setStatus(VipGroupStatusEnum.PROGRESS);
            vipGroupDao.update(vipGroup);
        }
		classGroup.setStudentNum(currentStudentNum);
		classGroup.setDelFlag(0);
		classGroupDao.update(classGroup);
		classGroupService.updateClassGroupInfo(classGroup.getId());

		courseScheduleTeacherSalaryService.updateVipGroupCourseTeacherSalary(vipGroupId.intValue(),null);

		studentDao.updateStudentServiceTag(null, studentIds, YesOrNoEnum.YES.getCode());

		try {
			imGroupService.create(classGroup.getId().longValue(), null, classGroup.getName(), classGroup.getName(), vipGroup.getName(), null, null, GroupType.VIP.getCode());
			imGroupMemberService.join(classGroup.getId().longValue(), userRoleMap);

			imUserFriendService.refreshGroupImUserFriend(vipGroup.getId().toString(),GroupType.VIP);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	@Override
	@Transactional(rollbackFor = Exception.class)
	public void stopVipGroupWithNoCreate() {
		List<VipGroup> noCreateSuccessVipGroups = vipGroupDao.findNoCreateSuccessVipGroup();
		if(CollectionUtils.isEmpty(noCreateSuccessVipGroups)){
			return;
		}
		//用户账户资金变动信息列表
		List<SysUserCashAccountDetail> userCashAccountDetails = new ArrayList<>();
		for (VipGroup noCreateSuccessVipGroup : noCreateSuccessVipGroups) {
			int i = courseScheduleStudentPaymentDao.countStudentCourseNumWithGroup(GroupType.VIP, noCreateSuccessVipGroup.getId().toString());
			if(i>0){
				continue;
			}
			noCreateSuccessVipGroup.setStatus(VipGroupStatusEnum.CANCEL);
			List<StudentPaymentOrder> studentPaymentOrders = studentPaymentOrderDao.queryByDealStatus(noCreateSuccessVipGroup.getId().toString(),
					OrderTypeEnum.SMALL_CLASS_TO_BUY, DealStatusEnum.SUCCESS);

			for (StudentPaymentOrder studentPaymentOrder:studentPaymentOrders){
				//生成账户资金明细
				if(studentPaymentOrder.getExpectAmount().compareTo(BigDecimal.ZERO)>0){
					sysUserCashAccountService.updateBalance(studentPaymentOrder.getUserId(),studentPaymentOrder.getExpectAmount());
					SysUserCashAccount sysUserCashAccount = sysUserCashAccountService.get(studentPaymentOrder.getUserId());
					SysUserCashAccountDetail sysUserIncomeCashAccountDetail = new SysUserCashAccountDetail();
					sysUserIncomeCashAccountDetail.setUserId(studentPaymentOrder.getUserId());
					sysUserIncomeCashAccountDetail.setType(PlatformCashAccountDetailTypeEnum.REFUNDS);
					sysUserIncomeCashAccountDetail.setStatus(DealStatusEnum.SUCCESS);
					sysUserIncomeCashAccountDetail.setAmount(studentPaymentOrder.getExpectAmount());
					sysUserIncomeCashAccountDetail.setBalance(sysUserCashAccount.getBalance());
					sysUserIncomeCashAccountDetail.setAttribute(studentPaymentOrder.getTransNo());
					sysUserIncomeCashAccountDetail.setDescription("达到报名截止时间，未满员系统自动取消课程组，并退费");
					sysUserIncomeCashAccountDetail.setComment("达到报名截止时间，未满员系统自动取消课程组，并退费");
					userCashAccountDetails.add(sysUserIncomeCashAccountDetail);
				}
			}
			classGroupStudentMapperDao.updateVipGroupStudentStatus(noCreateSuccessVipGroup.getId().toString(),GroupType.VIP.getCode(),ClassGroupStudentStatusEnum.QUIT.getCode());
		}
		if(!CollectionUtils.isEmpty(userCashAccountDetails)){
			sysUserCashAccountDetailDao.batchInsert(userCashAccountDetails);
		}
		if(noCreateSuccessVipGroups != null && noCreateSuccessVipGroups.size() > 0){
			vipGroupDao.batchUpdate(noCreateSuccessVipGroups);

			for (VipGroup noCreateSuccessVipGroup : noCreateSuccessVipGroups) {
				//推送消息
				if(noCreateSuccessVipGroup.getStatus().equals(VipGroupStatusEnum.CANCEL)) {
					stopVipPush(noCreateSuccessVipGroup.getId(), noCreateSuccessVipGroup.getName());
				}
			}
		}
	}

	@Override
	@Transactional(rollbackFor = Exception.class, isolation = Isolation.READ_COMMITTED)
	public void updateVipGroupStatusToFinished() {
		List<VipGroup> vipGroupList = vipGroupDao.queryRequiredOverList();
		if (vipGroupList != null && vipGroupList.size() > 0) {
			Date date = new Date();
			for (VipGroup vipGroup : vipGroupList) {
				vipGroup.setStatus(VipGroupStatusEnum.FINISHED);
				vipGroup.setUpdateTime(date);
			}
			vipGroupDao.batchUpdate(vipGroupList);
			Set<Long> collect = vipGroupList.stream().map(e -> e.getId()).collect(Collectors.toSet());
			Set<Integer> classGroupIds = classGroupDao.queryClassGroupIds(collect);
			//解散群
			for (Integer classGroupId : classGroupIds) {
				imGroupService.cancel(classGroupId.longValue());
			}
		}
		List<VipGroup> normalVipGroupList = vipGroupDao.queryNormalStatusList();
		if (!CollectionUtils.isEmpty(normalVipGroupList)){
            Date now = new Date();
            List<VipGroup> needUpdateVipGroups = new ArrayList<>();
			for (VipGroup vipGroup : normalVipGroupList) {
				try {
					if (Objects.isNull(vipGroup.getRegistrationStartTime())) {
						continue;
					}
					if (vipGroup.getStatus().equals(VipGroupStatusEnum.PAUSE) || vipGroup.getStatus().equals(VipGroupStatusEnum.CANCEL)
							|| vipGroup.getStatus().equals(VipGroupStatusEnum.FINISHED) || vipGroup.getStatus().equals(VipGroupStatusEnum.PROGRESS)) {
						continue;
					}
					if (now.before(vipGroup.getRegistrationStartTime())) {
						vipGroup.setStatus(VipGroupStatusEnum.NOT_START);
					} else if (vipGroup.getRegistrationStartTime().before(now)
							&& vipGroup.getPaymentExpireDate().after(now)
							&& VipGroupStatusEnum.NOT_START.equals(vipGroup.getStatus())) {
						vipGroup.setStatus(VipGroupStatusEnum.APPLYING);
					}else{
						continue;
					}
					VipGroup vipGroup1 = new VipGroup();
					vipGroup1.setId(vipGroup.getId());
					vipGroup1.setStatus(vipGroup.getStatus());
					vipGroup1.setUpdateTime(now);
					vipGroup1.setTotalPrice(vipGroup.getTotalPrice());
					needUpdateVipGroups.add(vipGroup1);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
			if(!CollectionUtils.isEmpty(needUpdateVipGroups)){
				vipGroupDao.batchUpdate(needUpdateVipGroups);
			}
        }
	}

	@Override
	public VipGroupPayInfoDto getVipGroupPayInfo(Integer vipGroupId, Integer userId) {
		if(Objects.isNull(vipGroupId)){
			throw new BizException("请指定需要购买的小课");
		}
		VipGroup vipGroup=vipGroupDao.get(vipGroupId.longValue());
		if(Objects.isNull(vipGroup)){
			throw new BizException("未找到此课程");
		}
		VipGroupPayInfoDto vipGroupPayInfo=new VipGroupPayInfoDto();
		vipGroupPayInfo.setVipGroupId(vipGroup.getId().intValue());
		vipGroupPayInfo.setViipGroupName(vipGroup.getName());
		vipGroupPayInfo.setPrice(vipGroup.getTotalPrice());
		SysUserCashAccount sysUserCashAccount = sysUserCashAccountService.get(userId);
		if(Objects.isNull(sysUserCashAccount)){
			throw new BizException("当前用户没有现金账户");
		}
		vipGroupPayInfo.setBalance(sysUserCashAccount.getBalance());
		return  vipGroupPayInfo;
	}

	@Override
	public VipBuyResultDto findVipBuyResultInfo(Integer vipGroupId) {
		return vipGroupDao.getVipBuyResultInfo(vipGroupId);
	}

	@Override
	public List<TeacherBasicDto> findTeacherWithVipGroupOrganAndSubject(Long vipGroupId) {
		if(Objects.isNull(vipGroupId)){
			throw new BizException("请指定小课");
		}
		VipGroup vipGroup=vipGroupDao.get(vipGroupId.longValue());
		if(Objects.isNull(vipGroup)) {
			throw new BizException("未找到指定课程");
		}
		ClassGroup classGroup = classGroupDao.findByVipGroup(vipGroupId.longValue(), null);
		List<TeacherBasicDto> teacherByOrganAndSubject = teacherDao.findTeacherByOrganAndSubject(vipGroup.getOrganId().toString(), classGroup.getSubjectIdList());
        if(CollectionUtils.isEmpty(teacherByOrganAndSubject)){
            teacherByOrganAndSubject=new ArrayList<>();
            teacherByOrganAndSubject.add(teacherDao.findByTeacherId(vipGroup.getUserId()));
        }
		return teacherByOrganAndSubject;
	}
}
