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

import static com.ym.mec.biz.dal.enums.DealStatusEnum.CLOSE;
import static com.ym.mec.biz.dal.enums.DealStatusEnum.SUCCESS;
import static com.ym.mec.biz.dal.enums.PaymentStatusEnum.YES;

import java.io.IOException;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

import com.ym.mec.biz.dal.dao.*;
import com.ym.mec.biz.service.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
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.biz.dal.dto.BasicUserDto;
import com.ym.mec.biz.dal.dto.CloseMusicGroupDto;
import com.ym.mec.biz.dal.dto.CourseFormDto;
import com.ym.mec.biz.dal.dto.CourseScheduleTeachersDto;
import com.ym.mec.biz.dal.dto.HighClassGroupDto;
import com.ym.mec.biz.dal.dto.MusicCardDto;
import com.ym.mec.biz.dal.dto.RegisterPayDto;
import com.ym.mec.biz.dal.dto.SporadicPayDto;
import com.ym.mec.biz.dal.dto.SubFeeSettingDto;
import com.ym.mec.biz.dal.dto.SubjectRegisterDto;
import com.ym.mec.biz.dal.dto.UpdateExpectedNumDto;
import com.ym.mec.biz.dal.entity.ApprovalStatus;
import com.ym.mec.biz.dal.entity.ChargeType;
import com.ym.mec.biz.dal.entity.ClassGroup;
import com.ym.mec.biz.dal.entity.CooperationOrgan;
import com.ym.mec.biz.dal.entity.CourseSchedule;
import com.ym.mec.biz.dal.entity.CourseScheduleTeacherSalary;
import com.ym.mec.biz.dal.entity.Goods;
import com.ym.mec.biz.dal.entity.MusicGroup;
import com.ym.mec.biz.dal.entity.MusicGroupBuildLog;
import com.ym.mec.biz.dal.entity.MusicGroupPaymentCalender;
import com.ym.mec.biz.dal.entity.MusicGroupPaymentCalender.PaymentType;
import com.ym.mec.biz.dal.entity.MusicGroupPaymentCalenderCourseSettings;
import com.ym.mec.biz.dal.entity.MusicGroupPaymentCalenderDetail;
import com.ym.mec.biz.dal.entity.MusicGroupPaymentCalenderStudentDetail;
import com.ym.mec.biz.dal.entity.MusicGroupPurchaseList;
import com.ym.mec.biz.dal.entity.MusicGroupQuit;
import com.ym.mec.biz.dal.entity.MusicGroupStudentFee;
import com.ym.mec.biz.dal.entity.MusicGroupStudentFee.PaymentStatus;
import com.ym.mec.biz.dal.entity.MusicGroupSubjectGoodsGroup;
import com.ym.mec.biz.dal.entity.MusicGroupSubjectPlan;
import com.ym.mec.biz.dal.entity.Organization;
import com.ym.mec.biz.dal.entity.School;
import com.ym.mec.biz.dal.entity.SporadicChargeInfo;
import com.ym.mec.biz.dal.entity.Student;
import com.ym.mec.biz.dal.entity.StudentPaymentOrder;
import com.ym.mec.biz.dal.entity.StudentPaymentOrderDetail;
import com.ym.mec.biz.dal.entity.StudentPreRegistration;
import com.ym.mec.biz.dal.entity.StudentRegistration;
import com.ym.mec.biz.dal.entity.Subject;
import com.ym.mec.biz.dal.entity.SubjectChange;
import com.ym.mec.biz.dal.entity.SysUserCashAccount;
import com.ym.mec.biz.dal.entity.SysUserCashAccountDetail;
import com.ym.mec.biz.dal.enums.ClassGroupTypeEnum;
import com.ym.mec.biz.dal.enums.CourseStatusEnum;
import com.ym.mec.biz.dal.enums.DealStatusEnum;
import com.ym.mec.biz.dal.enums.GoodsType;
import com.ym.mec.biz.dal.enums.GroupType;
import com.ym.mec.biz.dal.enums.KitGroupPurchaseTypeEnum;
import com.ym.mec.biz.dal.enums.MessageTypeEnum;
import com.ym.mec.biz.dal.enums.MusicGroupStatusEnum;
import com.ym.mec.biz.dal.enums.OrderDetailTypeEnum;
import com.ym.mec.biz.dal.enums.OrderTypeEnum;
import com.ym.mec.biz.dal.enums.PaymentStatusEnum;
import com.ym.mec.biz.dal.enums.PlatformCashAccountDetailTypeEnum;
import com.ym.mec.biz.dal.enums.SporadicChargeTypeEnum;
import com.ym.mec.biz.dal.enums.StudentMusicGroupStatusEnum;
import com.ym.mec.biz.dal.enums.YesOrNoEnum;
import com.ym.mec.biz.dal.page.MusicGroupQueryInfo;
import com.ym.mec.common.dal.BaseDAO;
import com.ym.mec.common.entity.HttpResponseResult;
import com.ym.mec.common.entity.ImGroupMember;
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.thirdparty.message.MessageSenderPluginContext.MessageSender;
import com.ym.mec.util.collection.MapUtil;
import com.ym.mec.util.date.DateUtil;
import com.ym.mec.util.http.HttpUtil;

@Service
public class MusicGroupServiceImpl extends BaseServiceImpl<String, MusicGroup> implements MusicGroupService {

    @Autowired
    private MusicGroupDao musicGroupDao;
    @Autowired
    private ChargeTypeDao chargeTypeDao;
    @Autowired
    private TeacherDao teacherDao;
    @Autowired
    private StudentDao studentDao;
    @Autowired
    private IdGeneratorService idGeneratorService;
    @Autowired
    private SchoolDao schoolDao;
    @Autowired
    private MusicGroupPaymentCalenderDao musicGroupPaymentCalenderDao;
    @Autowired
    private MusicGroupPaymentCalenderService musicGroupPaymentCalenderService;
    @Autowired
    private MusicGroupPaymentEntitiesDao musicGroupPaymentEntitiesDao;
    @Autowired
    private MusicGroupSubjectGoodsGroupDao musicGroupSubjectGoodsGroupDao;
    @Autowired
    private MusicGroupSubjectPlanDao musicGroupSubjectPlanDao;
    @Autowired
    private MusicGroupBuildLogDao musicGroupBuildLogDao;
    @Autowired
    private MusicGroupPurchaseListDao musicGroupPurchaseListDao;
    @Autowired
    private MusicGroupStudentFeeDao musicGroupStudentFeeDao;

    @Autowired
    private ClassGroupStudentMapperDao classGroupStudentMapperDao;

    @Autowired
    private ClassGroupTeacherMapperDao classGroupTeacherMapperDao;

    @Autowired
    private StudentPaymentOrderDao studentPaymentOrderDao;

    @Autowired
    private SysUserCashAccountService sysUserCashAccountService;

    @Autowired
    private SysUserCashAccountDetailService sysUserCashAccountDetailService;

    @Autowired
    private MusicGroupPaymentCalenderStudentDetailDao musicGroupPaymentCalenderStudentDetailDao;

    @Autowired
    private MusicGroupQuitDao musicGroupQuitDao;

    @Autowired
    private StudentRegistrationDao studentRegistrationDao;

    @Autowired
    private CourseScheduleDao courseScheduleDao;

    @Autowired
    private ClassGroupDao classGroupDao;

    @Autowired
    private OrganizationDao organizationDao;

    @Autowired
    private CourseScheduleTeacherSalaryDao courseScheduleTeacherSalaryDao;

    @Autowired
    private CourseScheduleStudentPaymentDao courseScheduleStudentPaymentDao;

    @Autowired
    private CourseScheduleStudentPaymentService courseScheduleStudentPaymentService;

    @Autowired
    private CooperationOrganDao cooperationOrganDao;

    @Autowired
    private TeacherAttendanceDao teacherAttendanceDao;

    @Autowired
    private StudentPaymentOrderService studentPaymentOrderService;

    @Autowired
    private StudentPaymentOrderDetailService studentPaymentOrderDetailService;

    @Autowired
    private PayService payService;

    @Autowired
    private SysUserFeignService sysUserFeignService;

    @Autowired
    private EmployeeDao employeeDao;

    @Autowired
    private SysMessageService sysMessageService;

    @Autowired
    private SysConfigDao sysConfigDao;

    @Autowired
    private ClassGroupService classGroupService;

    @Autowired
    private StudentPaymentOrderDetailDao studentPaymentOrderDetailDao;
    @Autowired
    private MusicGroupSubjectPlanService musicGroupSubjectPlanService;
    @Autowired
    private StudentRegistrationService studentRegistrationService;
    @Autowired
    private SporadicChargeInfoDao sporadicChargeInfoDao;
    @Autowired
    private MusicGroupSubjectGoodsGroupService musicGroupSubjectGoodsGroupService;
    @Autowired
    private GoodsService goodsService;
    @Autowired
    private ClassGroupStudentMapperService classGroupStudentMapperService;
    @Autowired
    private MusicGroupPaymentCalenderDetailDao musicGroupPaymentCalenderDetailDao;
    @Autowired
    private ImGroupMemberService imGroupMemberService;
    @Autowired
    private ImUserFriendService imUserFriendService;
    @Autowired
    private ImGroupService imGroupService;
    @Autowired
    private StudentPaymentRouteOrderService studentPaymentRouteOrderService;
    @Autowired
    private MusicGroupPaymentCalenderCourseSettingsDao musicGroupPaymentCalenderCourseSettingsDao;
    @Autowired
    private MusicGroupPaymentStudentCourseDetailDao musicGroupPaymentStudentCourseDetailDao;
    @Autowired
    private SubjectChangeDao subjectChangeDao;
    @Autowired
    private StudentVisitDao studentVisitDao;
    @Autowired
    private SubjectDao subjectDao;
    @Autowired
    private SysUserCashAccountDao sysUserCashAccountDao;
    
    @Autowired
    private StudentPreRegistrationDao studentPreRegistrationDao;

    private SimpleDateFormat sdf_ymd = new SimpleDateFormat("yyyy-MM-dd");

    private SimpleDateFormat sdf_hms = new SimpleDateFormat("HH:mm:ss");

    private SimpleDateFormat sdf_ymdhms = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Override
    public BaseDAO<String, MusicGroup> getDAO() {
        return musicGroupDao;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String createGroup(SubFeeSettingDto subFeeSettingDto) {
        SysUser sysUser = sysUserFeignService.queryUserInfo();
        if (sysUser == null || sysUser.getId() == null) {
            throw new BizException("获取用户信息失败");
        }
        MusicGroup musicGroup = subFeeSettingDto.getMusicGroup();
        List<MusicGroupSubjectGoodsGroup> musicGroupSubjectGoodsGroups = subFeeSettingDto.getMusicGroupSubjectGoodsGroups();
        List<MusicGroupSubjectPlan> musicGroupSubjectPlans = subFeeSettingDto.getMusicGroupSubjectPlans();
        List<SubjectRegisterDto> subjectRegisters = subFeeSettingDto.getSubjectRegisters();
        String musicGroupId = idGeneratorService.generatorId() + "";
        musicGroup.setId(musicGroupId);
        if (musicGroup.getStatus() != MusicGroupStatusEnum.DRAFT && musicGroup.getStatus() != MusicGroupStatusEnum.AUDIT) {
            throw new BizException("乐团初始状态错误");
        }
        musicGroup.setDelFlag(false);
        // 保存乐团基本信息
        musicGroupDao.insert(musicGroup);

        // 记录创建日志
        String event = musicGroup.getStatus() == MusicGroupStatusEnum.AUDIT ? "新建乐团，提交审核" : "保存乐团草稿";
        musicGroupBuildLogDao.insert(new MusicGroupBuildLog(musicGroupId, event, sysUser.getId(), ""));
        if (musicGroup.getStatus() == MusicGroupStatusEnum.AUDIT) {
            Set<Integer> roleIds = new HashSet<>(1);
            roleIds.add(SysUserRole.SECTION_MANAGER);
            sysMessageService.batchSeoMessage(musicGroupDao.queryUserIdByRoleId(roleIds, musicGroup.getOrganId()), MessageTypeEnum.BACKSTAGE_CREATE_MUSIC_GROUP_APPLY, "", sysUser.getUsername());
        }
        // 保存乐团付费主体列表
        //批量新增
        if (subFeeSettingDto.getMusicGroupPaymentEntities() != null && subFeeSettingDto.getMusicGroupPaymentEntities().size() > 0) {
            musicGroupPaymentEntitiesDao.batchAdd(subFeeSettingDto.getMusicGroupPaymentEntities(), musicGroupId);
        }
        // 保存学员付费周期
        /*List<Integer> months = subFeeSettingDto.getMonths();
        if (months != null && months.size() > 0) {
            musicGroupPaymentCalenderDao.batchAdd(months, musicGroupId);
        }*/

        //乐团科目学生
        if (subjectRegisters != null && subjectRegisters.size() > 0) {
            List<StudentRegistration> studentRegistrationList = new ArrayList<>();
            subjectRegisters.forEach(e -> {
                if (e.getRegisterIdList().size() == 0) {
                    return;
                }
                //原来乐团的注册学生
                List<StudentRegistration> musicGroupStudentRegistrationList = studentRegistrationDao.findStudentListByIdList(e.getRegisterIdList());

                for (MusicGroupSubjectPlan musicGroupSubjectPlan : musicGroupSubjectPlans) {
                    if (!musicGroupSubjectPlan.getSubjectId().equals(e.getSubjectId())) continue;
                    musicGroupSubjectPlan.setExpectedStudentNum(e.getRegisterIdList().size());
                    musicGroupSubjectPlan.setApplyStudentNum(e.getRegisterIdList().size());
                    if (musicGroupSubjectPlan.getFee().compareTo(BigDecimal.ZERO) == 0) {
                        musicGroupSubjectPlan.setPaidStudentNum(e.getRegisterIdList().size());
                    }

                    for (StudentRegistration studentRegistration : musicGroupStudentRegistrationList) {
                        studentRegistration.setId(null);
                        if (musicGroupSubjectPlan.getFee().compareTo(BigDecimal.ZERO) == 0) {
                            studentRegistration.setMusicGroupStatus(StudentMusicGroupStatusEnum.NORMAL);
                            studentRegistration.setPaymentStatus(YES);
                        } else {
                            studentRegistration.setMusicGroupStatus(StudentMusicGroupStatusEnum.APPLY);
                            studentRegistration.setPaymentStatus(PaymentStatusEnum.OPEN);
                        }
                        studentRegistration.setMusicGroupId(musicGroupId);
                        studentRegistration.setSubjectId(e.getSubjectId());
                        studentRegistration.setActualSubjectId(e.getSubjectId());
                        studentRegistration.setTemporaryCourseFee(null);
                    }
                }

                studentRegistrationList.addAll(musicGroupStudentRegistrationList);
            });
            musicGroup.setStatus(MusicGroupStatusEnum.PAY);
            //是否是免费团
            if (musicGroupSubjectPlans != null && musicGroupSubjectPlans.size() > 0) {
                int size = (int) musicGroupSubjectPlans.stream().filter(e -> e.getFee().compareTo(BigDecimal.ZERO) > 0).count();
                if (size < 1) {
                    musicGroup.setStatus(MusicGroupStatusEnum.PREPARE);
                }
            }
            if (studentRegistrationList.size() > 0) {
                studentRegistrationDao.batchInsert(studentRegistrationList);
            }
            musicGroupDao.update(musicGroup);
//            List<MusicGroupStudentFee> musicGroupStudentFees = musicGroupStudentFeeDao.initMusicGroupStudentFee(musicGroupId);
//            if(musicGroupStudentFees != null && musicGroupStudentFees.size() > 0){
//                Date nextPaymentDate = musicGroupPaymentCalenderService.getNextPaymentDate(musicGroupId, null,null);
//                musicGroupStudentFeeDao.batchInsert(musicGroupStudentFees,nextPaymentDate,"PAID_COMPLETED");
//            }
            musicGroupBuildLogDao.insert(new MusicGroupBuildLog(musicGroupId, "跨团调整", sysUser.getId(), ""));
        }

        // 保存乐团声部规划
        if (musicGroupSubjectPlans != null && musicGroupSubjectPlans.size() > 0) {
            musicGroupSubjectPlanDao.batchAdd(musicGroupSubjectPlans, musicGroupId);
        }
        // 保存乐团声部商品规划
        if (musicGroupSubjectGoodsGroups != null && musicGroupSubjectGoodsGroups.size() > 0) {
            for (MusicGroupSubjectGoodsGroup musicGroupSubjectGoodsGroup : musicGroupSubjectGoodsGroups) {
                if (musicGroupSubjectGoodsGroup.getType().equals(GoodsType.INSTRUMENT) && (musicGroupSubjectGoodsGroup.getKitGroupPurchaseTypeJson() == null
                        || musicGroupSubjectGoodsGroup.getKitGroupPurchaseTypeJson().isEmpty()
                        || musicGroupSubjectGoodsGroup.getKitGroupPurchaseTypeJson().equals("{}"))) {
                    throw new BizException(musicGroupSubjectGoodsGroup.getName() + " 请选择提供方式");
                }
                if (musicGroupSubjectGoodsGroup.getGroupRemissionCourseFee() == null) {
                    musicGroupSubjectGoodsGroup.setGroupRemissionCourseFee(0);
                }
            }
            musicGroupSubjectGoodsGroupDao.batchInsert(musicGroupSubjectGoodsGroups, musicGroupId);
        }
        return musicGroupId;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
	public boolean preRegister(StudentPreRegistration studentPreRegistration) {

		String musicGroupId = studentPreRegistration.getMusicGroupId();

		// 查询乐团状态
		MusicGroup musicGroup = musicGroupDao.getLocked(musicGroupId);
		if (musicGroup == null) {
			throw new BizException("乐团信息查询失败");
		}
		if (musicGroup.getStatus() != MusicGroupStatusEnum.PRE_APPLY) {
			throw new BizException("乐团当前状态不能预报名");
		}

		StudentPreRegistration originRegistration = studentPreRegistrationDao.queryByMusicGroupIdAndPhone(studentPreRegistration.getPhone(), musicGroupId);
		if (originRegistration != null) {
			throw new BizException("您已预报名成功，请勿重复提交资料");
		}
		Date date = new Date();

		// 判断用户是否存在
		SysUser user = sysUserFeignService.queryUserByMobile(studentPreRegistration.getPhone());
		if (user == null || user.getId() == null) {
			user = new SysUser();
			user.setPhone(studentPreRegistration.getPhone());
			user.setUsername(studentPreRegistration.getUserName());
			user.setOrganId(musicGroup.getOrganId());
			user.setUserType("STUDENT");
			user.setCreateTime(date);
			user.setUpdateTime(date);
			// 注册账户信息
			HttpResponseResult<Integer> result = sysUserFeignService.addUser(user);

			Integer userId = result.getData();
			user.setId(userId);

			Student student = new Student();
			student.setUserId(userId);
			student.setCreateTime(date);
			student.setUpdateTime(date);
			student.setIsNewUser(true);
			studentDao.insert(student);
			sysUserCashAccountDao.insert(new SysUserCashAccount(userId, "CNY"));
		}

		studentPreRegistration.setCreateTime(date);
		studentPreRegistration.setUserId(user.getId());

		studentPreRegistrationDao.insert(studentPreRegistration);
		
		// 添加成员
		imGroupMemberService.join(Long.parseLong(musicGroupId), user.getId(), null, false);

		return true;
	}

	@Override
	public boolean finishPreApply(String musicGroupId, boolean isCheckStudentNum) {
		MusicGroup musicGroup = musicGroupDao.get(musicGroupId);
		if (musicGroup == null) {
			throw new BizException("乐团信息查询失败");
		}
		if (musicGroup.getStatus() != MusicGroupStatusEnum.PRE_APPLY) {
			throw new BizException("操作失败：只有乐团在[{}]状态才能操作", MusicGroupStatusEnum.PRE_APPLY.getMsg());
		}
		if (isCheckStudentNum) {
			// 查询乐团已报名人数
			List<StudentPreRegistration> studentPreRegistrationList = studentPreRegistrationDao.queryByMusicGroupId(musicGroupId);
			if (studentPreRegistrationList == null || studentPreRegistrationList.size() < 120) {
				throw new BizException("操作失败：报名人数没有达到120人");
			}
		}
		musicGroup.setStatus(MusicGroupStatusEnum.PRE_BUILD_FEE);
		musicGroup.setUpdateTime(new Date());
		musicGroupDao.update(musicGroup);
		
		SysUser sysUser = sysUserFeignService.queryUserInfo();
		if(sysUser == null || sysUser.getId() == null){
			throw new BizException("请重新登录");
		}
		
		//记录操作日志
		musicGroupBuildLogDao.insert(new MusicGroupBuildLog(musicGroup.getId(), "报名缴费项目失败（预报名 -> 准备创建缴费）", sysUser.getId(), ""));
		
		return true;
	}

	@Override
	public boolean sendParentMeetingNotice(Integer userId, String musicGroupId, Date meetingDate, String address) {
		MusicGroup musicGroup = musicGroupDao.get(musicGroupId);
		if (musicGroup == null) {
			throw new BizException("乐团信息查询失败");
		}
		if (musicGroup.getStatus() != MusicGroupStatusEnum.PRE_APPLY) {
			throw new BizException("操作失败：只有乐团在[{}]状态才能操作", MusicGroupStatusEnum.PRE_APPLY.getMsg());
		}
		
		List<StudentPreRegistration> studentPreRegistrationList = studentPreRegistrationDao.queryByMusicGroupId(musicGroupId);
		Map<Integer,String> receiverList = studentPreRegistrationList.stream().collect(Collectors.toMap(StudentPreRegistration :: getUserId, StudentPreRegistration :: getPhone));
		
		String meetingDateStr = sdf_ymdhms.format(meetingDate);
		sysMessageService.batchSendImGroupMessage(MessageTypeEnum.SMS_MUSIC_GROUP_PARENT_MEETING_NOTICE, userId + "", null, new String[]{musicGroupId}, null, meetingDateStr, address);
		sysMessageService.batchSendMessage(MessageSender.AWSMS, MessageTypeEnum.SMS_MUSIC_GROUP_PARENT_MEETING_NOTICE, receiverList, null, 1, null, null, meetingDateStr, address);
		return true;
	}

	@Override
    @Transactional(rollbackFor = Exception.class)
    public Map sporadicPay(SporadicPayDto sporadicPayDto) throws Exception {
        //获取收费项价格
        SporadicChargeInfo chargeInfo = sporadicChargeInfoDao.get(sporadicPayDto.getSporadicId());
        if (chargeInfo == null) {
            throw new BizException("支付项不存在");
        }
        if (chargeInfo.getOpenFlag().equals(1)) {
            throw new BizException("项目已关闭");
        }
        if (sporadicPayDto.getNum() == null) {
            sporadicPayDto.setNum(1);
        }
        BigDecimal amount = chargeInfo.getAmount().multiply(new BigDecimal(sporadicPayDto.getNum()));
        if (chargeInfo.getDiscountAmount() != null && chargeInfo.getDiscountAmount().compareTo(BigDecimal.ZERO) > 0) {
            amount = amount.subtract(chargeInfo.getDiscountAmount().multiply(new BigDecimal(sporadicPayDto.getNum())));
        }
        if (!(amount.compareTo(sporadicPayDto.getAmount()) == 0)) {
            throw new BizException("订单金额异常");
        }
        if (chargeInfo.getMaxAmount() != null) {
            if (chargeInfo.getOpenMaxTerm().equals(YesOrNoEnum.YES) && chargeInfo.getMaxAmount().compareTo(chargeInfo.getPaidAmount()) <= 0) {
                throw new Exception("活动名额已满，谢谢您的支持！");
            }
            if (chargeInfo.getOpenMaxTerm().equals(YesOrNoEnum.YES) && chargeInfo.getMaxAmount().compareTo(chargeInfo.getPaidAmount().add(amount)) < 0) {
                throw new Exception("活动名额已满，谢谢您的支持！");
            }
        }

        Date date = new Date();

        OrderTypeEnum type = OrderTypeEnum.SPORADIC;
        if (chargeInfo.getChargeType().equals(SporadicChargeTypeEnum.DOUBLE_ELEVEN2020)) {
            type = OrderTypeEnum.DOUBLE_ELEVEN2020;

            String startTimeStr = sysConfigDao.findConfigValue(SysConfigService.START_TIME_OF_1111);
            String endTimeStr = sysConfigDao.findConfigValue(SysConfigService.END_TIME_OF_1111);
            Date startTime = sdf_ymdhms.parse(startTimeStr);
            Date endTime = sdf_ymdhms.parse(endTimeStr);
            if (date.before(startTime)) {
                throw new Exception("活动暂未开始，请您耐心等待！");
            }
            if (date.after(endTime)) {
                throw new Exception("活动已结束，谢谢您的支持！");
            }
        }

        Integer userId = sporadicPayDto.getUserId();
        String orderNo = idGeneratorService.generatorId("payment") + "";
        String channelType = "";
        StudentPaymentOrder studentPaymentOrder = new StudentPaymentOrder();
        studentPaymentOrder.setUserId(userId);
        studentPaymentOrder.setGroupType(GroupType.SPORADIC);
        studentPaymentOrder.setOrderNo(orderNo);
        studentPaymentOrder.setType(type);
        studentPaymentOrder.setExpectAmount(amount);
        studentPaymentOrder.setActualAmount(amount);
        studentPaymentOrder.setStatus(DealStatusEnum.ING);
        studentPaymentOrder.setMusicGroupId(sporadicPayDto.getSporadicId().toString());
        studentPaymentOrder.setClassGroupId(sporadicPayDto.getNum());
        studentPaymentOrderService.insert(studentPaymentOrder);

        studentPaymentOrder.setVersion(0);
        BigDecimal balance = BigDecimal.ZERO;
        if (sporadicPayDto.getUseBalancePayment() && amount.compareTo(BigDecimal.ZERO) > 0) {
            if (chargeInfo.getChargeType().getCode().equals(9) || chargeInfo.getChargeType().getCode().equals(13)) {
                throw new BizException(chargeInfo.getChargeType().getMsg() + "不支持余额支付");
            }
            SysUserCashAccount userCashAccount = sysUserCashAccountService.get(userId);

            if (userCashAccount == null) {
                throw new BizException("用户账户找不到");
            }
            if (userCashAccount.getBalance() != null && userCashAccount.getBalance().compareTo(BigDecimal.ZERO) > 0) {
                balance = amount.compareTo(userCashAccount.getBalance()) >= 0 ? userCashAccount.getBalance() : amount;
                amount = amount.subtract(balance);
                studentPaymentOrder.setPaymentChannel("BALANCE");
                studentPaymentOrder.setActualAmount(amount);
                studentPaymentOrder.setBalancePaymentAmount(balance);
                sysUserCashAccountService.updateBalance(userId, balance.negate(), PlatformCashAccountDetailTypeEnum.SPORADIC, chargeInfo.getTitle());
            }
        }

        studentPaymentOrder.setPaymentChannel("BALANCE");
        studentPaymentOrder.setOrganId(chargeInfo.getOrganId());
        studentPaymentOrder.setRoutingOrganId(chargeInfo.getOrganId());
        studentPaymentOrder.setUpdateTime(date);
        studentPaymentOrderService.update(studentPaymentOrder);
        studentPaymentOrder.setVersion(studentPaymentOrder.getVersion() + 1);

        if (amount.compareTo(BigDecimal.ZERO) == 0) {
            studentPaymentRouteOrderService.addRouteOrder(orderNo, chargeInfo.getOrganId(), balance);
            Map<String, String> notifyMap = new HashMap<>();
            notifyMap.put("tradeState", "1");
            notifyMap.put("merOrderNo", studentPaymentOrder.getOrderNo());
            notifyMap.put("channelType", channelType);
            notifyMap.put("orderNo", "");
            studentPaymentOrderService.updateOrder(notifyMap);
            return notifyMap;
        }

        String baseApiUrl = sysConfigDao.findConfigValue("base_api_url");

        Map<String, BigDecimal> classFee = new HashMap<>();
        classFee.put("course", BigDecimal.ZERO);
        classFee.put("instrument", BigDecimal.ZERO);
        classFee.put("accessories", BigDecimal.ZERO);
        classFee.put("other", amount);

        String receiver = "sporadic";

        Map payMap = payService.getPayMap(
                amount,
                balance,
                orderNo,
                baseApiUrl + "/api-student/studentOrder/notify",
                baseApiUrl + "/api-student/studentOrder/paymentResult?orderNo=" + orderNo,
                chargeInfo.getTitle(),
                chargeInfo.getTitle(),
                chargeInfo.getOrganId(),
                receiver
        );

        //Map<String, BigDecimal> routingFee = (Map<String, BigDecimal>) payMap.get("routingFee");
        studentPaymentOrder.setOrganId(chargeInfo.getOrganId());
        //studentPaymentOrder.setRoutingOrganId(chargeInfo.getOrganId());
        //studentPaymentOrder.setRoutingOrganId((Integer) payMap.get("routingOrganId"));
        //studentPaymentOrder.setComAmount(routingFee.get("COM"));
        //studentPaymentOrder.setPerAmount(routingFee.get("PER"));
        studentPaymentOrder.setMerNos((String) payMap.get("routingMerNos"));
        studentPaymentOrder.setPaymentChannel((String) payMap.get("type"));
        studentPaymentOrder.setUpdateTime(date);
        studentPaymentOrderService.update(studentPaymentOrder);
        return payMap;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map pay(RegisterPayDto registerPayDto) throws Exception {

        StudentRegistration studentRegistration = studentRegistrationService.get(registerPayDto.getRegisterId().longValue());
        if (studentRegistration == null) {
            throw new BizException("报名信息有误，请核查");
        }

        Integer userId = studentRegistration.getUserId();

        BigDecimal amount = registerPayDto.getAmount(); //前端获取的价格
        BigDecimal orderAmount = new BigDecimal("0");

        //获取课程价格
        MusicGroupSubjectPlan musicOneSubjectClassPlan = musicGroupSubjectPlanService.getMusicOneSubjectClassPlan(studentRegistration.getMusicGroupId(), studentRegistration.getActualSubjectId());
        BigDecimal courseFee = musicOneSubjectClassPlan.getFee() == null ? BigDecimal.ZERO : musicOneSubjectClassPlan.getFee();
        if (studentRegistration.getTemporaryCourseFee() != null) {
            courseFee = studentRegistration.getTemporaryCourseFee();
        }
        orderAmount = orderAmount.add(courseFee);

        BigDecimal remitFee = BigDecimal.ZERO;
        BigDecimal courseRemitFee = BigDecimal.ZERO; //课程减免费用
        boolean remitCourseRFeeFlag = false; //减免课程费用标识

        //乐器及打包辅件
        List<MusicGroupSubjectGoodsGroup> goodsGroups = new ArrayList<>();
        if (studentRegistration.getTemporaryCourseFee() != null) {
            List<StudentPaymentOrderDetail> orderDetails = studentPaymentOrderDetailService.findUserApplyOrder(studentRegistration.getUserId(), studentRegistration.getMusicGroupId(), DealStatusEnum.WAIT_PAY);
            for (StudentPaymentOrderDetail orderDetail : orderDetails) {
                if (orderDetail == null || orderDetail.getPrice() == null || orderDetail.getGoodsIdList() == null) {
                    continue;
                }
                MusicGroupSubjectGoodsGroup musicGroupSubjectGoodsGroup = new MusicGroupSubjectGoodsGroup();
                GoodsType goodsType = orderDetail.getType().equals(OrderDetailTypeEnum.MUSICAL) ? GoodsType.INSTRUMENT : GoodsType.ACCESSORIES;
                musicGroupSubjectGoodsGroup.setType(goodsType);
                musicGroupSubjectGoodsGroup.setGoodsIdList(orderDetail.getGoodsIdList());
                musicGroupSubjectGoodsGroup.setPrice(orderDetail.getPrice());
                musicGroupSubjectGoodsGroup.setKitGroupPurchaseType(orderDetail.getKitGroupPurchaseType());
                goodsGroups.add(musicGroupSubjectGoodsGroup);

                orderAmount = orderAmount.add(orderDetail.getPrice());
            }
        } else if (StringUtils.isNoneBlank(registerPayDto.getGoodsGroupIds())) {
            goodsGroups = musicGroupSubjectGoodsGroupService.findGoodsGroupByIds(registerPayDto.getGoodsGroupIds());
            for (MusicGroupSubjectGoodsGroup goodsGroup : goodsGroups) {
                if (goodsGroup.getType().equals(GoodsType.INSTRUMENT) && musicOneSubjectClassPlan.getKitGroupPurchaseType().equals(KitGroupPurchaseTypeEnum.LEASE)) {
                    goodsGroup.setPrice(musicOneSubjectClassPlan.getDepositFee());
                    goodsGroup.setKitGroupPurchaseType(KitGroupPurchaseTypeEnum.LEASE);
                }
                if (goodsGroup.getType().equals(GoodsType.INSTRUMENT) && musicOneSubjectClassPlan.getKitGroupPurchaseType().equals(KitGroupPurchaseTypeEnum.FREE)) {
                    goodsGroup.setPrice(new BigDecimal(0));
                }
                orderAmount = orderAmount.add(goodsGroup.getPrice());
                //团购乐器减免课程费用
                if (goodsGroup.getType().equals(GoodsType.INSTRUMENT) && goodsGroup.getRemissionCourseFee() != null && musicOneSubjectClassPlan.getKitGroupPurchaseType().equals(KitGroupPurchaseTypeEnum.GROUP)) {//团购
                    orderAmount = orderAmount.subtract(goodsGroup.getRemissionCourseFee());
                    courseFee = courseFee.subtract(goodsGroup.getRemissionCourseFee());
                }
            }
        } else if (registerPayDto.getGoodsGroups() != null && registerPayDto.getGoodsGroups().size() > 0) {
            String goodsGroupIds = registerPayDto.getGoodsGroups().keySet().stream().map(Object::toString).collect(Collectors.joining(","));
            goodsGroups = musicGroupSubjectGoodsGroupService.findGoodsGroupByIds(goodsGroupIds);
            for (MusicGroupSubjectGoodsGroup goodsGroup : goodsGroups) {
                Map<String, BigDecimal> groupType = JSONObject.parseObject(goodsGroup.getKitGroupPurchaseTypeJson(), new TypeReference<Map<String, BigDecimal>>() {
                });

                if (goodsGroup.getType().equals(GoodsType.INSTRUMENT)) {
                    String kitGroupPurchaseType = registerPayDto.getGoodsGroups().get(goodsGroup.getId());
                    if (!groupType.containsKey(kitGroupPurchaseType)) {
                        throw new BizException("乐器提供方式不存在,请核查");
                    }
                    if (!kitGroupPurchaseType.equals("GROUP")) {
                        goodsGroup.setPrice(kitGroupPurchaseType.equals("FREE") ? new BigDecimal(0) : goodsGroup.getDepositFee());
                    } else {
                        remitCourseRFeeFlag = goodsGroup.getGroupRemissionCourseFee().equals(1);
                    }
                    goodsGroup.setKitGroupPurchaseType(KitGroupPurchaseTypeEnum.valueOf(kitGroupPurchaseType));
                    remitFee = groupType.get(kitGroupPurchaseType) == null ? BigDecimal.ZERO : groupType.get(kitGroupPurchaseType);
                }
                orderAmount = orderAmount.add(goodsGroup.getPrice());
                goodsGroup.setGoodsList(goodsService.findGoodsByIds(goodsGroup.getGoodsIdList()));
            }
            orderAmount = orderAmount.subtract(remitFee);
        }

        //单独辅件
        List<Goods> goodsList = null;
        if (registerPayDto.getGoodsIds() != null && !registerPayDto.getGoodsIds().equals("")) {
            goodsList = goodsService.findGoodsByIds(registerPayDto.getGoodsIds());
            for (Goods goods : goodsList) {
                orderAmount = orderAmount.add(goods.getGroupPurchasePrice());
            }
        }

        //单独教谱
        List<Goods> otherGoodsList = null;
        if (registerPayDto.getOtherGoodsIds() != null && !registerPayDto.getOtherGoodsIds().equals("")) {
            otherGoodsList = goodsService.findGoodsByIds(registerPayDto.getOtherGoodsIds());
            for (Goods goods : otherGoodsList) {
                orderAmount = orderAmount.add(goods.getGroupPurchasePrice());
            }
        }
        //可选课程
        List<CourseFormDto> courseForms = new ArrayList<>();
        if (registerPayDto.getCourseKeys() != null && registerPayDto.getCourseKeys().size() > 0) {
            MusicGroup musicGroup = musicGroupDao.get(studentRegistration.getMusicGroupId());
            if (musicGroup.getCourseForm() == null) {
                throw new BizException("可选课程不存在");
            }
            JSONObject courseForm = JSON.parseObject(musicGroup.getCourseForm());
            for (String courseKey : registerPayDto.getCourseKeys()) {
                if (courseForm.get(courseKey) == null) {
                    throw new BizException("可选课程不存在");
                }
                CourseFormDto courseFormDto = new CourseFormDto();
                JSONObject jsonObject = JSON.parseObject(courseForm.getString(courseKey));
                orderAmount = orderAmount.add(jsonObject.getBigDecimal("value"));
                courseFormDto.setType(courseKey);
                courseFormDto.setPrice(jsonObject.getBigDecimal("value"));
                courseForms.add(courseFormDto);
            }
        }

        //新课程形态
        List<MusicGroupPaymentCalenderCourseSettings> newCourses = new ArrayList<>();
        if (registerPayDto.getNewCourse() != null && registerPayDto.getNewCourse().size() > 0) {
            newCourses = musicGroupPaymentCalenderCourseSettingsDao.getCalenderCourseSettings(registerPayDto.getNewCourse());
            for (MusicGroupPaymentCalenderCourseSettings calenderCourseSetting : newCourses) {
                if (remitCourseRFeeFlag && !calenderCourseSetting.getIsStudentOptional()) {
                    courseRemitFee = courseRemitFee.add(calenderCourseSetting.getCourseCurrentPrice());
                    continue;
                }
                orderAmount = orderAmount.add(calenderCourseSetting.getCourseCurrentPrice());
            }
        }

        if (amount.compareTo(orderAmount) != 0) {
            throw new BizException("商品价格不符");
        }

        if (amount.compareTo(BigDecimal.ZERO) < 0) {
            throw new BizException("价格异常");
        }
        String orderNo = idGeneratorService.generatorId("payment") + "";

        String channelType = "";

        StudentPaymentOrder studentPaymentOrder = studentRegistrationService.addOrder(studentRegistration, amount, orderNo, channelType, courseFee, goodsGroups, goodsList, otherGoodsList, courseForms, remitFee, courseRemitFee, newCourses);
        studentPaymentOrder.setVersion(0);

        Date date = new Date();
        BigDecimal balance = BigDecimal.ZERO;
        MusicGroup musicGroup = musicGroupDao.get(studentRegistration.getMusicGroupId());
        if (registerPayDto.getIsUseBalancePayment() && amount.compareTo(BigDecimal.ZERO) > 0) {
            SysUserCashAccount userCashAccount = sysUserCashAccountService.getLocked(userId);
            if (userCashAccount == null) {
                throw new BizException("用户账户找不到");
            }
            if (userCashAccount.getBalance() != null && userCashAccount.getBalance().compareTo(BigDecimal.ZERO) > 0) {
                balance = amount.compareTo(userCashAccount.getBalance()) >= 0 ? userCashAccount.getBalance() : amount;
                amount = amount.subtract(balance);
                studentPaymentOrder.setPaymentChannel("BALANCE");
                studentPaymentOrder.setActualAmount(amount);
                studentPaymentOrder.setBalancePaymentAmount(balance);
                sysUserCashAccountService.updateBalance(userId, balance.negate(), PlatformCashAccountDetailTypeEnum.PAY_FEE, "乐团报名");
            }
        }
        studentPaymentOrder.setPaymentChannel("BALANCE");
        studentPaymentOrder.setRemitFee(remitFee);
        studentPaymentOrder.setCourseRemitFee(courseRemitFee);
        studentPaymentOrder.setOrganId(musicGroup.getOrganId());
        studentPaymentOrder.setRoutingOrganId(musicGroup.getOrganId());
        studentPaymentOrder.setUpdateTime(date);
        studentPaymentOrderService.update(studentPaymentOrder);
        studentPaymentOrder.setVersion(studentPaymentOrder.getVersion() + 1);

        if (amount.compareTo(BigDecimal.ZERO) == 0) {
            studentPaymentRouteOrderService.addRouteOrder(orderNo, musicGroup.getOrganId(), balance);
            Map<String, String> notifyMap = new HashMap<>();
            notifyMap.put("tradeState", "1");
            notifyMap.put("merOrderNo", studentPaymentOrder.getOrderNo());
            notifyMap.put("channelType", channelType);
            notifyMap.put("orderNo", "");
            studentPaymentOrderService.updateOrder(notifyMap);
            return notifyMap;
        }

        String orderSubject = "乐团报名";
        String receiver = "register";
        if (musicGroup.getOwnershipType() != null && musicGroup.getOwnershipType().equals(CooperationOrgan.OwnershipType.COOPERATION)) {
            orderSubject = "乐团相关费用";
        }
        String baseApiUrl = sysConfigDao.findConfigValue("base_api_url");

        Map payMap = payService.getPayMap(
                amount,
                balance,
                orderNo,
                baseApiUrl + "/api-student/studentOrder/notify",
                baseApiUrl + "/api-student/studentOrder/paymentResult?orderNo=" + orderNo,
                orderSubject,
                orderSubject,
                musicGroup.getOrganId(),
                receiver
        );

        studentPaymentOrder.setOrganId(musicGroup.getOrganId());
        studentPaymentOrder.setMerNos((String) payMap.get("routingMerNos"));
        studentPaymentOrder.setPaymentChannel((String) payMap.get("type"));
        studentPaymentOrder.setUpdateTime(date);
        studentPaymentOrderService.update(studentPaymentOrder);
        return payMap;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map rePay(RegisterPayDto registerPayDto) throws Exception {
        StudentRegistration studentRegistration = studentRegistrationService.get(registerPayDto.getRegisterId().longValue());
        if (studentRegistration == null) {
            throw new BizException("报名信息有误，请核查");
        }

        Integer userId = studentRegistration.getUserId();

        StudentPaymentOrder ApplyOrder = studentPaymentOrderService.findMusicGroupApplyOrderByStatus(userId, studentRegistration.getMusicGroupId(), DealStatusEnum.ING);
        if (ApplyOrder == null) {
            throw new BizException("没有支付中的订单，请勿非法请求");
        }

        BigDecimal amount = registerPayDto.getAmount(); //前端获取的价格
        BigDecimal orderAmount = new BigDecimal("0");

        //获取课程价格
        MusicGroupSubjectPlan musicOneSubjectClassPlan = musicGroupSubjectPlanService.getMusicOneSubjectClassPlan(studentRegistration.getMusicGroupId(), studentRegistration.getActualSubjectId());
        BigDecimal courseFee = musicOneSubjectClassPlan.getFee() == null ? BigDecimal.ZERO : musicOneSubjectClassPlan.getFee();
        if (studentRegistration.getTemporaryCourseFee() != null) {
            courseFee = studentRegistration.getTemporaryCourseFee();
        }
        orderAmount = orderAmount.add(courseFee);

        BigDecimal remitFee = BigDecimal.ZERO;
        BigDecimal courseRemitFee = BigDecimal.ZERO; //课程减免费用
        boolean remitCourseRFeeFlag = false; //减免课程费用标识


        //乐器及打包辅件
        List<MusicGroupSubjectGoodsGroup> goodsGroups = new ArrayList<>();
        if (studentRegistration.getTemporaryCourseFee() != null) {
            List<StudentPaymentOrderDetail> orderDetails = studentPaymentOrderDetailService.findUserApplyOrder(studentRegistration.getUserId(), studentRegistration.getMusicGroupId(), DealStatusEnum.WAIT_PAY);
            for (StudentPaymentOrderDetail orderDetail : orderDetails) {
                if (orderDetail == null || orderDetail.getPrice() == null || orderDetail.getGoodsIdList() == null) {
                    continue;
                }
                MusicGroupSubjectGoodsGroup musicGroupSubjectGoodsGroup = new MusicGroupSubjectGoodsGroup();
                GoodsType goodsType = orderDetail.getType().equals(OrderDetailTypeEnum.MUSICAL) ? GoodsType.INSTRUMENT : GoodsType.ACCESSORIES;
                musicGroupSubjectGoodsGroup.setType(goodsType);
                musicGroupSubjectGoodsGroup.setGoodsIdList(orderDetail.getGoodsIdList());
                musicGroupSubjectGoodsGroup.setPrice(orderDetail.getPrice());
                musicGroupSubjectGoodsGroup.setKitGroupPurchaseType(orderDetail.getKitGroupPurchaseType());
                goodsGroups.add(musicGroupSubjectGoodsGroup);

                orderAmount = orderAmount.add(orderDetail.getPrice());
            }
        } else if (StringUtils.isNoneBlank(registerPayDto.getGoodsGroupIds())) {
            goodsGroups = musicGroupSubjectGoodsGroupService.findGoodsGroupByIds(registerPayDto.getGoodsGroupIds());
            for (MusicGroupSubjectGoodsGroup goodsGroup : goodsGroups) {
                if (goodsGroup.getType().equals(GoodsType.INSTRUMENT) && musicOneSubjectClassPlan.getKitGroupPurchaseType().equals(KitGroupPurchaseTypeEnum.LEASE)) {
                    goodsGroup.setPrice(musicOneSubjectClassPlan.getDepositFee());
                }
                if (goodsGroup.getType().equals(GoodsType.INSTRUMENT) && musicOneSubjectClassPlan.getKitGroupPurchaseType().equals(KitGroupPurchaseTypeEnum.FREE)) {
                    goodsGroup.setPrice(new BigDecimal(0));
                }
                orderAmount = orderAmount.add(goodsGroup.getPrice());

                //团购乐器减免课程费用
                if (goodsGroup.getType().equals(GoodsType.INSTRUMENT) && goodsGroup.getRemissionCourseFee() != null && musicOneSubjectClassPlan.getKitGroupPurchaseType().equals(KitGroupPurchaseTypeEnum.GROUP)) {//团购
                    orderAmount = orderAmount.subtract(goodsGroup.getRemissionCourseFee());
                    courseFee = courseFee.subtract(goodsGroup.getRemissionCourseFee());
                }
            }
        } else if (registerPayDto.getGoodsGroups() != null && registerPayDto.getGoodsGroups().size() > 0) {
            String goodsGroupIds = registerPayDto.getGoodsGroups().keySet().stream().map(Object::toString).collect(Collectors.joining(","));
            goodsGroups = musicGroupSubjectGoodsGroupService.findGoodsGroupByIds(goodsGroupIds);
            for (MusicGroupSubjectGoodsGroup goodsGroup : goodsGroups) {
                Map<String, BigDecimal> groupType = JSONObject.parseObject(goodsGroup.getKitGroupPurchaseTypeJson(), new TypeReference<Map<String, BigDecimal>>() {
                });
                if (goodsGroup.getType().equals(GoodsType.INSTRUMENT)) {
                    String kitGroupPurchaseType = registerPayDto.getGoodsGroups().get(goodsGroup.getId());
                    if (!groupType.containsKey(kitGroupPurchaseType)) {
                        throw new BizException("乐器提供方式不存在,请核查");
                    }
                    if (!kitGroupPurchaseType.equals("GROUP")) {
                        goodsGroup.setPrice(kitGroupPurchaseType.equals("FREE") ? new BigDecimal(0) : goodsGroup.getDepositFee());
                    } else {
                        remitCourseRFeeFlag = goodsGroup.getGroupRemissionCourseFee().equals(1);
                    }
                    goodsGroup.setKitGroupPurchaseType(KitGroupPurchaseTypeEnum.valueOf(kitGroupPurchaseType));
                    remitFee = groupType.get(kitGroupPurchaseType);
                }
                orderAmount = orderAmount.add(goodsGroup.getPrice());
                goodsGroup.setGoodsList(goodsService.findGoodsByIds(goodsGroup.getGoodsIdList()));
            }
            orderAmount = orderAmount.subtract(remitFee).subtract(courseRemitFee);
        }

        //单独辅件
        List<Goods> goodsList = null;
        if (registerPayDto.getGoodsIds() != null && !registerPayDto.getGoodsIds().equals("")) {
            goodsList = goodsService.findGoodsByIds(registerPayDto.getGoodsIds());
            for (Goods goods : goodsList) {
                orderAmount = orderAmount.add(goods.getGroupPurchasePrice());
            }
        }

        //单独教谱
        List<Goods> otherGoodsList = null;
        if (registerPayDto.getOtherGoodsIds() != null && !registerPayDto.getOtherGoodsIds().equals("")) {
            otherGoodsList = goodsService.findGoodsByIds(registerPayDto.getOtherGoodsIds());
            for (Goods goods : otherGoodsList) {
                orderAmount = orderAmount.add(goods.getGroupPurchasePrice());
            }
        }
        //可选课程
        List<CourseFormDto> courseForms = new ArrayList<>();
        if (registerPayDto.getCourseKeys() != null && registerPayDto.getCourseKeys().size() > 0) {
            MusicGroup musicGroup = musicGroupDao.get(studentRegistration.getMusicGroupId());
            if (musicGroup.getCourseForm() == null) {
                throw new BizException("可选课程不存在");
            }
            JSONObject courseForm = JSON.parseObject(musicGroup.getCourseForm());
            for (String courseKey : registerPayDto.getCourseKeys()) {
                if (courseForm.get(courseKey) == null) {
                    throw new BizException("可选课程不存在");
                }
                CourseFormDto courseFormDto = new CourseFormDto();
                JSONObject jsonObject = JSON.parseObject(courseForm.getString(courseKey));
                orderAmount = orderAmount.add(jsonObject.getBigDecimal("value"));
                courseFormDto.setType(courseKey);
                courseFormDto.setPrice(jsonObject.getBigDecimal("value"));
                courseForms.add(courseFormDto);
            }
        }

        //新课程形态
        List<MusicGroupPaymentCalenderCourseSettings> newCourses = new ArrayList<>();
        if (registerPayDto.getNewCourse() != null && registerPayDto.getNewCourse().size() > 0) {
            newCourses = musicGroupPaymentCalenderCourseSettingsDao.getCalenderCourseSettings(registerPayDto.getNewCourse());
            for (MusicGroupPaymentCalenderCourseSettings calenderCourseSetting : newCourses) {
                if (remitCourseRFeeFlag && !calenderCourseSetting.getIsStudentOptional()) {
                    courseRemitFee = courseRemitFee.add(calenderCourseSetting.getCourseCurrentPrice());
                    continue;
                }
                orderAmount = orderAmount.add(calenderCourseSetting.getCourseCurrentPrice());
            }
        }

        if (amount.compareTo(orderAmount) != 0) {
            throw new BizException("商品价格不符");
        }

        if (amount.compareTo(BigDecimal.ZERO) < 0) {
            throw new BizException("价格异常");
        }

        String orderNo = idGeneratorService.generatorId("payment") + "";

        String channelType = "";

        StudentPaymentOrder studentPaymentOrder = studentRegistrationService.reAddOrder(userId, amount, orderNo, channelType, courseFee, goodsGroups, goodsList, otherGoodsList, studentRegistration.getMusicGroupId(), ApplyOrder, courseForms, remitFee, courseRemitFee, newCourses);
        studentPaymentOrder.setVersion(0);
        Date date = new Date();

        BigDecimal balance = BigDecimal.ZERO;
        MusicGroup musicGroup = musicGroupDao.get(studentRegistration.getMusicGroupId());
        if (registerPayDto.getIsUseBalancePayment() && amount.compareTo(BigDecimal.ZERO) > 0) {
            SysUserCashAccount userCashAccount = sysUserCashAccountService.get(userId);
            if (userCashAccount == null) {
                throw new BizException("用户账户找不到");
            }
            if (userCashAccount.getBalance() != null && userCashAccount.getBalance().compareTo(BigDecimal.ZERO) > 0) {
                balance = amount.compareTo(userCashAccount.getBalance()) >= 0 ? userCashAccount.getBalance() : amount;
                amount = amount.subtract(balance);
                studentPaymentOrder.setPaymentChannel("BALANCE");
                studentPaymentOrder.setActualAmount(amount);
                studentPaymentOrder.setBalancePaymentAmount(balance);
                sysUserCashAccountService.updateBalance(userId, balance.negate(), PlatformCashAccountDetailTypeEnum.PAY_FEE, "乐团报名");
            }
        }
        studentPaymentOrder.setPaymentChannel("BALANCE");
        studentPaymentOrder.setRemitFee(remitFee);
        studentPaymentOrder.setCourseRemitFee(courseRemitFee);
        studentPaymentOrder.setOrganId(musicGroup.getOrganId());
        studentPaymentOrder.setRoutingOrganId(musicGroup.getOrganId());
        studentPaymentOrder.setUpdateTime(date);
        studentPaymentOrderService.update(studentPaymentOrder);
        studentPaymentOrder.setVersion(studentPaymentOrder.getVersion() + 1);

        if (amount.compareTo(BigDecimal.ZERO) == 0) {
            studentPaymentRouteOrderService.addRouteOrder(orderNo, musicGroup.getOrganId(), balance);
            Map<String, String> notifyMap = new HashMap<>();
            notifyMap.put("tradeState", "1");
            notifyMap.put("merOrderNo", studentPaymentOrder.getOrderNo());
            notifyMap.put("channelType", channelType);
            notifyMap.put("orderNo", "");
            studentPaymentOrderService.updateOrder(notifyMap);
            return notifyMap;
        }

        String orderSubject = "乐团报名";
        String receiver = "register";
        if (musicGroup.getOwnershipType() != null && musicGroup.getOwnershipType().equals(CooperationOrgan.OwnershipType.COOPERATION)) {
            orderSubject = "乐团相关费用";
        }
        String baseApiUrl = sysConfigDao.findConfigValue("base_api_url");
        Map payMap = payService.getPayMap(
                amount,
                balance,
                orderNo,
                baseApiUrl + "/api-student/studentOrder/notify",
                baseApiUrl + "/api-student/studentOrder/paymentResult?orderNo=" + orderNo,
                orderSubject,
                orderSubject,
                musicGroup.getOrganId(),
                receiver
        );

        studentPaymentOrder.setOrganId(musicGroup.getOrganId());
        studentPaymentOrder.setMerNos((String) payMap.get("routingMerNos"));
        studentPaymentOrder.setPaymentChannel((String) payMap.get("type"));
        studentPaymentOrder.setUpdateTime(date);
        studentPaymentOrderService.update(studentPaymentOrder);
        return payMap;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateSubjectInfo(SubFeeSettingDto subFeeSettingDto) throws Exception {
        SysUser sysUser = sysUserFeignService.queryUserInfo();
        if (sysUser == null) {
            throw new BizException("身份校验失败");
        }
        String musicGroupId = subFeeSettingDto.getMusicGroupId();
        //乐团状态是否正确
        MusicGroup musicGroup = musicGroupDao.get(musicGroupId);
        if (musicGroup == null) {
            throw new BizException("乐团信息不存在");
        }
        if (subFeeSettingDto.getMusicGroupStatus() == null) {
            throw new BizException("参数校验异常");
        }
        //声部存在学生不容许删除声部
        List<StudentRegistration> registrations = studentRegistrationDao.findClassGroupStu(musicGroupId, null);
        Map<Integer, List<StudentRegistration>> regMap = registrations.stream().collect(Collectors.groupingBy(StudentRegistration::getActualSubjectId));
        List<MusicGroupSubjectPlan> musicGroupSubjectPlans = subFeeSettingDto.getMusicGroupSubjectPlans();
        List<Integer> waringSubjectIds = new ArrayList<>();
        regMap.forEach((subjectId, regs) -> {
            boolean hasSubject = false;
            for (MusicGroupSubjectPlan musicGroupSubjectPlan : musicGroupSubjectPlans) {
                if (musicGroupSubjectPlan.getSubjectId().equals(subjectId)) {
                    hasSubject = true;
                    musicGroupSubjectPlan.setApplyStudentNum(regs.size());
                }
            }
            if (!hasSubject) {
                waringSubjectIds.add(subjectId);
            }
        });
        if (waringSubjectIds.size() > 0) {
            List<Subject> waringSubjects = subjectDao.findBySubjectIds(waringSubjectIds);
            String waringSubjectStr  = waringSubjects.stream().map(Subject::getName).collect(Collectors.joining(","));
            throw new BizException(waringSubjectStr+"存在学生，不能删除");
        }

        if (musicGroup.getStatus() == MusicGroupStatusEnum.DRAFT || musicGroup.getStatus() == MusicGroupStatusEnum.AUDIT_FAILED) {
            musicGroup.setStatus(subFeeSettingDto.getMusicGroupStatus());
            musicGroup.setUpdateTime(new Date());
            musicGroupDao.update(musicGroup);
        }
        //记录日志信息
        musicGroupBuildLogDao.insert(new MusicGroupBuildLog(musicGroupId, "基础信息提交审核(编辑中 -> 审核中)", sysUser.getId(), JSONObject.toJSONString(subFeeSettingDto)));
        //删除原有的乐团声部规划
        musicGroupSubjectPlanDao.delByMusicGroupId(musicGroupId);
        //删除原有的声部商品组合
        musicGroupSubjectGoodsGroupDao.delByMusicGroupId(subFeeSettingDto.getMusicGroupId());
        //如果是进行中，补充缴费信息
//            if(musicGroup.getStatus() == MusicGroupStatusEnum.PROGRESS){
//                List<MusicGroupStudentFee> musicGroupStudentFees = musicGroupStudentFeeDao.initMusicGroupStudentFee(musicGroupId);
//                if(musicGroupStudentFees != null && musicGroupStudentFees.size() > 0){
//                    Date nextPaymentDate = musicGroupPaymentCalenderService.getNextPaymentDate(musicGroupId, null,null);
//                    musicGroupStudentFeeDao.batchInsert(musicGroupStudentFees,nextPaymentDate,"PAID_COMPLETED");
//                }
//            }
        if (musicGroupSubjectPlans != null && musicGroupSubjectPlans.size() > 0) {
            musicGroupSubjectPlans.forEach(e -> {
                //修改课程费用
                musicGroupStudentFeeDao.updateCourseFee(musicGroupId, e.getSubjectId(), e.getFee());
            });
            musicGroupSubjectPlanDao.batchAdd(musicGroupSubjectPlans, musicGroupId);
        }
        if (subFeeSettingDto.getMusicGroupSubjectGoodsGroups() != null && subFeeSettingDto.getMusicGroupSubjectGoodsGroups().size() > 0) {
            for (MusicGroupSubjectGoodsGroup musicGroupSubjectGoodsGroup : subFeeSettingDto.getMusicGroupSubjectGoodsGroups()) {
                if (musicGroupSubjectGoodsGroup.getType().equals(GoodsType.INSTRUMENT) && (musicGroupSubjectGoodsGroup.getKitGroupPurchaseTypeJson() == null
                        || musicGroupSubjectGoodsGroup.getKitGroupPurchaseTypeJson().isEmpty()
                        || musicGroupSubjectGoodsGroup.getKitGroupPurchaseTypeJson().equals("{}"))) {
                    throw new BizException(musicGroupSubjectGoodsGroup.getName() + " 请选择提供方式");
                }
                if (musicGroupSubjectGoodsGroup.getGroupRemissionCourseFee() == null) {
                    musicGroupSubjectGoodsGroup.setGroupRemissionCourseFee(0);
                }
            }

            musicGroupSubjectGoodsGroupDao.batchInsert(subFeeSettingDto.getMusicGroupSubjectGoodsGroups(), musicGroupId);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateExpectedStudentNum(List<UpdateExpectedNumDto> updateExpectedNumDtos) {
        updateExpectedNumDtos.forEach(e -> {
            MusicGroupSubjectPlan musicGroupSubjectPlan = musicGroupSubjectPlanDao.get(e.getMusicGroupSubjectPlanId());
            musicGroupSubjectPlan.setExpectedStudentNum(e.getExpectedStudentNum());
            if (musicGroupSubjectPlanDao.update(musicGroupSubjectPlan) <= 0) {
                throw new BizException("更新失败,请重试");
            }
        });
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void musicGroupAction(String musicGroupId) throws Exception {
        SysUser sysUser = sysUserFeignService.queryUserInfo();
        if (sysUser == null) {
            throw new BizException("用户信息获取失败");
        }
        MusicGroup musicGroup = saveLog(musicGroupId, MusicGroupStatusEnum.PREPARE);

        //乐器采购清单是否确认
        Map<String, Object> param = new HashMap<>();
        param.put("musicGroupId", musicGroupId);
        int i = musicGroupPurchaseListDao.queryCount(param);
        if (i <= 0) {
            throw new BizException("采购清单未确认");
        }
        //课酬是否确认
        Integer courseScheduleNum = courseScheduleDao.countCourseScheduleByMusicGroupId(musicGroupId);
        if (courseScheduleNum != null && courseScheduleNum > 0) {
            if (classGroupService.checkSetSalary(musicGroupId) == false) {
                throw new BizException("课酬未确认");
            }
        }
        musicGroupStudentFeeDao.batchUpdateCalenders(musicGroupId);
        //记录操作日志
        musicGroupBuildLogDao.insert(new MusicGroupBuildLog(musicGroupId, "确认开团(筹备中 -> 进行中)", sysUser.getId(), ""));
        musicGroup.setStatus(MusicGroupStatusEnum.PROGRESS);
        //获取所有已缴费学员人数
        List<StudentRegistration> studentRegistrations = studentRegistrationDao.queryStudentByMusicGroupId(musicGroupId);
        musicGroup.setGroupMemberNum(studentRegistrations == null ? 0 : studentRegistrations.size());
        musicGroup.setBillStartDate(new Date());
        musicGroupDao.update(musicGroup);
        //获取乐团班级列表
        List<ClassGroup> classGroups = classGroupDao.queryClassGroups(musicGroupId, "MUSIC");
        for (ClassGroup classGroup : classGroups) {
            //获取班级关联的老师列表
            Set<Integer> teacherIds = classGroupTeacherMapperDao.queryTeacherIdsByClassGroupId(classGroup.getId(),null,null);
            //获取班级关联的学员列表
            Set<Integer> studentIds = classGroupStudentMapperDao.queryStudentIdsByClassGroupId(classGroup.getId(),null,null);
            //创建IM群组
            classGroupService.addImGroup(classGroup, new ArrayList<>(studentIds), new ArrayList<>(teacherIds));
        }
        imUserFriendService.refreshGroupImUserFriend(musicGroupId,GroupType.MUSIC);
        //给老师发送乐团成立通知
        Map<Integer, String> map = JSONObject.parseObject(JSONObject.toJSONString(MapUtil.convertMybatisMap(musicGroupDao.queryTeacherIdMap(musicGroupId))), HashMap.class);
        if (map != null && map.size() > 0) {
            sysMessageService.batchSendMessage(MessageSender.JIGUANG, MessageTypeEnum.TEACHER_PUSH_MUSIC_GROUP_COURSE_ADD_PLAN,
                    map, null, 0, "1", "TEACHER", musicGroup.getName());
        }
        Set<Integer> roleIds = new HashSet<>(5);
        roleIds.add(SysUserRole.SECTION_MANAGER);
        roleIds.add(SysUserRole.EDUCATIONAL_TEACHER);
        roleIds.add(SysUserRole.OPERATION_EXECUTIVE);
        roleIds.add(SysUserRole.ADMISSIONS_DIRECTOR);
        roleIds.add(SysUserRole.DEAN_OF_STUDIES);

        sysMessageService.batchSeoMessage(musicGroupDao.queryUserIdByRoleId(roleIds, musicGroup.getOrganId()), MessageTypeEnum.BACKSTAGE_ACTION_GROUP, "1", musicGroup.getName());
    }

    private MusicGroup saveLog(String musicGroupId, MusicGroupStatusEnum statusEnum) throws Exception {
        Date date = new Date();
        MusicGroup musicGroup = musicGroupDao.get(musicGroupId);
        if (musicGroup == null) {
            throw new BizException("乐团信息不存在");
        }
        if (musicGroup.getStatus() != statusEnum) {
            throw new BizException("当前乐团状态不支持此操作");
        }
        musicGroup.setUpdateTime(date);
        return musicGroup;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void musicGroupAudit(String musicGroupId) throws Exception {
        SysUser sysUser = sysUserFeignService.queryUserInfo();
        if (sysUser == null) {
            throw new BizException("用户信息获取失败");
        }
        MusicGroup musicGroup = saveLog(musicGroupId, MusicGroupStatusEnum.DRAFT);
        //记录操作日志
        musicGroupBuildLogDao.insert(new MusicGroupBuildLog(musicGroupId, "提交审核（草稿 -> 审核中）", sysUser.getId(), ""));
        musicGroup.setStatus(MusicGroupStatusEnum.AUDIT);
        musicGroupDao.update(musicGroup);
        Set<Integer> roleIds = new HashSet<>(1);
        roleIds.add(SysUserRole.SECTION_MANAGER);

        sysMessageService.batchSeoMessage(musicGroupDao.queryUserIdByRoleId(roleIds, musicGroup.getOrganId()), MessageTypeEnum.BACKSTAGE_CREATE_MUSIC_GROUP_APPLY, "", sysUser.getUsername());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void musicGroupAuditFailed(String musicGroupId, String memo) throws Exception {
        SysUser sysUser = sysUserFeignService.queryUserInfo();
        if (sysUser == null) {
            throw new BizException("用户信息获取失败");
        }
        MusicGroup musicGroup = saveLog(musicGroupId, MusicGroupStatusEnum.AUDIT);
        //记录操作日志
        musicGroupBuildLogDao.insert(new MusicGroupBuildLog(musicGroupId, "乐团审核失败（审核中 -> 审核失败）", sysUser.getId(), memo));
        musicGroup.setMemo(memo);
        musicGroup.setStatus(MusicGroupStatusEnum.AUDIT_FAILED);
        musicGroupDao.update(musicGroup);
        //修改缴费项目状态
        List<MusicGroupPaymentCalender> musicGroupPaymentCalenders = musicGroupPaymentCalenderDao.findByMusicGroupId(musicGroupId);
        if (musicGroupPaymentCalenders != null && musicGroupPaymentCalenders.size() > 0) {
            musicGroupPaymentCalenders.forEach(e -> {
                e.setStatus(MusicGroupPaymentCalender.PaymentCalenderStatusEnum.REJECT);
            });
            musicGroupPaymentCalenderDao.batchUpdate(musicGroupPaymentCalenders);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void musicGroupAuditSuccess(String musicGroupId) throws Exception {
        SysUser sysUser = sysUserFeignService.queryUserInfo();
        if (sysUser == null) {
            throw new BizException("用户信息获取失败");
        }
        MusicGroup musicGroup = saveLog(musicGroupId, MusicGroupStatusEnum.AUDIT);
        //记录操作日志
        musicGroupBuildLogDao.insert(new MusicGroupBuildLog(musicGroupId, "审核通过（审核中 -> 预报名）", sysUser.getId(), ""));
        musicGroup.setStatus(MusicGroupStatusEnum.PRE_APPLY);
        musicGroupDao.update(musicGroup);
        
        // 创建群
        imGroupService.create(Long.parseLong(musicGroupId), null, "乐团预报名", null, musicGroup.getName(), musicGroup.getName(), null, GroupType.MUSIC.getCode());
        
        Map<Integer,String> userRoleMap = new HashMap<Integer, String>();
        
        if(musicGroup.getTeamTeacherId() != null){
        	userRoleMap.put(musicGroup.getTeamTeacherId(), "运营主管");
        }
        if(musicGroup.getEducationalTeacherId() != null){
        	userRoleMap.put(musicGroup.getEducationalTeacherId(), "乐团主管");
        }
        if(musicGroup.getDirectorUserId() != null){
        	userRoleMap.put(musicGroup.getDirectorUserId(), "乐队指导");
        }
        // 添加成员
        imGroupMemberService.join(Long.parseLong(musicGroupId), userRoleMap);

    }

    @Override
    public int pushMessage(String musicGroupId, String classGroupIds) throws IOException {
        MusicGroup musicGroup = musicGroupDao.get(musicGroupId);
        if (musicGroup.getOwnershipType() == null || musicGroup.getOwnershipType() != CooperationOrgan.OwnershipType.OWN) {
            throw new BizException("三方乐团，不推送报名信息");
        }
        List<HighClassGroupDto> highClassGroup = classGroupDao.findHighClassGroup(musicGroupId, classGroupIds);

        if (classGroupIds != null && !classGroupIds.isEmpty()) {
            List<Integer> classGroupSet = highClassGroup.stream().map(HighClassGroupDto::getId).collect(Collectors.toList());
            Map<Integer, Long> totalNumMap = MapUtil.convertIntegerMap(courseScheduleDao.countTotalNumByClassGroupId(classGroupSet, null));
            highClassGroup.removeIf(next -> totalNumMap.get(next.getId()) != null && totalNumMap.get(next.getId()) > 0);
        }
        Set<ClassGroupTypeEnum> classGroupTypeSet = highClassGroup.stream().map(HighClassGroupDto::getType).collect(Collectors.toSet());
        String HighClassGroupSubjectIds = highClassGroup.stream().filter(e -> e.getType().equals(ClassGroupTypeEnum.HIGH)).map(HighClassGroupDto::getSubjectIdList).collect(Collectors.joining(","));
        String HighOnlineClassGroupSubjectIds = highClassGroup.stream().filter(e -> e.getType().equals(ClassGroupTypeEnum.HIGH_ONLINE)).map(HighClassGroupDto::getMemo).collect(Collectors.joining(","));
        if (!HighClassGroupSubjectIds.isEmpty() && !HighOnlineClassGroupSubjectIds.isEmpty()) {
            HighClassGroupSubjectIds += "," + HighOnlineClassGroupSubjectIds;
        } else {
            HighClassGroupSubjectIds += HighOnlineClassGroupSubjectIds;
        }

        String[] subjectIds = HighClassGroupSubjectIds.split(",");

        List<StudentRegistration> students = new ArrayList<>();
        if (classGroupTypeSet.contains(ClassGroupTypeEnum.HIGH)) {
            List<StudentRegistration> noHighClassGroupStudents = studentRegistrationService.findMusicGroupStuNoClassType(musicGroupId, null, ClassGroupTypeEnum.HIGH, null);
            students.addAll(noHighClassGroupStudents);
        }
        if (classGroupTypeSet.contains(ClassGroupTypeEnum.HIGH_ONLINE)) {
            List<StudentRegistration> noHighOnlineClassGroupStudents = studentRegistrationService.findMusicGroupStuNoClassType(musicGroupId, null, ClassGroupTypeEnum.HIGH_ONLINE, null);
            students.addAll(noHighOnlineClassGroupStudents);
        }


        Map<Integer, String> studentMap = new HashMap<>();
        for (StudentRegistration student : students) {
            if (!Arrays.asList(subjectIds).contains(student.getActualSubjectId().toString())) {
                continue;
            }
            studentMap.put(student.getUserId(), student.getUserId().toString());
        }

        if (studentMap.size() == 0) {
            throw new BizException("开启报名失败，没有可推送的学生");
        }

        String baseURL = sysConfigDao.findConfigValue(SysConfigService.BASE_API_URL);
        String url = baseURL + "/#/smallRegister?musicGroupId=" + musicGroupId;
        classGroupIds = highClassGroup.stream().map(e -> e.getId().toString()).collect(Collectors.joining(","));
        if (classGroupIds != null && !classGroupIds.isEmpty()) {
            url = baseURL + "/#/smallRegister?musicGroupId=" + musicGroupId + "&classGroupIds=" + classGroupIds;
        }
        String serverPhone = sysConfigDao.findConfigValue(SysConfigService.SERVER_PHONE);
        sysMessageService.batchSendMessage(MessageSender.JIGUANG, MessageTypeEnum.SMS_BASICS_SKILL_APPLY_MESSAGE,
                studentMap, null, 0, "5?" + url, "STUDENT", musicGroup.getName(), HttpUtil.getSortUrl(url), serverPhone);

        return studentMap.size();
    }

    @Override
    public List<MusicCardDto> queryOrganMusicInfos(Integer organId) {
        return musicGroupDao.queryOrganMusicInfos(organId);
    }

    @Override
    public List<MusicCardDto> queryUserMusicGroups(Integer userId) {
        List<MusicCardDto> musicCardDtos = musicGroupDao.queryUserMusicGroups(userId);
        Set<String> musicGroupIds = musicCardDtos.stream().map(MusicCardDto::getMusicGroupId).collect(Collectors.toSet());
        Map<String, String> paymentStatus = MapUtil.convertMybatisMap(musicGroupPaymentCalenderDao.queryUserPaymentStatus(userId, StringUtils.join(musicGroupIds, ",")));
        // 获取学员在该乐团续费状态
        musicCardDtos.forEach(e -> {
            e.setPaymentStatus(paymentStatus.get(e.getMusicGroupId()));
        });
        return musicCardDtos;
    }


    @Override
    public MusicCardDto queryPersonalMusicGroups(Integer userId) {
        SysUser sysUser = sysUserFeignService.queryUserById(userId);
        if (sysUser == null) {
            throw new BizException("用户不存在");
        }
        MusicCardDto musicCardDto = musicGroupDao.queryPersonalMusicGroups(userId);
        if (musicCardDto == null) {
            musicCardDto = new MusicCardDto();
            musicCardDto.setUserName(sysUser.getUsername());
        }
        musicCardDto.setMusicGroupNum(musicGroupDao.countUserMusicGroups(userId));
        musicCardDto.setVipClassNum(classGroupStudentMapperDao.countUserGroups(userId, ClassGroupTypeEnum.VIP.getCode()));
        return musicCardDto;
    }

    @Override
    public List<BasicUserDto> findTeachersByStuId(Integer studentId, String search) {
        //获取相关课程，班级老师列表
        Set<Integer> teacherIds = teacherDao.findMusicTeacherIds(studentId);
        //获取学员所在乐团列表
        List<String> musicGroupIds = studentRegistrationDao.queryStudentMusicGroup(studentId);
        if (musicGroupIds != null && musicGroupIds.size() > 0) {
            List<MusicGroup> musicGroups = musicGroupDao.queryListByIds(StringUtils.join(musicGroupIds, ","));
            musicGroups.forEach(e -> {
                teacherIds.add(e.getDirectorUserId());
                teacherIds.add(e.getEducationalTeacherId());
                teacherIds.add(e.getTeamTeacherId());
            });
        }
        //获取相关vip课老师列表
        teacherIds.addAll(teacherDao.findVipTeacherIds(studentId));
        //获取陪练课老师列表
        teacherIds.addAll(teacherDao.findPracticeTeacherIds(studentId));
        //获取对外课程老师列表
        teacherIds.addAll(teacherDao.findCloseCourseTeacherIds(studentId));
        //获取陪练课课程教务老师
        teacherIds.addAll(teacherDao.findPracticeEducationalTeacherId(studentId));
        //获取VIP课程教务老师
        teacherIds.addAll(teacherDao.findVipEducationalTeacherId(studentId));
        //获取对外课程务老师
        teacherIds.addAll(teacherDao.findCommEducationalTeacherId(studentId));
        //获取关联的指导老师
        Student student = studentDao.get(studentId);
        if (student != null && student.getTeacherId() != null) {
            teacherIds.add(student.getTeacherId());
        }
        if (teacherIds.size() > 0) {
            return teacherDao.queryTeacherBaseInfo(teacherIds, search);
        }
        return new ArrayList<>();
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public boolean cancelMusicGroup(String musicGroupId) {
        SysUser sysUser = sysUserFeignService.queryUserInfo();
        if (sysUser == null) {
            throw new BizException("用户信息获取失败");
        }
        MusicGroup musicGroup = musicGroupDao.getLocked(musicGroupId);
        if (musicGroup == null) {
            throw new BizException("乐团找不到");
        }

        if (musicGroup.getStatus() != MusicGroupStatusEnum.PROGRESS) {
            musicGroup.setStatus(MusicGroupStatusEnum.CANCELED);
            musicGroup.setUpdateTime(new Date());
            musicGroupDao.update(musicGroup);
        } else {
            throw new BizException("乐团当前状态是{}，不能取消", musicGroup.getStatus().getMsg());
        }

        // 查询是否有中间状态的缴费信息
        List<StudentPaymentOrder> studentPaymentOrders = studentPaymentOrderDao.queryByDealStatus(musicGroupId, OrderTypeEnum.APPLY, DealStatusEnum.ING);

        if (studentPaymentOrders != null && studentPaymentOrders.size() > 0) {
            throw new BizException("缴费存在交易中的数据，不能取消乐团");
        }

        //删除续费记录
        musicGroupStudentFeeDao.deleteByMusicGroupId(musicGroupId, null);

        // 删除课表
        courseScheduleDao.deleteCourseSchedulesByMusicGroupID(musicGroupId, GroupType.MUSIC);
        // 删除每节课的课酬
        courseScheduleStudentPaymentService.deleteByMusicGroupId(musicGroupId, GroupType.MUSIC);
        courseScheduleTeacherSalaryDao.deleteByMusicGroupId(musicGroupId, GroupType.MUSIC);

        //删除考勤
        teacherAttendanceDao.deleteByMusicGroupId(musicGroupId, GroupType.MUSIC);

        /*// 查询已缴费信息
        studentPaymentOrders = studentPaymentOrderDao.queryByDealStatus(musicGroupId, OrderTypeEnum.APPLY, SUCCESS);

        // 退费
        for (StudentPaymentOrder order : studentPaymentOrders) {
            // 增加交易流水
            sysUserCashAccountDetailService.addCashAccountDetail(order.getUserId(), order.getActualAmount().add(order.getBalancePaymentAmount()), SysUserCashAccountDetailService.MUSIC_GROUP
                    + musicGroupId, "", PlatformCashAccountDetailTypeEnum.REFUNDS, null, SUCCESS, "取消乐团", null);
        }*/
        //获取当前乐团所有已报名学员
        if (musicGroup.getOwnershipType() != null && musicGroup.getOwnershipType() == CooperationOrgan.OwnershipType.OWN) {
            List<StudentRegistration> registrations = studentRegistrationDao.findClassGroupStu(musicGroupId, null);
            if (registrations != null && registrations.size() > 0) {
                Map<Integer, String> map = new HashMap<>(registrations.size());
                registrations.forEach(e -> {
                    map.put(e.getUserId(), e.getUserId().toString());
                });
                sysMessageService.batchSendMessage(MessageSender.JIGUANG, MessageTypeEnum.STUDENT_PUSH_MUSIC_GROUP_CLOSE,
                        map, null, 0, "1", "STUDENT", musicGroup.getName(), sysConfigDao.findConfigValue(SysConfigService.REFUND_PERIOD));
            }
        }
        //记录建团日志
        musicGroupBuildLogDao.insert(new MusicGroupBuildLog(musicGroupId, "取消乐团", sysUser.getId(), ""));
        Set<Integer> roleIds = new HashSet<>(2);
        roleIds.add(SysUserRole.SECTION_MANAGER);
        roleIds.add(SysUserRole.OPERATION_EXECUTIVE);

        sysMessageService.batchSeoMessage(musicGroupDao.queryUserIdByRoleId(roleIds, musicGroup.getOrganId()), MessageTypeEnum.BACKSTAGE_MUSIC_GROUP_STOP, "1", musicGroup.getName());
        return true;
    }

    @Override
    public boolean deleteMusicGroup(String musicGroupId) {

        MusicGroup musicGroup = musicGroupDao.get(musicGroupId);

        if (musicGroup == null) {
            throw new BizException("乐团不存在");
        }

        if (musicGroup.getDelFlag() == true) {
            throw new BizException("乐团已删除");
        }

        if (musicGroup.getStatus() != MusicGroupStatusEnum.CANCELED) {
            throw new BizException("乐团当前状态是{}，不能删除", musicGroup.getStatus().getMsg());
        }

        musicGroup.setUpdateTime(new Date());
        musicGroup.setDelFlag(true);
        musicGroupDao.update(musicGroup);

        return true;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public boolean pauseMusicGroup(String musicGroupId) {
        SysUser sysUser = sysUserFeignService.queryUserInfo();
        if (sysUser == null) {
            throw new BizException("用户信息获取失败");
        }
        MusicGroup musicGroup = musicGroupDao.get(musicGroupId);
        if (musicGroup == null) {
            throw new BizException("乐团找不到");
        }

        if (musicGroup.getStatus() != MusicGroupStatusEnum.PROGRESS) {
            throw new BizException("乐团当前状态是{}，不能暂停", musicGroup.getStatus().getMsg());
        }

        musicGroup.setStatus(MusicGroupStatusEnum.PAUSE);
        musicGroup.setUpdateTime(new Date());
        musicGroupDao.update(musicGroup);

        // 清除下次缴费时间
        musicGroupStudentFeeDao.updateNextPaymentDate(musicGroupId, null);
        musicGroupBuildLogDao.insert(new MusicGroupBuildLog(musicGroupId, "暂停乐团", sysUser.getId(), ""));

        //删除课表
        courseScheduleDao.logicDeleteCourseSchedulesByMusicGroupID(musicGroup.getId());

        return true;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public boolean resumeMusicGroup(String musicGroupId) {
        SysUser sysUser = sysUserFeignService.queryUserInfo();
        if (sysUser == null) {
            throw new BizException("用户信息获取失败");
        }
        MusicGroup musicGroup = musicGroupDao.get(musicGroupId);
        if (musicGroup == null) {
            throw new BizException("乐团找不到");
        }

        if (musicGroup.getStatus() != MusicGroupStatusEnum.PAUSE) {
            throw new BizException("乐团当前状态是{}，不能恢复", musicGroup.getStatus().getMsg());
        }

        musicGroup.setStatus(MusicGroupStatusEnum.PROGRESS);
        musicGroup.setUpdateTime(new Date());
        musicGroupDao.update(musicGroup);

        // 重新设置下次缴费时间
        /*List<MusicGroupStudentFee> fees = musicGroupStudentFeeDao.queryByMusicGroupId(musicGroupId);
        Date date = new Date();
        fees.forEach(e -> {
            e.setNextPaymentDate(musicGroupPaymentCalenderService.getNextPaymentDate(musicGroupId, null, e));
            e.setUpdateTime(date);
        });
        musicGroupStudentFeeDao.batchUpdate(fees);*/
//        musicGroupStudentFeeDao.updateNextPaymentDate(musicGroupId, musicGroupPaymentCalenderService.getNextPaymentDate(musicGroupId, null));
        musicGroupBuildLogDao.insert(new MusicGroupBuildLog(musicGroupId, "恢复乐团", sysUser.getId(), ""));

        //恢复课表
        courseScheduleDao.resumeCourseScheduleByMusicGroupId(musicGroup.getId());

        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean extensionPaymentExpireDate(String musicGroupId, Date expireDate) {
        SysUser sysUser = sysUserFeignService.queryUserInfo();
        if (sysUser == null) {
            throw new BizException("用户信息获取失败");
        }
        MusicGroup musicGroup = musicGroupDao.get(musicGroupId);
        if (musicGroup == null) {
            throw new BizException("乐团找不到");
        }

        if (musicGroup.getStatus() != MusicGroupStatusEnum.PAY) {
            throw new BizException("乐团当前状态是[{}]，不能延长缴费", musicGroup.getStatus().getMsg());
        }

        Date date = new Date();

        if (expireDate.before(date)) {
            throw new BizException("日期设置错误");
        }

        musicGroup.setPaymentExpireDate(expireDate);
        musicGroup.setUpdateTime(date);
        musicGroupDao.update(musicGroup);

        MusicGroupPaymentCalender regCalender = musicGroupPaymentCalenderService.findByMusicGroupRegCalender(musicGroup.getId());
        if (regCalender != null && regCalender.getPayUserType().equals(MusicGroupPaymentCalender.PayUserType.STUDENT)) {
            regCalender.setDeadlinePaymentDate(expireDate);
            regCalender.setStatus(MusicGroupPaymentCalender.PaymentCalenderStatusEnum.OPEN);
            regCalender.setUpdateTime(date);
            musicGroupPaymentCalenderService.update(regCalender);
        }

        musicGroupBuildLogDao.insert(new MusicGroupBuildLog(musicGroupId, "延长缴费", sysUser.getId(), ""));
        Set<Integer> roleIds = new HashSet<>(4);
        roleIds.add(SysUserRole.SECTION_MANAGER);
        roleIds.add(SysUserRole.EDUCATIONAL_TEACHER);
        roleIds.add(SysUserRole.OPERATION_EXECUTIVE);
        roleIds.add(SysUserRole.ADMISSIONS_DIRECTOR);

        sysMessageService.batchSeoMessage(musicGroupDao.queryUserIdByRoleId(roleIds, musicGroup.getOrganId()), MessageTypeEnum.BACKSTAGE_LENGTHEN_PAYMENT, "", musicGroup.getName());
        return true;
    }

    @Override
    public boolean extensionApplyExpireDate(String musicGroupId, Date expireDate) {
        SysUser sysUser = sysUserFeignService.queryUserInfo();
        if (sysUser == null) {
            throw new BizException("用户信息获取失败");
        }
        MusicGroup musicGroup = musicGroupDao.get(musicGroupId);
        if (musicGroup == null) {
            throw new BizException("乐团找不到");
        }

        if (!(musicGroup.getStatus() == MusicGroupStatusEnum.APPLY || musicGroup.getStatus() == MusicGroupStatusEnum.PAY)) {
            throw new BizException("乐团当前状态是[{}]，不能延长报名", musicGroup.getStatus().getMsg());
        }

        Date date = new Date();

        if (date.after(expireDate)) {
            throw new BizException("日期设置错误");
        }

        musicGroup.setApplyExpireDate(expireDate);
        musicGroup.setUpdateTime(date);
        musicGroupDao.update(musicGroup);
        musicGroupBuildLogDao.insert(new MusicGroupBuildLog(musicGroupId, "延长报名时间", sysUser.getId(), ""));
        return true;
    }

    @Override
	public boolean extensionPreApplyExpireDate(String musicGroupId, Date expireDate) {
    	SysUser sysUser = sysUserFeignService.queryUserInfo();
        if (sysUser == null) {
            throw new BizException("用户信息获取失败");
        }
        MusicGroup musicGroup = musicGroupDao.get(musicGroupId);
        if (musicGroup == null) {
            throw new BizException("乐团找不到");
        }

        if (musicGroup.getStatus() != MusicGroupStatusEnum.PRE_APPLY) {
            throw new BizException("乐团当前状态是[{}]，不能延长预报名", musicGroup.getStatus().getMsg());
        }

        Date date = new Date();

        if (date.after(expireDate)) {
            throw new BizException("日期设置错误");
        }

        musicGroup.setPreApplyExpireDate(expireDate);
        musicGroup.setUpdateTime(date);
        musicGroupDao.update(musicGroup);
        musicGroupBuildLogDao.insert(new MusicGroupBuildLog(musicGroupId, "延长预报名时间", sysUser.getId(), ""));
        return true;
	}

	@Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public boolean applyQuitMusicGroup(String musicGroupId, String reason) {
        SysUser sysUser = sysUserFeignService.queryUserInfo();
        if (sysUser == null) {
            throw new BizException("用户信息获取失败");
        }
        MusicGroup musicGroup = musicGroupDao.get(musicGroupId);
        if (musicGroup == null) {
            throw new BizException("乐团不存在");
        }

        if (musicGroup.getStatus() == MusicGroupStatusEnum.CANCELED || musicGroup.getStatus() == MusicGroupStatusEnum.PAUSE) {
            throw new BizException("申请失败，乐团状态[已取消]或[已暂停]");
        }
        Integer userId = sysUser.getId();

        StudentRegistration studentRegistration = studentRegistrationDao.queryByUserIdAndMusicGroupId(userId, musicGroupId);
        if (studentRegistration == null) {
            throw new BizException("用户注册信息不存在");
        }

        MusicGroupQuit musicGroupQuit = musicGroupQuitDao.queryByUserIdAndMusicGroupId(userId, musicGroupId);
        if (musicGroupQuit != null) {
            if (musicGroupQuit.getStatus() == ApprovalStatus.PROCESSING) {
                throw new BizException("申请失败，存在[申请中]的记录");
            }
        }

        musicGroupQuit = new MusicGroupQuit();
        musicGroupQuit.setCreateTime(new Date());
        musicGroupQuit.setJoinDate(studentRegistration.getCreateTime());
        musicGroupQuit.setMusicGroupId(musicGroupId);
        musicGroupQuit.setUserId(sysUser.getId());
        musicGroupQuit.setUserComment(reason);
        musicGroupQuit.setStatus(ApprovalStatus.PROCESSING);

        musicGroupQuitDao.insert(musicGroupQuit);
        Set<Integer> roleIds = new HashSet<>(1);
        roleIds.add(SysUserRole.EDUCATIONAL_TEACHER);
        Map<String, Object> memo = new HashMap<>(2);
        memo.put("Id", musicGroupQuit.getId());
        memo.put("type", "MUSICGROUP");

        sysMessageService.batchSeoMessage(musicGroupDao.queryUserIdByRoleId(roleIds, musicGroup.getOrganId()),
                MessageTypeEnum.BACKSTAGE_STUDENT_APPLY_QUIT_GROUP, JSONObject.toJSONString(memo), sysUser.getUsername());
        Map<Integer, String> receivers = new HashMap<>(1);
        receivers.put(musicGroup.getEducationalTeacherId(), musicGroup.getEducationalTeacherId().toString());
        sysMessageService.batchSendMessage(MessageSender.JIGUANG, MessageTypeEnum.PUSH_STUDENT_COMMIT_QUIT_MUSIC_APPLY,
                receivers, null, 0, null, "SYSTEM", musicGroup.getName(), sysUser.getUsername());
        return true;
    }

    @Override
    public boolean cancelQuitMusicGroup(Integer userId, String musicGroupId, String reason) {
        MusicGroupQuit musicGroupQuit = musicGroupQuitDao.queryByUserIdAndMusicGroupId(userId, musicGroupId);
        if (musicGroupQuit == null) {
            throw new BizException("操作失败，没有查询到退团记录");
        }
        SysUser sysUser = sysUserFeignService.queryUserInfo();
        if (sysUser == null) {
            throw new BizException("用户信息获取失败");
        }
        MusicGroup musicGroup = musicGroupDao.get(musicGroupId);
        if (musicGroup == null) {
            throw new BizException("乐团不存在");
        }
		if (musicGroup.getStatus() == MusicGroupStatusEnum.PAY || musicGroup.getStatus() == MusicGroupStatusEnum.PREPARE
				|| musicGroup.getStatus() == MusicGroupStatusEnum.PROGRESS || musicGroup.getStatus() == MusicGroupStatusEnum.CANCELED
				|| musicGroup.getStatus() == MusicGroupStatusEnum.PAUSE || musicGroup.getStatus() == MusicGroupStatusEnum.CLOSE) {
			throw new BizException("乐团当前状态下不能取消");
		}
        musicGroupQuit.setStatus(ApprovalStatus.CANCELED);
        musicGroupQuit.setReason(reason);
        musicGroupQuit.setQuitDate(new Date());
        musicGroupQuitDao.update(musicGroupQuit);

        Map<Integer, String> receivers = new HashMap<>(1);
        receivers.put(musicGroup.getEducationalTeacherId(), musicGroup.getEducationalTeacherId().toString());
        sysMessageService.batchSendMessage(MessageSender.JIGUANG, MessageTypeEnum.PUSH_STUDENT_REVOKE_QUIT_MUSIC_APPLY,
                receivers, null, 0, null, "SYSTEM", musicGroup.getName(), sysUser.getUsername());
        return true;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public boolean approveQuitMusicGroup(Long id, ApprovalStatus status, String reason, boolean isRefundCourseFee, boolean isRefundInstrumentFee,
                                         boolean isRefundTeachingAssistantsFee) {
        MusicGroupQuit musicGroupQuit = musicGroupQuitDao.get(id);
        if (musicGroupQuit == null) {
            throw new BizException("数据不存在");
        }
        Date date = new Date();

        String musicGroupId = musicGroupQuit.getMusicGroupId();
        Integer userId = musicGroupQuit.getUserId();

        MusicGroup musicGroup = musicGroupDao.get(musicGroupId);
        if (musicGroup == null) {
            throw new BizException("乐团不存在");
        }

        if (musicGroup.getStatus() == MusicGroupStatusEnum.CANCELED || musicGroup.getStatus() == MusicGroupStatusEnum.PAUSE) {
            throw new BizException("申请失败，乐团状态[已取消]或[已暂停]");
        }

		// 有进行中的课程不能退团
		List<CourseSchedule> courseScheduleList = courseScheduleDao.findMusicGroupCourseSchedulesWithStudent(musicGroupId, GroupType.MUSIC.getCode(),
				"UNDERWAY", userId);
		if (courseScheduleList != null && courseScheduleList.size() > 0) {
			throw new BizException("退团失败，存在[进行中]的课程");
		}

        musicGroupQuit.setStatus(status);
        musicGroupQuit.setReason(reason);
        musicGroupQuit.setQuitDate(date);
        musicGroupQuitDao.update(musicGroupQuit);

        courseScheduleStudentPaymentService.updateCourseActualPrice(Arrays.asList(musicGroupId), Arrays.asList(userId), GroupType.MUSIC);

        if (status == ApprovalStatus.APPROVED) {

            StudentRegistration studentRegistration = studentRegistrationDao.queryByUserIdAndMusicGroupId(userId, musicGroupId);
            if (studentRegistration == null) {
                throw new BizException("用户注册信息不存在");
            }

            List<Integer> classGroupIdList = classGroupStudentMapperDao.queryClassGroupIdList(musicGroupId, userId, GroupType.MUSIC);
            //更新学员在班级的状态
            for (Integer classGroupId : classGroupIdList) {
                ClassGroup classGroup = classGroupService.get(classGroupId);
                if (classGroup.getType().equals(ClassGroupTypeEnum.MUSIC_NETWORK)) {
                    classGroupService.delSingle(classGroupId);
                } else {
                    classGroupStudentMapperService.delClassGroupStudent(userId, classGroupId, true);
                }
            }

            //删除续费周期
            musicGroupStudentFeeDao.deleteByUserIdAndMusicGroupId(userId, musicGroupId);
            // 退团
            BigDecimal surplusCourseFee = studentRegistration.getSurplusCourseFee();
            StudentMusicGroupStatusEnum currentStudentMusicGroupStatus = studentRegistration.getMusicGroupStatus();
            studentRegistration.setMusicGroupStatus(StudentMusicGroupStatusEnum.QUIT);
            studentRegistration.setSurplusCourseFee(BigDecimal.ZERO);
            studentRegistration.setUpdateTime(date);

            studentRegistrationDao.update(studentRegistration);

            //更新服务指标、运营指标
            int remainCourseNum = courseScheduleStudentPaymentDao.countStudentNotStartCourseNumWithCourseType(userId, null);
            if (remainCourseNum == 0) {
                Student student = studentDao.get(userId);
                if (student == null) {
                    throw new BizException("学生信息查询失败");
                }
                student.setServiceTag(0);
                student.setOperatingTag(0);
                student.setOperatingTempTag(0);
                student.setUpdateTime(date);
                studentDao.update(student);
            }

            //删除进行中加学生，且在审批中或拒绝的缴费
            List<Long> paymentCalenderIdList = musicGroupPaymentCalenderDao.findStudentNoPaymentCalender(userId, musicGroupId);
            if(paymentCalenderIdList != null && paymentCalenderIdList.size() > 0){
            	musicGroupPaymentCalenderDao.delByIds(paymentCalenderIdList);
            }
            
            //查询未交费的项目
            List<MusicGroupPaymentCalenderDetail> musicGroupPaymentCalenderDetailList = musicGroupPaymentCalenderDetailDao.queryNotPaymentStudentByUserIdAndMusicGroupId(userId, musicGroupId);
            
			for (MusicGroupPaymentCalenderDetail mgpcd : musicGroupPaymentCalenderDetailList) {
				MusicGroupPaymentCalender mgpc = musicGroupPaymentCalenderDao.get(mgpcd.getMusicGroupPaymentCalenderId());
				if (mgpc != null) {
					if (mgpc.getPaymentType() == PaymentType.ADD_STUDENT) {
						musicGroupPaymentCalenderDao.delete(mgpc.getId());
					} else {
						// 缴费项目预计人数减一
						mgpc.setExpectNum(mgpc.getExpectNum() - 1);
						mgpc.setUpdateTime(date);
						musicGroupPaymentCalenderDao.update(mgpc);
					}
				}
				musicGroupPaymentCalenderDetailDao.delete(mgpcd.getId());
			}
            //删除用户购买的课程记录
            musicGroupPaymentStudentCourseDetailDao.deleteByUserIdAndMusicGroupId(userId, musicGroupId);

            BigDecimal amount = new BigDecimal(0);

            // 判断乐器是否是租赁
            MusicGroupSubjectPlan musicGroupSubjectPlan = musicGroupSubjectPlanDao.getMusicOneSubjectClassPlan(musicGroupId, studentRegistration.getActualSubjectId());
            if (musicGroupSubjectPlan != null) {
                musicGroupSubjectPlan.setPaidStudentNum(musicGroupSubjectPlan.getPaidStudentNum() - 1);
                musicGroupSubjectPlan.setUpdateTime(date);
                musicGroupSubjectPlanDao.update(musicGroupSubjectPlan);
            }
            
            if(currentStudentMusicGroupStatus != StudentMusicGroupStatusEnum.NORMAL){
            	return true;
            }
            
            if (isRefundCourseFee) {
                // 退课程费用
                amount = amount.add(surplusCourseFee);
            }

            StudentPaymentOrder studentPaymentOrder = studentPaymentOrderService.findMusicGroupApplyOrderByStatus(userId, musicGroupId, SUCCESS);

            if (studentPaymentOrder != null) {
            	List<StudentPaymentOrderDetail> orderDetailList = studentPaymentOrderDetailDao.findApplyOrderGoods(studentPaymentOrder.getId());

                SubjectChange studentLastChange = null;
                if (isRefundInstrumentFee || isRefundTeachingAssistantsFee) {
                    studentLastChange = subjectChangeDao.getStudentLastChange(userId, musicGroupId);
                }

                BigDecimal remitFee = studentPaymentOrder.getRemitFee() == null ? BigDecimal.ZERO : studentPaymentOrder.getRemitFee();
                for (StudentPaymentOrderDetail detail : orderDetailList) {
                    if (remitFee.compareTo(detail.getPrice()) >= 0) {
                        remitFee = remitFee.subtract(detail.getPrice());
                        detail.setPrice(BigDecimal.ZERO);
                    } else {
                        detail.setPrice(detail.getPrice().subtract(remitFee));
                        remitFee = BigDecimal.ZERO;
                    }

                    if (isRefundInstrumentFee && studentLastChange == null) {
                        // 退乐器费用
                        if (detail.getType() == OrderDetailTypeEnum.MUSICAL) {
                            amount = amount.add(detail.getPrice());
                        }

                    }
                    if (isRefundTeachingAssistantsFee && studentLastChange == null) {
                        // 退教辅费用
                        if (detail.getType() == OrderDetailTypeEnum.ACCESSORIES || detail.getType() == OrderDetailTypeEnum.TEACHING) {
                            amount = amount.add(detail.getPrice());
                        }
                    }
                }
                if (studentLastChange != null) {
                    amount = amount.add(studentLastChange.getChangeMusicalPrice()).add(studentLastChange.getChangeAccessoriesPrice());
                }
            }

            
            if (amount.doubleValue() > 0) {
                // 增加交易流水
                sysUserCashAccountDetailService.addCashAccountDetail(userId, amount, SysUserCashAccountDetailService.MUSIC_GROUP + musicGroupId, "",
                        PlatformCashAccountDetailTypeEnum.REFUNDS, null, SUCCESS, "退出乐团", null);
            }
        }
        return true;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public boolean directQuitMusicGroup(String musicGroupId, Integer userId, String reason, boolean isRefundCourseFee, boolean isRefundInstrumentFee,
                                        boolean isRefundTeachingAssistantsFee) {

        SysUser sysUser = sysUserFeignService.queryUserById(userId);
        if (sysUser == null) {
            throw new BizException("获取用户信息失败");
        }
        MusicGroup musicGroup = musicGroupDao.get(musicGroupId);
        if (musicGroup == null) {
            throw new BizException("乐团不存在");
        }
        if (musicGroup.getStatus() == MusicGroupStatusEnum.CANCELED || musicGroup.getStatus() == MusicGroupStatusEnum.PAUSE) {
            throw new BizException("退团失败，乐团状态[已取消]或[已暂停]");
        }

		// 有进行中的课程不能退团
		List<CourseSchedule> courseScheduleList = courseScheduleDao.findMusicGroupCourseSchedulesWithStudent(musicGroupId, GroupType.MUSIC.getCode(),
				"UNDERWAY", userId);
		if (courseScheduleList != null && courseScheduleList.size() > 0) {
			throw new BizException("退团失败，存在[进行中]的课程");
		}

        courseScheduleStudentPaymentService.updateCourseActualPrice(Arrays.asList(musicGroupId), Arrays.asList(userId), GroupType.MUSIC);

        // 判断乐器是否是租赁
        StudentRegistration studentRegistration = studentRegistrationDao.queryByUserIdAndMusicGroupId(userId, musicGroupId);
        if (studentRegistration == null) {
            throw new BizException("用户注册信息不存在");
		}

        Date date = new Date();

        MusicGroupQuit musicGroupQuit = new MusicGroupQuit();
        musicGroupQuit.setCreateTime(date);
        musicGroupQuit.setJoinDate(studentRegistration.getCreateTime());
        musicGroupQuit.setMusicGroupId(musicGroupId);
        musicGroupQuit.setUserId(sysUser.getId());
        musicGroupQuit.setStatus(ApprovalStatus.APPROVED);
        musicGroupQuit.setReason(reason);
        musicGroupQuit.setQuitDate(date);

        musicGroupQuitDao.insert(musicGroupQuit);

        List<Integer> classGroupIdList = classGroupStudentMapperDao.queryClassGroupIdList(musicGroupId, userId, GroupType.MUSIC);
        for (Integer classGroupId : classGroupIdList) {
            ClassGroup classGroup = classGroupService.get(classGroupId);
            if (classGroup.getType().equals(ClassGroupTypeEnum.MUSIC_NETWORK)) {
                classGroupService.delSingle(classGroupId);
            } else {
                classGroupStudentMapperService.delClassGroupStudent(userId, classGroupId, true);
            }
        }

        //删除续费周期
        musicGroupStudentFeeDao.deleteByUserIdAndMusicGroupId(userId, musicGroupId);

        BigDecimal surplusCourseFee = studentRegistration.getSurplusCourseFee();
        StudentMusicGroupStatusEnum currentStudentMusicGroupStatus = studentRegistration.getMusicGroupStatus();
        // 退团
        studentRegistration.setMusicGroupStatus(StudentMusicGroupStatusEnum.QUIT);
        studentRegistration.setSurplusCourseFee(BigDecimal.ZERO);
        studentRegistration.setUpdateTime(date);

        studentRegistrationDao.update(studentRegistration);

        //更新服务指标、运营指标
        int remainCourseNum = courseScheduleStudentPaymentDao.countStudentNotStartCourseNumWithCourseType(userId, null);
        if (remainCourseNum == 0) {
            Student student = studentDao.get(userId);
            if (student == null) {
                throw new BizException("学生信息查询失败");
            }
            student.setServiceTag(0);
            student.setOperatingTag(0);
            student.setOperatingTempTag(0);
            student.setUpdateTime(date);
            studentDao.update(student);
        }

        //删除进行中加学生，且在审批中或拒绝的缴费
        List<Long> paymentCalenderIdList = musicGroupPaymentCalenderDao.findStudentNoPaymentCalender(userId, musicGroupId);
        if(paymentCalenderIdList != null && paymentCalenderIdList.size() > 0){
        	musicGroupPaymentCalenderDao.delByIds(paymentCalenderIdList);
        }
        
        //查询未交费的项目
        List<MusicGroupPaymentCalenderDetail> musicGroupPaymentCalenderDetailList = musicGroupPaymentCalenderDetailDao.queryNotPaymentStudentByUserIdAndMusicGroupId(userId, musicGroupId);
        
		for (MusicGroupPaymentCalenderDetail mgpcd : musicGroupPaymentCalenderDetailList) {
			MusicGroupPaymentCalender mgpc = musicGroupPaymentCalenderDao.get(mgpcd.getMusicGroupPaymentCalenderId());
			if (mgpc != null) {
				if (mgpc.getPaymentType() == PaymentType.ADD_STUDENT) {
					musicGroupPaymentCalenderDao.delete(mgpc.getId());
				} else {
					// 缴费项目预计人数减一
					mgpc.setExpectNum(mgpc.getExpectNum() - 1);
					mgpc.setUpdateTime(date);
					musicGroupPaymentCalenderDao.update(mgpc);
				}
			}
			musicGroupPaymentCalenderDetailDao.delete(mgpcd.getId());
		}
        //删除用户购买的课程记录
        musicGroupPaymentStudentCourseDetailDao.deleteByUserIdAndMusicGroupId(userId, musicGroupId);
        
        BigDecimal amount = new BigDecimal(0);

        // 判断乐器是否是租赁
        MusicGroupSubjectPlan musicGroupSubjectPlan = musicGroupSubjectPlanDao.getMusicOneSubjectClassPlan(musicGroupId, studentRegistration.getActualSubjectId());
        if (musicGroupSubjectPlan != null) {
            musicGroupSubjectPlan.setPaidStudentNum(musicGroupSubjectPlan.getPaidStudentNum() - 1);
            musicGroupSubjectPlan.setUpdateTime(date);
            musicGroupSubjectPlanDao.update(musicGroupSubjectPlan);
        }
        
        if(currentStudentMusicGroupStatus != StudentMusicGroupStatusEnum.NORMAL){
        	return true;
        }
        
        if (isRefundCourseFee) {
            // 退课程费用
            amount = amount.add(surplusCourseFee);
        }

        StudentPaymentOrder studentPaymentOrder = studentPaymentOrderService.findMusicGroupApplyOrderByStatus(userId, musicGroupId, SUCCESS);

        if (studentPaymentOrder != null) {
        	List<StudentPaymentOrderDetail> orderDetailList = studentPaymentOrderDetailDao.findApplyOrderGoods(studentPaymentOrder.getId());

            SubjectChange studentLastChange = null;
            if (isRefundInstrumentFee || isRefundTeachingAssistantsFee) {
                studentLastChange = subjectChangeDao.getStudentLastChange(userId, musicGroupId);
            }

            BigDecimal remitFee = studentPaymentOrder.getRemitFee() == null ? BigDecimal.ZERO : studentPaymentOrder.getRemitFee();

            for (StudentPaymentOrderDetail detail : orderDetailList) {
                if (remitFee.compareTo(detail.getPrice()) >= 0) {
                    remitFee = remitFee.subtract(detail.getPrice());
                    detail.setPrice(BigDecimal.ZERO);
                } else {
                    detail.setPrice(detail.getPrice().subtract(remitFee));
                    remitFee = BigDecimal.ZERO;
                }
                if (isRefundInstrumentFee && studentLastChange == null) {
                    // 退乐器费用
                    if (detail.getType() == OrderDetailTypeEnum.MUSICAL) {
                        amount = amount.add(detail.getPrice());
                    }

                }
                if (isRefundTeachingAssistantsFee && studentLastChange == null) {
                    // 退教辅费用
                    if (detail.getType() == OrderDetailTypeEnum.ACCESSORIES || detail.getType() == OrderDetailTypeEnum.TEACHING) {
                        amount = amount.add(detail.getPrice());
                    }
                }
            }
            if (studentLastChange != null) {
                amount = amount.add(studentLastChange.getChangeMusicalPrice()).add(studentLastChange.getChangeAccessoriesPrice());
            }
        }

        
        if (amount.doubleValue() > 0) {
            // 增加交易流水
            sysUserCashAccountDetailService.addCashAccountDetail(userId, amount, SysUserCashAccountDetailService.MUSIC_GROUP + musicGroupId, "",
                    PlatformCashAccountDetailTypeEnum.REFUNDS, null, SUCCESS, "退出乐团", null);
        }

        return true;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public Map renew(Long calenderId, Integer userId, boolean isUseBalancePayment) throws Exception {
        MusicGroupPaymentCalender calender = musicGroupPaymentCalenderDao.get(calenderId);
        if (calender == null) {
            throw new BizException("缴费项目不存在");
        }
        StudentRegistration studentRegistration = studentRegistrationService.queryByUserIdAndMusicGroupId(userId, calender.getMusicGroupId());
        if (studentRegistration == null) {
            throw new BizException("请走报名缴费流程");
        }
        Integer organId = studentRegistration.getOrganId();
        MusicGroupPaymentCalenderDetail calenderDetail = musicGroupPaymentCalenderDetailDao.findByCalenderIdAndUserId(calenderId, userId);
        //关闭之前的订单
        if (calenderDetail.getPaymentOrderId() != null) {
            StudentPaymentOrder oldStudentPaymentOrder = studentPaymentOrderDao.get(calenderDetail.getPaymentOrderId());
            if (oldStudentPaymentOrder != null) {
                if (oldStudentPaymentOrder.getStatus() == SUCCESS) {
                    throw new BizException("您已支付请勿重复提交");
                }
                oldStudentPaymentOrder.setStatus(CLOSE);
                studentPaymentOrderService.update(oldStudentPaymentOrder);
                if (oldStudentPaymentOrder.getBalancePaymentAmount() != null && oldStudentPaymentOrder.getBalancePaymentAmount().compareTo(BigDecimal.ZERO) > 0) {
                    sysUserCashAccountService.updateBalance(oldStudentPaymentOrder.getUserId(), oldStudentPaymentOrder.getBalancePaymentAmount(), PlatformCashAccountDetailTypeEnum.REFUNDS, "关闭订单");
                }
            }
        }
        String orderNo = idGeneratorService.generatorId("payment") + "";

        BigDecimal amount = calenderDetail.getExpectAmount();

        Date date = new Date();
        StudentPaymentOrder studentPaymentOrder = new StudentPaymentOrder();
        studentPaymentOrder.setGroupType(GroupType.MUSIC);
        studentPaymentOrder.setUserId(userId);
        studentPaymentOrder.setOrderNo(orderNo);
        studentPaymentOrder.setType(OrderTypeEnum.RENEW);
        studentPaymentOrder.setExpectAmount(amount);
        studentPaymentOrder.setActualAmount(amount);
        studentPaymentOrder.setStatus(DealStatusEnum.ING);
        studentPaymentOrder.setMusicGroupId(calender.getMusicGroupId());
        studentPaymentOrder.setCreateTime(date);
        studentPaymentOrder.setUpdateTime(date);
        studentPaymentOrder.setVersion(0);
        studentPaymentOrderService.insert(studentPaymentOrder);
        calenderDetail.setPaymentOrderId(studentPaymentOrder.getId());
        musicGroupPaymentCalenderDetailDao.update(calenderDetail);

        /*ArrayList<StudentPaymentOrderDetail> studentPaymentOrderDetailList = new ArrayList<>();
        StudentPaymentOrderDetail studentPaymentOrderDetail = new StudentPaymentOrderDetail();
        studentPaymentOrderDetail.setType(OrderDetailTypeEnum.COURSE);
        studentPaymentOrderDetail.setPrice(amount);
        studentPaymentOrderDetail.setCreateTime(date);
        studentPaymentOrderDetail.setUpdateTime(date);
        studentPaymentOrderDetail.setPaymentOrderId(studentPaymentOrder.getId());
        studentPaymentOrderDetailList.add(studentPaymentOrderDetail);

        studentPaymentOrderDetailService.batchAdd(studentPaymentOrderDetailList);*/

        BigDecimal balance = BigDecimal.ZERO;
        if (isUseBalancePayment || amount.doubleValue() == 0) {
            SysUserCashAccount userCashAccount = sysUserCashAccountService.getLocked(userId);
            if (userCashAccount == null) {
                throw new BizException("用户账户找不到");
            }
            studentPaymentOrder.setPaymentChannel("BALANCE");
            if (userCashAccount.getBalance().subtract(amount).doubleValue() >= 0) {
                // 更新订单信息
                balance = amount;
                studentPaymentOrder.setActualAmount(BigDecimal.ZERO);
                studentPaymentOrder.setBalancePaymentAmount(amount);
                studentPaymentOrder.setActualAmount(new BigDecimal(0));
                studentPaymentOrder.setUpdateTime(date);
                studentPaymentOrder.setOrganId(organId);
                studentPaymentOrder.setRoutingOrganId(organId);
                studentPaymentOrderService.update(studentPaymentOrder);
                sysUserCashAccountService.updateBalance(userId, amount.negate(), PlatformCashAccountDetailTypeEnum.PAY_FEE, "乐团续费");
                amount = BigDecimal.ZERO;
            } else {
                if (userCashAccount.getBalance().doubleValue() > 0) {
                    balance = userCashAccount.getBalance();
                    sysUserCashAccountService.updateBalance(userId, balance.negate(), PlatformCashAccountDetailTypeEnum.PAY_FEE, "乐团续费");
                    amount = amount.subtract(userCashAccount.getBalance());
                    studentPaymentOrder.setBalancePaymentAmount(userCashAccount.getBalance());
                    studentPaymentOrder.setActualAmount(studentPaymentOrder.getActualAmount().subtract(userCashAccount.getBalance()));
                } else {
                    studentPaymentOrder.setBalancePaymentAmount(new BigDecimal(0));
                }
            }
        }
        String baseApiUrl = sysConfigDao.findConfigValue("base_api_url");

        if (amount.compareTo(BigDecimal.ZERO) == 0) {
            studentPaymentRouteOrderService.addRouteOrder(orderNo, organId, balance);
            Map<String, String> notifyMap = new HashMap<>(4);
            notifyMap.put("tradeState", "1");
            notifyMap.put("merOrderNo", studentPaymentOrder.getOrderNo());
            notifyMap.put("channelType", "");
            notifyMap.put("orderNo", "");
            studentPaymentOrderService.updateOrder(notifyMap);
            return notifyMap;
        }

        Map<String, Object> payMap = payService.getPayMap(
                amount,
                balance,
                orderNo,
                baseApiUrl + "/api-student/studentOrder/notify",
                baseApiUrl + "/api-student/studentOrder/paymentResult?orderNo=" + studentPaymentOrder.getOrderNo(),
                "续费",
                "乐团续费",
                organId,
                "renew"
        );

        studentPaymentOrder.setActualAmount(amount);
        studentPaymentOrder.setOrganId(organId);
        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)
    public boolean renewForCallback(StudentPaymentOrder studentPaymentOrder) throws IOException {

        int updateNum = studentPaymentOrderService.update(studentPaymentOrder);
        if (updateNum <= 0) {
            throw new BizException("订单更新失败");
        }
        Integer userId = studentPaymentOrder.getUserId();
        String musicGroupId = studentPaymentOrder.getMusicGroupId();

        Date date = new Date();
        StudentRegistration studentRegistration = studentRegistrationDao.queryByUserIdAndMusicGroupId(userId, musicGroupId);
        Map<Integer, String> yimei = new HashMap<>(1);
        Map<Integer, String> push = new HashMap<>(1);
        push.put(userId, userId.toString());
        yimei.put(userId, studentRegistration.getParentsPhone());
        if (studentPaymentOrder.getStatus() == SUCCESS) {
            //当前乐团报名是否赠送乐团网管课
            MusicGroupPaymentCalenderDetail calenderDetail = musicGroupPaymentCalenderDetailDao.findByOrderId(studentPaymentOrder.getId());
            MusicGroupStudentFee musicGroupStudentFee = musicGroupPaymentCalenderService.updateCalender(calenderDetail.getId(), studentRegistration.getUserId());
            if (musicGroupStudentFee != null) {
                musicGroupStudentFee.setUpdateTime(date);
                musicGroupStudentFee.setLatestPaidTime(date);
                musicGroupStudentFee.setPaymentStatus(PaymentStatus.PAID_COMPLETED);
                musicGroupStudentFee.setTemporaryCourseFee(new BigDecimal(0));
                musicGroupStudentFeeDao.update(musicGroupStudentFee);
            }
            //如果是进行中加学员
            MusicGroupPaymentCalender paymentCalender = musicGroupPaymentCalenderDao.get(calenderDetail.getMusicGroupPaymentCalenderId());
            if(paymentCalender.getPaymentType() == MusicGroupPaymentCalender.PaymentType.ADD_STUDENT){
                studentRegistration.setPaymentStatus(YES);
                studentRegistration.setMusicGroupStatus(StudentMusicGroupStatusEnum.NORMAL);
                studentRegistrationDao.update(studentRegistration);
            }
            /*if (musicGroupPaymentCalender.getType().equals(MusicGroupPaymentCalender.FeeType.ONLINE)) {
                Integer getRemainNetworkClassTimes = musicGroupStudentFee.getRemainNetworkClassTimes() == null ? 0 : musicGroupStudentFee.getRemainNetworkClassTimes();
                musicGroupStudentFee.setRemainNetworkClassTimes(getRemainNetworkClassTimes + 1);
            }*/
//            musicGroupStudentFee.setNextPaymentDate(musicGroupPaymentCalenderService.getNextPaymentDate(musicGroupId, musicGroupStudentFee.getNextPaymentDate(), musicGroupStudentFee));


            //插入交易明细
            SysUserCashAccount cashAccount = sysUserCashAccountService.get(userId);
            BigDecimal amount = studentPaymentOrder.getActualAmount();
            //充值
            SysUserCashAccountDetail rechargeDetail = new SysUserCashAccountDetail();
            rechargeDetail.setAmount(amount);
            rechargeDetail.setBalance(cashAccount.getBalance().add(amount));
            rechargeDetail.setComment("缴费前充值");
            rechargeDetail.setCreateTime(date);
            rechargeDetail.setStatus(SUCCESS);
            rechargeDetail.setTransNo(studentPaymentOrder.getTransNo());
            rechargeDetail.setType(PlatformCashAccountDetailTypeEnum.RECHARGE);
            rechargeDetail.setUpdateTime(date);
            rechargeDetail.setUserId(userId);
            rechargeDetail.setChannel(studentPaymentOrder.getPaymentChannel());
            rechargeDetail.setComAmount(studentPaymentOrder.getComAmount());
            rechargeDetail.setPerAmount(studentPaymentOrder.getPerAmount());
            sysUserCashAccountDetailService.insert(rechargeDetail);

            List<StudentPaymentOrderDetail> paymentOrderDetails = new ArrayList<>();
            List<MusicGroupPaymentCalenderCourseSettings> courseSettings = musicGroupPaymentCalenderCourseSettingsDao.queryCalenderCourseSettings(calenderDetail.getMusicGroupPaymentCalenderId());
            //跨团合班没有settings
            if(courseSettings.size() == 0){
                List<MusicGroupPaymentCalenderStudentDetail> studentDetails = musicGroupPaymentCalenderStudentDetailDao.findByBatchNoAndUserId(paymentCalender.getBatchNo(), userId);
                for (MusicGroupPaymentCalenderStudentDetail studentDetail : studentDetails) {
                    StudentPaymentOrderDetail studentPaymentOrderDetail = new StudentPaymentOrderDetail();
                    studentPaymentOrderDetail.setType(OrderDetailTypeEnum.valueOf(studentDetail.getCourseType()));
                    studentPaymentOrderDetail.setPrice(studentDetail.getCourseCurrentPrice());
                    studentPaymentOrderDetail.setCreateTime(date);
                    studentPaymentOrderDetail.setUpdateTime(date);
                    studentPaymentOrderDetail.setPaymentOrderId(studentPaymentOrder.getId());
                    paymentOrderDetails.add(studentPaymentOrderDetail);
                }
            }else {
                courseSettings.forEach(e -> {
                    StudentPaymentOrderDetail studentPaymentOrderDetail = new StudentPaymentOrderDetail();
                    studentPaymentOrderDetail.setType(OrderDetailTypeEnum.valueOf(e.getCourseType().getCode()));
                    studentPaymentOrderDetail.setPrice(e.getCourseCurrentPrice());
                    studentPaymentOrderDetail.setCreateTime(date);
                    studentPaymentOrderDetail.setUpdateTime(date);
                    studentPaymentOrderDetail.setPaymentOrderId(studentPaymentOrder.getId());
                    paymentOrderDetails.add(studentPaymentOrderDetail);
                });
            }
            studentPaymentOrderDetailService.batchAdd(paymentOrderDetails);

            //缴费
            SysUserCashAccountDetail paymentDetail = new SysUserCashAccountDetail();
            paymentDetail.setAmount(amount.negate());
            paymentDetail.setBalance(cashAccount.getBalance());
            paymentDetail.setComment("续费");
            paymentDetail.setCreateTime(date);
            paymentDetail.setStatus(SUCCESS);
            paymentDetail.setTransNo(studentPaymentOrder.getTransNo());
            paymentDetail.setType(PlatformCashAccountDetailTypeEnum.PAY_FEE);
            paymentDetail.setUpdateTime(date);
            paymentDetail.setUserId(userId);
            paymentDetail.setChannel(studentPaymentOrder.getPaymentChannel());
            sysUserCashAccountDetailService.insert(paymentDetail);
            MusicGroup musicGroup = musicGroupDao.get(musicGroupId);
            if (musicGroup.getOwnershipType() != null && musicGroup.getOwnershipType() == CooperationOrgan.OwnershipType.OWN) {
                // 发送续费结果通知
                sysMessageService.batchSendMessage(MessageSender.JIGUANG, MessageTypeEnum.STUDENT_SMS_MUSIC_GROUP_RENEW_SUCCESS, push, null, 0, "1", "STUDENT",
                        studentRegistration.getName(), studentPaymentOrder.getActualAmount());
                sysMessageService.batchSendMessage(MessageSender.AWSMS, MessageTypeEnum.STUDENT_SMS_MUSIC_GROUP_RENEW_SUCCESS, yimei, null, 0, "1", "",
                        studentRegistration.getName(), studentPaymentOrder.getActualAmount());
            }
            studentRegistrationService.updateUserSurplusCourseFee(userId, musicGroupId, studentPaymentOrder.getExpectAmount(), "乐团续费", userId);
            return true;
        } else {
            if (studentPaymentOrder.getBalancePaymentAmount() != null && studentPaymentOrder.getBalancePaymentAmount().doubleValue() > 0) {
                sysUserCashAccountService.updateBalance(userId, studentPaymentOrder.getBalancePaymentAmount(), PlatformCashAccountDetailTypeEnum.REFUNDS,
                        "乐团续费失败");
            }
        }
        MusicGroup musicGroup = musicGroupDao.get(musicGroupId);
        if (musicGroup.getOwnershipType() != null && musicGroup.getOwnershipType() == CooperationOrgan.OwnershipType.OWN) {
            if (studentPaymentOrder.getStatus() == CLOSE || studentPaymentOrder.getStatus() == DealStatusEnum.FAILED) {
                String baseUrl = sysConfigDao.findConfigValue(SysConfigService.BASE_API_URL);
                String memo = baseUrl + "/#/renew?musicGroupId=" + musicGroupId;
                //4?http://mstudev.dayaedu.com/#/renew?musicGroupId=" +musicGroupId
                sysMessageService.batchSendMessage(MessageSender.JIGUANG, MessageTypeEnum.STUDENT_PUSH_MUSIC_GROUP_RENEW_FAILED, push, null, 0, "4?" + memo, "STUDENT",
                        HttpUtil.getSortUrl(memo));
                return false;
            }
        }
        return false;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public boolean updateTeacherCoursesSalary(Long courseScheduleId, Integer teacherId, BigDecimal salary, BigDecimal subsidy, String scope) {
        SysUser sysUser = sysUserFeignService.queryUserInfo();
        if (sysUser == null) {
            throw new BizException("获取用户信息失败");
        }
        CourseSchedule courseSchedule = courseScheduleDao.get(courseScheduleId);
        if (courseSchedule == null) {
            throw new BizException("课程信息不存在");
        }

        if ("all".equals(scope)) {
            Integer classGrpupId = courseSchedule.getClassGroupId();
            String startDateTime = sdf_ymd.format(courseSchedule.getClassDate()) + " " + sdf_hms.format(courseSchedule.getStartClassTime());
            // 未结算的课酬都修改
            courseScheduleTeacherSalaryDao.batchUpdateWages(classGrpupId, teacherId, salary, subsidy, startDateTime);
        } else {
            CourseScheduleTeacherSalary courseScheduleTeacherSalary = courseScheduleTeacherSalaryDao.queryByCourseScheduleIdAndUserId(courseScheduleId,
                    teacherId);
            if (courseScheduleTeacherSalary == null) {
                throw new BizException("课程结算信息不存在");
            }
            // 判断当前课程是否结算
            if (courseScheduleTeacherSalary.getSettlementTime() != null) {
                throw new BizException("课程已结算");
            }
            courseScheduleTeacherSalary.setExpectSalary(salary);
            courseScheduleTeacherSalary.setSubsidy(subsidy);
            courseScheduleTeacherSalary.setUpdateTime(new Date());
            courseScheduleTeacherSalaryDao.update(courseScheduleTeacherSalary);
        }
        return true;
    }

    @Override
    public PageInfo<MusicGroup> queryMusicGroupPage(MusicGroupQueryInfo queryInfo) {
        SysUser sysUser = sysUserFeignService.queryUserInfo();
        if (sysUser == null) {
            throw new BizException("获取用户信息失败");
        }
        //获取用户权限列表
        List<Integer> roles = employeeDao.queryUserRole(sysUser.getId());
        PageInfo<MusicGroup> musicGroupPageInfo;
        if (roles != null && roles.size() == 1 && roles.contains(SysUserRole.EDUCATIONAL_TEACHER)) {
            //只有教务老师权限
            /*String musicGroupIds = musicGroupDao.queryEducationalMusicGroupId(sysUser.getId());
            queryInfo.setMusicGroupId(musicGroupIds);*/
            musicGroupPageInfo = queryPage(queryInfo);
        } else {
            musicGroupPageInfo = queryPage(queryInfo);
        }
        List<MusicGroup> musicGroupList = musicGroupPageInfo.getRows();

        if (musicGroupList == null || musicGroupList.size() == 0) {
            return musicGroupPageInfo;
        }
        // 获取学校编号列表
//        Set<Integer> schoolIds = musicGroupList.stream().map(e -> e.getSchoolId()).collect(Collectors.toSet());
//        List<Map<Integer, String>> schoolNames = schoolDao.queryNameByIds(StringUtils.join(schoolIds,","));
        // 获取相关学校名称map
//        Map<Integer, String> schoolNameMap = MapUtil.convertMybatisMap(schoolNames);

        // 获取教务老师编号列表
        Set<Integer> educationalTeacherIds = musicGroupList.stream().map(e -> e.getEducationalTeacherId()).collect(Collectors.toSet());
        // 获取相关老师的名字
        List<Map<Integer, String>> educationalTeacherNames = teacherDao.queryNameByIds(StringUtils.join(educationalTeacherIds, ","));
        Map<Integer, String> educationalTeacherNameMap = MapUtil.convertMybatisMap(educationalTeacherNames);

        // 获取运营主管编号列表
        Set<Integer> teamTeacherIds = musicGroupList.stream().map(e -> e.getTeamTeacherId()).collect(Collectors.toSet());
        List<Map<Integer, String>> teamTeacherNames = teacherDao.queryNameByIds(StringUtils.join(teamTeacherIds, ","));
        Map<Integer, String> teamTeacherNameMap = MapUtil.convertMybatisMap(teamTeacherNames);

        // 获取乐团编号列表
        Set<String> musicGroupIds = musicGroupList.stream().map(e -> e.getId()).collect(Collectors.toSet());
        // 统计乐团在读人数
//        List<Map<String, Long>> payNums = musicGroupDao.countPayNum(StringUtils.join(musicGroupIds,","));
//        Map<String, String> payNumMap = MapUtil.convertMybatisMap(payNums);

        Map<String, Integer> payNumMap = JSONObject.parseObject(JSONObject.toJSONString(MapUtil.convertIntegerMap(studentRegistrationDao.countNormalNum(StringUtils.join(musicGroupIds, ",")))), HashMap.class);

        // 获取收费类型编号列表
        Set<Integer> chargeTypeIds = musicGroupList.stream().map(e -> e.getChargeTypeId()).collect(Collectors.toSet());
        if (chargeTypeIds == null) {
            chargeTypeIds = new HashSet<>();
        }
        List<Map<Integer, String>> chargeTypeNames = chargeTypeDao.queryNameByIds(StringUtils.join(chargeTypeIds, ","));
        Map<Integer, String> chargeTypeNameMap = MapUtil.convertMybatisMap(chargeTypeNames);

        //获取教学点编号
        Map<Integer, String> cooperationOrganNames = MapUtil.convertMybatisMap(cooperationOrganDao.queryNameByIds(StringUtils.join(musicGroupList.stream().map(MusicGroup::getCooperationOrganId).collect(Collectors.toSet()), ",")));

//        Set<Integer> organIds = musicGroupList.stream().map(e -> e.getOrganId()).collect(Collectors.toSet());
//        Map<Integer,String> organNames = MapUtil.convertMybatisMap(organizationDao.findOrganNameMap(StringUtils.join(organIds,",")));

        List<MusicGroupPurchaseList> musicGroupPurchaseListCount = musicGroupPurchaseListDao.getCount(musicGroupIds);
        Map<String, Integer> purchaseListMap = musicGroupPurchaseListCount.stream().collect(Collectors.toMap(MusicGroupPurchaseList::getMusicGroupId, MusicGroupPurchaseList::getPurchaseNum));

        //获取分部名称map
        musicGroupList.forEach(e -> {
//            e.setSchoolName(schoolNameMap.get(e.getSchoolId()));
//            e.setOrganName(organNames.get(e.getOrganId()));
            e.setCooperationOrganName(cooperationOrganNames.get(e.getCooperationOrganId()));
            e.setEducationalTeacherName(educationalTeacherNameMap.get(e.getEducationalTeacherId()));
            e.setTeamTeacherName(teamTeacherNameMap.get(e.getTeamTeacherId()));
            e.setPayNum(payNumMap.get(e.getId()) == null ? 0 : payNumMap.get(e.getId()));
            e.setChargeTypeName(chargeTypeNameMap.get(e.getChargeTypeId()));
            e.setHasVerifyMusicalList(purchaseListMap.get(e.getId()) != null);
        });
        return musicGroupPageInfo;
    }

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

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

    private void updateTeamTeacher(MusicGroup oldMusicGroup, MusicGroup newMusicGroup) {
        //获取当前乐团所有班级
        List<ClassGroup> classGroups = classGroupDao.findClassGroups(newMusicGroup.getId());
        if (classGroups == null || classGroups.size() == 0) {
            return;
        }
        Integer teamTeacherId = newMusicGroup.getTeamTeacherId();
        Integer educationalTeacherId = newMusicGroup.getEducationalTeacherId();
        
        Integer oldDirectorUserId = oldMusicGroup.getDirectorUserId();
        if (oldDirectorUserId == null) {
            oldDirectorUserId = teamTeacherId;
        }
        Integer directorUserId = newMusicGroup.getDirectorUserId();
        if (directorUserId == null) {
            directorUserId = teamTeacherId;
        }

        List<Integer> quitUserIdList = new ArrayList<Integer>();
        quitUserIdList.add(oldMusicGroup.getTeamTeacherId());
        quitUserIdList.add(oldMusicGroup.getEducationalTeacherId());
        quitUserIdList.add(oldDirectorUserId);

        Map<Integer,String> userRoleMap = new HashMap<Integer, String>();
        userRoleMap.put(directorUserId, "乐队指导");
        userRoleMap.put(educationalTeacherId, "乐团主管");
        userRoleMap.put(teamTeacherId, "运营主管");
        
        classGroups.forEach(e -> {
        	imGroupMemberService.quit(e.getId().longValue(), quitUserIdList);
        	imGroupMemberService.join(e.getId().longValue(), userRoleMap);
        });
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateBaseInfo(SubFeeSettingDto subFeeSettingDto) throws Exception {
        SysUser sysUser = sysUserFeignService.queryUserInfo();
        if (sysUser == null) {
            throw new BizException("用户信息获取失败");
        }
        String musicGroupId = subFeeSettingDto.getMusicGroup().getId();
        MusicGroup group = musicGroupDao.getLocked(musicGroupId);
        if (group == null) {
            throw new BizException("乐团信息不存在");
        }

        if (!(group.getStatus() == MusicGroupStatusEnum.DRAFT || group.getStatus() == MusicGroupStatusEnum.AUDIT_FAILED
                || group.getStatus() == MusicGroupStatusEnum.PROGRESS)) {
            throw new BizException("当前乐团状态不能修改基本信息");
        }

        MusicGroup musicGroup = subFeeSettingDto.getMusicGroup();
        musicGroup.setStatus(group.getStatus());
        if (!group.getSchoolId().equals(musicGroup.getSchoolId())) {
            //如果已生成课表，那么修改未上课时教学点
            courseScheduleDao.updateCourseScheduleSchool("MUSIC", musicGroupId, musicGroup.getSchoolId());
        }
        if(group.getStatus() == MusicGroupStatusEnum.PROGRESS){
            updateTeamTeacher(group, musicGroup);
        }

        Date date = new Date();
        //缴费方式不同
        if ((group.getStatus().equals(MusicGroupStatusEnum.AUDIT_FAILED) || group.getStatus().equals(MusicGroupStatusEnum.DRAFT))
                && !group.getChargeTypeId().equals(musicGroup.getChargeTypeId())) {
            //删除原有的声部商品组合
            musicGroupSubjectGoodsGroupDao.delByMusicGroupId(musicGroupId);
            //删除原有的缴费项目
            MusicGroupPaymentCalender regCalender = musicGroupPaymentCalenderDao.findByMusicGroupRegCalender(musicGroupId);
            if (regCalender != null) {
                musicGroupPaymentCalenderDao.delByGroupId(musicGroupId);

                List<Long> calenderIds = new ArrayList<Long>();
                calenderIds.add(regCalender.getId());
                musicGroupPaymentCalenderCourseSettingsDao.deleteByMusicGroupPaymentCalenderId(calenderIds);
            }
        }
        musicGroup.setUpdateTime(date);
        musicGroupDao.update(musicGroup);
        // 删除乐团付费主体列表
        musicGroupPaymentEntitiesDao.delByGroupId(musicGroupId);
        //批量新增
        if (subFeeSettingDto.getMusicGroupPaymentEntities() != null && subFeeSettingDto.getMusicGroupPaymentEntities().size() > 0) {
            musicGroupPaymentEntitiesDao.batchAdd(subFeeSettingDto.getMusicGroupPaymentEntities(), musicGroupId);
        }
        if(group.getStatus() == MusicGroupStatusEnum.PROGRESS){
            imUserFriendService.refreshGroupImUserFriend(musicGroupId,GroupType.MUSIC);
        }
        //记录操作日志
        musicGroupBuildLogDao.insert(new MusicGroupBuildLog(musicGroupId, "修改乐团基本信息数据", sysUser.getId(), JSONObject.toJSONString(subFeeSettingDto)));
    }

    @Override
    public SubFeeSettingDto findMusicGroupBasicInfo(String musicGroupId) {
        SubFeeSettingDto subFeeSettingDto = new SubFeeSettingDto();
        //获取乐团信息
        MusicGroup musicGroup = musicGroupDao.get(musicGroupId);
        ChargeType chargeType = chargeTypeDao.get(musicGroup.getChargeTypeId());
        musicGroup.setChargeTypeName(chargeType.getName());
        MusicGroupPaymentCalender regCalender = musicGroupPaymentCalenderService.findByMusicGroupRegCalender(musicGroup.getId());
        if (regCalender != null && regCalender.getPayUserType().equals(MusicGroupPaymentCalender.PayUserType.STUDENT)) {
            musicGroup.setPaymentExpireDate(regCalender.getDeadlinePaymentDate());
        }
        subFeeSettingDto.setMusicGroup(musicGroup);
        //获取付费主体
        subFeeSettingDto.setMusicGroupPaymentEntities(musicGroupPaymentEntitiesDao.findByMusicGroupId(musicGroupId));
        //获取缴费周期
        //List<Integer> paymentMonth = musicGroupPaymentCalenderDao.findByMusicGroupId(musicGroupId).stream().map(e -> e.getPaymentMonth()).collect(Collectors.toList());
        //subFeeSettingDto.setMonths(paymentMonth);
        return subFeeSettingDto;
    }

    @Override
    public SubFeeSettingDto findMusicGroupSubjectInfo(String musicGroupId) {
        SubFeeSettingDto subFeeSettingDto = new SubFeeSettingDto();
        //获取乐团声部规划列表
        subFeeSettingDto.setMusicGroupSubjectPlans(musicGroupSubjectPlanDao.getMusicSubjectClassPlan(musicGroupId));
        //获取乐团声部商品组
        subFeeSettingDto.setMusicGroupSubjectGoodsGroups(musicGroupSubjectGoodsGroupDao.findGoodsGroup(musicGroupId, null));
        return subFeeSettingDto;
    }

    @Override
    public List<MusicGroup> queryListByIds(Set<String> musicGroupIds) {
        return musicGroupDao.queryListByIds(StringUtils.join(musicGroupIds, ","));
    }

    @Override
    public List<CourseScheduleTeachersDto> queryTeacherSalary(Long courseScheduleId, Integer teacherId) {
        return courseScheduleTeacherSalaryDao.queryTeacherSalary(courseScheduleId, teacherId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public MusicGroup openPay(String musicGroupId, String expireDate) throws Exception {
        SysUser sysUser = sysUserFeignService.queryUserInfo();
        if (sysUser == null) {
            throw new BizException("用户信息获取失败");
        }
        MusicGroup musicGroup = saveLog(musicGroupId, MusicGroupStatusEnum.APPLY);
        //记录操作日志
        musicGroupBuildLogDao.insert(new MusicGroupBuildLog(musicGroupId, "开启缴费（报名中 -->  缴费中）", sysUser.getId(), ""));
        musicGroup.setPaymentExpireDate(DateUtil.toDate(expireDate));
        musicGroup.setStatus(MusicGroupStatusEnum.PAY);
        musicGroupDao.update(musicGroup);
        //所有人开启缴费
        studentRegistrationDao.musicGroupOpenPay(musicGroupId, PaymentStatusEnum.OPEN);
        MusicGroupPaymentCalender regCalender = musicGroupPaymentCalenderDao.findByMusicGroupRegCalender(musicGroupId);
        if (regCalender != null && regCalender.getPayUserType().equals(MusicGroupPaymentCalender.PayUserType.STUDENT)) {
            regCalender.setStatus(MusicGroupPaymentCalender.PaymentCalenderStatusEnum.OPEN);
            regCalender.setDeadlinePaymentDate(DateUtil.toDate(expireDate));
            regCalender.setUpdateTime(new Date());
            musicGroupPaymentCalenderDao.update(regCalender);
        }
        //三方乐团不发送缴费通知
        if (musicGroup.getOwnershipType() != null && musicGroup.getOwnershipType() == CooperationOrgan.OwnershipType.OWN) {
            //获取所有已报名学员列表
            HashMap<Integer, String> map = JSONObject.parseObject(JSONObject.toJSONString(MapUtil.convertMybatisMap(studentRegistrationDao.findMapByMusicGroupId(musicGroupId, 0))), HashMap.class);
            if (map != null && map.size() > 0) {
                String studentApplyUrl = sysConfigDao.findConfigValue(SysConfigService.STUDENT_APPLY_URL) + musicGroupId;
                String serverPhone = sysConfigDao.findConfigValue(SysConfigService.SERVER_PHONE);
                sysMessageService.batchSendMessage(MessageSender.AWSMS, MessageTypeEnum.SMS_PAYMENT_MESSAGE,
                        map, null, 0, "", "", musicGroup.getName(), studentApplyUrl, DateUtil.format(musicGroup.getPaymentExpireDate(), DateUtil.DATE_FORMAT_MIN), serverPhone);
            }
        }
        Set<Integer> roleIds = new HashSet<>(3);
        roleIds.add(SysUserRole.SECTION_MANAGER);
        roleIds.add(SysUserRole.EDUCATIONAL_TEACHER);
        roleIds.add(SysUserRole.OPERATION_EXECUTIVE);
        sysMessageService.batchSeoMessage(musicGroupDao.queryUserIdByRoleId(roleIds, musicGroup.getOrganId()), MessageTypeEnum.BACKSTAGE_ACTION_PAYMENT, "", musicGroup.getName());
        return musicGroup;
    }

    @Override
    public MusicGroup getMusicGroupDetail(String musicGroupId) {
        MusicGroup musicGroup = musicGroupDao.get(musicGroupId);
        musicGroup.setEducationalTeacherName(teacherDao.queryNameById(musicGroup.getEducationalTeacherId()));
        musicGroup.setTeamTeacherName(teacherDao.queryNameById(musicGroup.getTeamTeacherId()));
        musicGroup.setDirectorUserName(teacherDao.queryNameById(musicGroup.getDirectorUserId()));
        musicGroup.setRepairUserName(teacherDao.queryNameById(musicGroup.getRepairUserId()));
        Organization organization = organizationDao.get(musicGroup.getOrganId());
        if (organization != null) {
            musicGroup.setOrganName(organization.getName());
        }
        School school = schoolDao.get(musicGroup.getSchoolId());
        if (school != null) {
            musicGroup.setSchoolName(school.getName());
            musicGroup.setAddress(school.getAddress());
        }
        ChargeType chargeType = chargeTypeDao.get(musicGroup.getChargeTypeId());
        if (chargeType != null) {
            musicGroup.setChargeTypeName(chargeType.getName());
        }
        int highClassGroupNum = studentRegistrationDao.findMusicGroupStudentNum(musicGroupId) / 5;
        musicGroup.setImproventClassesNum(highClassGroupNum);
        return musicGroup;
    }

    @Override
    public List<ImGroupMember> queryMusicGroupTeachers(String musicGroupId) {
        MusicGroup musicGroup = musicGroupDao.get(musicGroupId);
        List<ImGroupMember> groupMembers = new ArrayList<>();
        Set teacherIds = new HashSet(4);
        teacherIds.add(musicGroup.getEducationalTeacherId());
        teacherIds.add(musicGroup.getTeamTeacherId());
        teacherIds.add(musicGroup.getOperatorUserId());
        teacherIds.add(musicGroup.getDirectorUserId());
        teacherIds.removeAll(Collections.singleton(null));
        for (Object teacherId : teacherIds) {
            groupMembers.add(new ImGroupMember(teacherId.toString()));
        }
        return groupMembers;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void musicGroupFound(String musicGroupId) throws Exception {
        SysUser sysUser = sysUserFeignService.queryUserInfo();
        if (sysUser == null) {
            throw new BizException("用户信息获取失败");
        }
        MusicGroup musicGroup = musicGroupDao.get(musicGroupId);
        if (musicGroup == null) {
            throw new BizException("乐团信息不存在");
        }
        //记录操作日志
        String event;
        if (musicGroup.getStatus() == MusicGroupStatusEnum.APPLY) {
            event = "确认开团(报名中 -> 筹备中)";
        } else if (musicGroup.getStatus() == MusicGroupStatusEnum.PAY) {
            event = "确认开团(缴费中 -> 筹备中)";
        } else {
            throw new BizException("当前乐团状态不支持此操作");
        }
        //报名未交费的学生，完成回访才能到下一步
        boolean hasNoVisit = false;
        StringBuilder tipsMsg = new StringBuilder();
        List<StudentRegistration> noPaymentStudents = studentRegistrationDao.getNoPaymentStudent(musicGroupId);
        if (noPaymentStudents.size() > 0) {
            tipsMsg.append("以下学生未完成回访，");
            List<Integer> studentIds = noPaymentStudents.stream().map(StudentRegistration::getUserId).collect(Collectors.toList());
            List<Integer> musicGroupVisitStudent = studentVisitDao.getMusicGroupVisitStudent(musicGroupId, studentIds);
            for (StudentRegistration noPaymentStudent : noPaymentStudents) {
                if (!musicGroupVisitStudent.contains(noPaymentStudent.getUserId())) {
                    hasNoVisit = true;
                    tipsMsg.append(noPaymentStudent.getName()).append("(").append(noPaymentStudent.getUserId()).append(")、");
                }
            }
        }
        if (hasNoVisit) {
            throw new BizException(tipsMsg.append("请完成回访").toString());
        }

        musicGroupBuildLogDao.insert(new MusicGroupBuildLog(musicGroupId, event, sysUser.getId(), ""));
        musicGroup.setStatus(MusicGroupStatusEnum.PREPARE);
        musicGroupDao.update(musicGroup);
//        if (musicGroup.getOwnershipType() != null && musicGroup.getOwnershipType() == CooperationOrgan.OwnershipType.OWN) {
//            //给家长发送乐团基础训练课短信
//            //获取所有乐团学员列表
//            List<StudentRegistration> students = studentRegistrationDao.queryStudentByMusicGroupId(musicGroupId);
//            if (students != null && students.size() > 0) {
//                // 获取所有家长电话
//                Set<String> parentsPhones = students.stream().map(StudentRegistration::getParentsPhone).collect(Collectors.toSet());
//                // 获取对应家长的用户编号
//                Map<Integer, String> userIds = MapUtil.convertMybatisMap(studentRegistrationDao.findParentId(StringUtils.join(parentsPhones, ",")));
//                userIds = JSONObject.parseObject(JSONObject.toJSONString(userIds), HashMap.class);
//                if (userIds != null && userIds.size() > 0) {
//                    String studentApplyUrl = sysConfigDao.findConfigValue(SysConfigService.STUDENT_APPLY_URL) + musicGroupId;
//                    String serverPhone = sysConfigDao.findConfigValue(SysConfigService.SERVER_PHONE);
//                    sysMessageService.batchSendMessage(MessageSender.YIMEI, MessageTypeEnum.SMS_BASICS_SKILL_APPLY_MESSAGE, userIds, null, 0, "", "", musicGroup.getName(), studentApplyUrl, serverPhone);
//                }
//            }
//        }
        Set<Integer> roleIds = new HashSet<>(1);
        roleIds.add(SysUserRole.SECTION_MANAGER);
        sysMessageService.batchSeoMessage(musicGroupDao.queryUserIdByRoleId(roleIds, musicGroup.getOrganId()), MessageTypeEnum.BACKSTAGE_MUSIC_GROUP_MARKING, "", musicGroup.getName());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<StudentRegistration> addMusicGroupRegs(String musicGroupId, List<Long> registerIds) {
        SysUser sysUser = sysUserFeignService.queryUserInfo();
        if (sysUser == null || sysUser.getId() == null) {
            throw new BizException("获取用户信息失败");
        }
        List<StudentRegistration> studentRegistrations = studentRegistrationDao.findStudentListByIdList(registerIds);
        List<StudentRegistration> oldRegs = studentRegistrationDao.getMusicGroupStu(musicGroupId);
        Map<Integer, List<StudentRegistration>> oldRegMap = oldRegs.stream().collect(Collectors.groupingBy(StudentRegistration::getUserId));
        //去掉相同的人
        List<StudentRegistration> newRegs = new ArrayList<>();
        Set<Integer> hasUsers = new HashSet<>();
        for (StudentRegistration studentRegistration : studentRegistrations) {
            if (oldRegMap.containsKey(studentRegistration.getUserId()) || hasUsers.contains(studentRegistration.getUserId())) {
                continue;
            }
            hasUsers.add(studentRegistration.getUserId());
            newRegs.add(studentRegistration);
        }
        if(registerIds.size() >0 && newRegs.size()<=0){
            throw new BizException("添加的学员,乐团已存在");
        }
        studentRegistrations = newRegs;

        List<Integer> subjectIds = studentRegistrations.stream().map(StudentRegistration::getActualSubjectId).collect(Collectors.toList());
        List<Subject> subjects = subjectDao.findBySubjectIds(subjectIds);
        Map<Integer, List<Subject>> subjectMap = subjects.stream().collect(Collectors.groupingBy(Subject::getId));
        List<MusicGroupSubjectPlan> musicSubjectClassPlans = musicGroupSubjectPlanDao.getMusicSubjectClassPlan(musicGroupId);

        Map<Integer, List<StudentRegistration>> regsMap = studentRegistrations.stream().collect(Collectors.groupingBy(StudentRegistration::getActualSubjectId));
        List<StudentRegistration> studentRegistrationList = new ArrayList<>();
        regsMap.forEach((subjectId, regs) -> {
            boolean hasSubject = false;
            MusicGroupSubjectPlan subjectPlan = null;
            for (MusicGroupSubjectPlan musicGroupSubjectPlan : musicSubjectClassPlans) {
                if (!subjectId.equals(musicGroupSubjectPlan.getSubjectId())) continue;
                hasSubject = true;
                musicGroupSubjectPlan.setApplyStudentNum(musicGroupSubjectPlan.getApplyStudentNum() + regs.size());
                subjectPlan = musicGroupSubjectPlan;
            }
            if (!hasSubject) {
                String name = subjectMap.get(subjectId).get(0).getName();
                throw new BizException("当前乐团没有学员包含的声部（" + name + ")");
            }
            //更新乐团声部计划信息
            musicGroupSubjectPlanDao.update(subjectPlan);

            for (StudentRegistration studentRegistration : regs) {
                studentRegistration.setId(null);
                studentRegistration.setMusicGroupStatus(StudentMusicGroupStatusEnum.APPLY);
                studentRegistration.setPaymentStatus(PaymentStatusEnum.NO);
                studentRegistration.setMusicGroupId(musicGroupId);
                studentRegistration.setSubjectId(subjectId);
                studentRegistration.setActualSubjectId(subjectId);
                studentRegistration.setTemporaryCourseFee(null);
            }
            studentRegistrationList.addAll(regs);
        });

        //添加的学生
        if (studentRegistrationList.size() > 0) {
            studentRegistrationDao.batchInsert(studentRegistrationList);
        }

        //修改乐团信息
        MusicGroup musicGroup = musicGroupDao.get(musicGroupId);
        musicGroup.setIsExtraClass(YesOrNoEnum.YES);
        musicGroupDao.update(musicGroup);

        musicGroupBuildLogDao.insert(new MusicGroupBuildLog(musicGroupId, "添加报名学员", sysUser.getId(), ""));

        return studentRegistrationList;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean closeMusicGroup(CloseMusicGroupDto closeMusicGroupDto) {
        SysUser sysUser = sysUserFeignService.queryUserInfo();
        if (sysUser == null) {
            throw new BizException("用户信息获取失败");
        }
        MusicGroup musicGroup = musicGroupDao.get(closeMusicGroupDto.getMusicGroupId());
        if (musicGroup == null) {
            throw new BizException("乐团找不到");
        }

        if (musicGroup.getStatus() != MusicGroupStatusEnum.PROGRESS) {
            throw new BizException("乐团当前状态是{}，不能关闭", musicGroup.getStatus().getMsg());
        }

        //有进行中的课不能关闭乐团
        Integer underwayCourseNum = courseScheduleDao.getUnderwayCourseNum(musicGroup.getId(), GroupType.MUSIC, CourseStatusEnum.UNDERWAY);
        if(underwayCourseNum >0){
            throw new BizException("乐团有进行的课程，不能关闭");
        }
        musicGroup.setStatus(MusicGroupStatusEnum.CLOSE);
        musicGroup.setUpdateTime(new Date());
        musicGroupDao.update(musicGroup);

        courseScheduleStudentPaymentService.updateCourseActualPrice(Arrays.asList(musicGroup.getId()), null, GroupType.MUSIC);

        musicGroupBuildLogDao.insert(new MusicGroupBuildLog(closeMusicGroupDto.getMusicGroupId(), "关闭乐团", sysUser.getId(), ""));

        List<StudentRegistration> musicGroupRegs = studentRegistrationDao.findMusicGroupStudent(closeMusicGroupDto.getMusicGroupId(), null);
        Map<Integer, BigDecimal> userReBackMap = closeMusicGroupDto.getUserReBack();
        //退还没上课程费用
        for (StudentRegistration musicGroupReg : musicGroupRegs) {
            BigDecimal userReBack = userReBackMap.getOrDefault(musicGroupReg.getUserId(), BigDecimal.ZERO);

            if (userReBack.compareTo(musicGroupReg.getSurplusCourseFee()) > 0) {
                throw new BizException(musicGroupReg.getName() + "退费金额不能大于实际金额");
            }
            //退用户余额
            if (userReBack.compareTo(BigDecimal.ZERO) > 0) {
                sysUserCashAccountService.updateBalance(musicGroupReg.getUserId(), userReBack, PlatformCashAccountDetailTypeEnum.REFUNDS, "关闭乐团");
            }
            //清除剩余课程费用
            if (musicGroupReg.getSurplusCourseFee().compareTo(BigDecimal.ZERO) > 0) {
                studentRegistrationService.updateUserSurplusCourseFee(musicGroupReg.getUserId(), musicGroupReg.getMusicGroupId(), musicGroupReg.getSurplusCourseFee().negate(), "关闭乐团", sysUser.getId());
            }
        }

        //删除未上课表
        courseScheduleDao.logicDeleteCourseSchedulesByMusicGroupID(musicGroup.getId());
        return true;
    }

}
