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

import static com.ym.mec.biz.dal.entity.MusicGroupStudentFee.PaymentStatus.NON_PAYMENT;
import static com.ym.mec.biz.dal.entity.MusicGroupStudentFee.PaymentStatus.PAID_COMPLETED;
import static com.ym.mec.biz.dal.enums.PaymentStatusEnum.YES;

import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

import javax.annotation.Resource;

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

import com.alibaba.fastjson.JSONObject;
import com.ym.mec.auth.api.client.SysUserFeignService;
import com.ym.mec.auth.api.entity.SysUser;
import com.ym.mec.auth.api.entity.SysUserRole;
import com.ym.mec.auth.api.enums.CertificateTypeEnum;
import com.ym.mec.biz.dal.dao.CourseScheduleDao;
import com.ym.mec.biz.dal.dao.GoodsDao;
import com.ym.mec.biz.dal.dao.MusicGroupDao;
import com.ym.mec.biz.dal.dao.MusicGroupPaymentCalenderCourseSettingsDao;
import com.ym.mec.biz.dal.dao.MusicGroupPaymentCalenderDao;
import com.ym.mec.biz.dal.dao.MusicGroupPaymentCalenderDetailDao;
import com.ym.mec.biz.dal.dao.MusicGroupPaymentStudentCourseDetailDao;
import com.ym.mec.biz.dal.dao.MusicGroupStudentFeeDao;
import com.ym.mec.biz.dal.dao.MusicGroupSubjectPlanDao;
import com.ym.mec.biz.dal.dao.StudentCourseFeeDetailDao;
import com.ym.mec.biz.dal.dao.StudentDao;
import com.ym.mec.biz.dal.dao.StudentPaymentOrderDetailDao;
import com.ym.mec.biz.dal.dao.StudentRegistrationDao;
import com.ym.mec.biz.dal.dao.SubjectChangeDao;
import com.ym.mec.biz.dal.dao.SubjectDao;
import com.ym.mec.biz.dal.dao.SysConfigDao;
import com.ym.mec.biz.dal.dao.SysUserCashAccountDao;
import com.ym.mec.biz.dal.dao.TeacherDao;
import com.ym.mec.biz.dal.dto.CourseFormDto;
import com.ym.mec.biz.dal.dto.StudentAddDto;
import com.ym.mec.biz.dal.dto.StudentApplyDetailDto;
import com.ym.mec.biz.dal.dto.StudentFeeDetailDto;
import com.ym.mec.biz.dal.dto.StudentInfo;
import com.ym.mec.biz.dal.dto.StudentMusicDetailDto;
import com.ym.mec.biz.dal.dto.StudentMusicGroupDto;
import com.ym.mec.biz.dal.entity.ClassGroup;
import com.ym.mec.biz.dal.entity.ClassGroupStudentMapper;
import com.ym.mec.biz.dal.entity.CooperationOrgan;
import com.ym.mec.biz.dal.entity.CourseSchedule;
import com.ym.mec.biz.dal.entity.CourseScheduleStudentPayment;
import com.ym.mec.biz.dal.entity.Goods;
import com.ym.mec.biz.dal.entity.MusicGroup;
import com.ym.mec.biz.dal.entity.MusicGroupPaymentCalender;
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.MusicGroupPaymentStudentCourseDetail;
import com.ym.mec.biz.dal.entity.MusicGroupStudentFee;
import com.ym.mec.biz.dal.entity.MusicGroupSubjectGoodsGroup;
import com.ym.mec.biz.dal.entity.MusicGroupSubjectPlan;
import com.ym.mec.biz.dal.entity.Student;
import com.ym.mec.biz.dal.entity.StudentCourseFeeDetail;
import com.ym.mec.biz.dal.entity.StudentPaymentOrder;
import com.ym.mec.biz.dal.entity.StudentPaymentOrderDetail;
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.ClassGroupStudentStatusEnum;
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.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.StudentMusicGroupStatusEnum;
import com.ym.mec.biz.dal.page.StudentRegistrationQueryInfo;
import com.ym.mec.biz.service.ClassGroupService;
import com.ym.mec.biz.service.ClassGroupStudentMapperService;
import com.ym.mec.biz.service.ContractService;
import com.ym.mec.biz.service.CourseScheduleService;
import com.ym.mec.biz.service.CourseScheduleStudentPaymentService;
import com.ym.mec.biz.service.ImGroupMemberService;
import com.ym.mec.biz.service.MusicGroupPaymentCalenderService;
import com.ym.mec.biz.service.MusicGroupSubjectPlanService;
import com.ym.mec.biz.service.SellOrderService;
import com.ym.mec.biz.service.StudentPaymentOrderDetailService;
import com.ym.mec.biz.service.StudentPaymentOrderService;
import com.ym.mec.biz.service.StudentRegistrationService;
import com.ym.mec.biz.service.SubjectService;
import com.ym.mec.biz.service.SysConfigService;
import com.ym.mec.biz.service.SysMessageService;
import com.ym.mec.biz.service.SysUserCashAccountDetailService;
import com.ym.mec.biz.service.SysUserCashAccountService;
import com.ym.mec.common.dal.BaseDAO;
import com.ym.mec.common.entity.ImResult;
import com.ym.mec.common.entity.ImUserModel;
import com.ym.mec.common.exception.BizException;
import com.ym.mec.common.page.PageInfo;
import com.ym.mec.common.service.impl.BaseServiceImpl;
import com.ym.mec.im.ImFeignService;
import com.ym.mec.thirdparty.message.MessageSenderPluginContext;
import com.ym.mec.util.collection.MapUtil;
import com.ym.mec.util.date.DateUtil;
import com.ym.mec.util.http.HttpUtil;

@Service
public class StudentRegistrationServiceImpl extends BaseServiceImpl<Long, StudentRegistration> implements StudentRegistrationService {

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

    @Resource
    private StudentRegistrationDao studentRegistrationDao;
    @Autowired
    private StudentPaymentOrderService studentPaymentOrderService;
    @Autowired
    private StudentPaymentOrderDetailService studentPaymentOrderDetailService;
    @Autowired
    private CourseScheduleStudentPaymentService courseScheduleStudentPaymentService;
    @Autowired
    private CourseScheduleService courseScheduleService;
    @Autowired
    private TeacherDao teacherDao;
    @Autowired
    private ClassGroupService classGroupDao;
    @Autowired
    private MusicGroupStudentFeeDao musicGroupStudentFeeDao;
    @Autowired
    private ClassGroupStudentMapperService classGroupStudentMapperDao;
    @Autowired
    private SysMessageService sysMessageService;
    @Autowired
    private MusicGroupSubjectPlanDao musicGroupSubjectPlanDao;
    @Autowired
    private SubjectDao subjectDao;
    @Autowired
    private SysUserCashAccountDao sysUserCashAccountDao;
    @Autowired
    private StudentDao studentDao;
    @Autowired
    private ContractService contractService;
    @Autowired
    private ImFeignService imFeignService;
    @Autowired
    private ImGroupMemberService imGroupMemberService;
    @Autowired
    private MusicGroupSubjectPlanService musicGroupSubjectPlanService;
    @Autowired
    private MusicGroupPaymentCalenderService musicGroupPaymentCalenderService;
    @Autowired
    private SubjectService subjectService;
    @Autowired
    private SysConfigDao sysConfigDao;
    @Autowired
    private MusicGroupDao musicGroupDao;
    @Autowired
    private SysUserCashAccountDetailService sysUserCashAccountDetailService;
    @Autowired
    private SysUserCashAccountService sysUserCashAccountService;
    @Autowired
    private SysUserFeignService sysUserFeignService;
    @Autowired
    private SellOrderService sellOrderService;
    @Autowired
    private StudentPaymentOrderDetailDao studentPaymentOrderDetailDao;
    @Autowired
    private SubjectChangeDao subjectChangeDao;
    @Autowired
    private GoodsDao goodsDao;
    @Autowired
    private MusicGroupPaymentCalenderDetailDao musicGroupPaymentCalenderDetailDao;
    @Autowired
    private MusicGroupPaymentCalenderDao musicGroupPaymentCalenderDao;
    @Autowired
    private MusicGroupPaymentStudentCourseDetailDao musicGroupPaymentStudentCourseDetailDao;
    @Autowired
    private MusicGroupPaymentCalenderCourseSettingsDao musicGroupPaymentCalenderCourseSettingsDao;
    @Autowired
    private StudentCourseFeeDetailDao studentCourseFeeDetailDao;
    @Autowired
    private CourseScheduleDao courseScheduleDao;

    @Override
    public BaseDAO<Long, StudentRegistration> getDAO() {
        return studentRegistrationDao;
    }

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

        List<StudentApplyDetailDto> dataList = null;
        int count = studentRegistrationDao.queryStudentDetailCount(params);
        if (queryInfo.getIsExport() && count > 50000) {
            throw new BizException("数据集太大，不能导出.最大数据集不能超过50000");
        }
        if (count > 0) {
            pageInfo.setTotal(count);
            params.put("offset", pageInfo.getOffset());
            dataList = studentRegistrationDao.queryStudentDetailPage(params);
            Set<Integer> subjectIds = dataList.stream().map(e -> e.getActualSubjectId()).collect(Collectors.toSet());
            Map<Integer, String> subjectMap = MapUtil.convertIntegerMap(musicGroupSubjectPlanDao.findSubjectMap(subjectIds, queryInfo.getMusicGroupId()));
            List<SubjectChange> waitPayChange = subjectChangeDao.getMusicGroupWaitPay(queryInfo.getMusicGroupId());
            Map<Integer, List<SubjectChange>> studentWaitPayChange = waitPayChange.stream().collect(Collectors.groupingBy(SubjectChange::getStudentId));
            dataList.forEach(e -> {
                if (StringUtils.isNotBlank(subjectMap.get(e.getActualSubjectId()))) {
                    e.setKitGroupPurchaseTypeEnum(KitGroupPurchaseTypeEnum.valueOf(subjectMap.get(e.getActualSubjectId())));
                }
                if (studentWaitPayChange.containsKey(e.getStudentId())) {
                    e.setSubjectChange(studentWaitPayChange.get(e.getStudentId()).get(0));
                }
            });
        }
        if (count == 0) {
            dataList = new ArrayList<>();
        }
        pageInfo.setRows(dataList);
        return pageInfo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer batchUpdateSubject(Integer userId, Integer subId, String musicGroupId) throws Exception {
        SysUser sysUser = sysUserFeignService.queryUserInfo();
        if (sysUser == null) {
            throw new BizException("获取用户信息失败");
        }
        //获取当前学员的当前声部
        StudentRegistration studentRegistration = studentRegistrationDao.queryByUserIdAndMusicGroupId(userId, musicGroupId);
        if (studentRegistration == null) {
            throw new BizException("学员信息不存在");
        }
        //批量调剂（未缴费学员）
        int i = studentRegistrationDao.batchUpdateSubject(userId, subId, musicGroupId);
        if (i > 0) {
            //当前专业报名人数减一
            musicGroupSubjectPlanService.addApplyStudentNum(musicGroupId, studentRegistration.getActualSubjectId(), -1);
            //修改专业已报名人数
            musicGroupSubjectPlanService.addApplyStudentNum(musicGroupId, subId, 1);
            MusicGroup musicGroup = musicGroupDao.get(musicGroupId);
            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_STUDENT_SUBJECT_CHANGE, "", musicGroup.getName());
        }
        return i;
    }

    @Override
    public StudentFeeDetailDto queryFeeDetail(Integer studentId, String musicGroupId) {
        return studentRegistrationDao.queryFeeDetail(studentId, musicGroupId);
    }

    @Override
    public List<Map<String, Object>> getNoClassStuBySubjectId(String musicGroupId, String actualSubjectId) {
        List<StudentRegistration> students = studentRegistrationDao.getNoClassStuBySubjectId(musicGroupId, actualSubjectId);
        List<Map<String, Object>> mapArrayList = new ArrayList<>();
        if (students != null && students.size() > 0) {
            String[] subjectIds = actualSubjectId.split(",");
            if (subjectIds != null && subjectIds.length > 0) {
                List<Map<Integer, String>> subjectNames = subjectDao.queryNameByIds(actualSubjectId);
                Map<Integer, String> subjectNameMap = MapUtil.convertMybatisMap(subjectNames);
                for (int i = 0; i < subjectIds.length; i++) {
                    Map<String, Object> resultMap = new HashMap<>(3);
                    int subjectId = Integer.parseInt(subjectIds[i]);
                    List<StudentRegistration> collect = students.stream().filter(e -> e.getActualSubjectId().equals(subjectId)).collect(Collectors.toList());
                    resultMap.put("subjectId", subjectId);
                    resultMap.put("subjectName", subjectNameMap.get(subjectId));
                    resultMap.put("rows", collect);
                    mapArrayList.add(resultMap);
                }
            }
        }
        return mapArrayList;
    }

    @Override
    public List<MusicGroupSubjectPlan> getNoClassStuCountByMusicGroupId(String musicGroupId) {
        return studentRegistrationDao.getNoClassStuCountByMusicGroupId(musicGroupId);
    }

    @Override
    public Integer updateByUserIdAndMusicGroupId(StudentRegistration studentRegistration) {
        return studentRegistrationDao.updateByUserIdAndMusicGroupId(studentRegistration);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public StudentRegistration addStudent(StudentRegistration studentRegistration) throws Exception {
        Integer userId = studentRegistration.getUserId();

        Student student = studentDao.getLocked(userId);
        if (student == null) {
            throw new BizException("您已登录超时，请重新登录后再次报名");
        }

        StudentRegistration hasReg = getByPhoneAndMusicGroupId(studentRegistration.getMusicGroupId(), studentRegistration.getParentsPhone());
        if (hasReg != null && hasReg.getMusicGroupStatus() != StudentMusicGroupStatusEnum.QUIT) {
            throw new BizException("该乐团您已报名");
        }

        Date date = new Date();
        SysUser sysUser = sysUserFeignService.queryUserByMobile(studentRegistration.getParentsPhone());
        if (sysUser == null) {
            throw new BizException("用户信息查询失败");
        }

        if (!sysUser.getUserType().contains("STUDENT")) {
            sysUser.setUserType(sysUser.getUserType() + ",STUDENT");
        }
        sysUser.setPhone(studentRegistration.getParentsPhone());
        sysUser.setOrganId(studentRegistration.getOrganId());
        sysUser.setRealName(studentRegistration.getParentsName());

        sysUser.setUsername(studentRegistration.getName());
        sysUser.setGender(studentRegistration.getGender());
        sysUser.setBirthdate(studentRegistration.getBirthdate());
        sysUser.setCreateTime(date);
        sysUser.setUpdateTime(date);
        teacherDao.updateUser(sysUser);

        studentRegistration.setCurrentGradeDate(date);
        studentRegistration.setActualSubjectId(studentRegistration.getSubjectId());
        studentRegistration.setCreateTime(date);
        studentRegistration.setUpdateTime(date);
        studentRegistration.setUserId(sysUser.getId());
        studentRegistration.setMusicGroupStatus(StudentMusicGroupStatusEnum.APPLY);
        if(hasReg != null){
            studentRegistration.setMusicGroupStatus(StudentMusicGroupStatusEnum.NORMAL);
            studentRegistration.setId(hasReg.getId());
            studentRegistrationDao.update(studentRegistration);
        }else {
            studentRegistrationDao.insert(studentRegistration);
        }

        // 增加报名学生数
        musicGroupSubjectPlanService.addApplyStudentNum(studentRegistration.getMusicGroupId(), studentRegistration.getSubjectId(), 1);
        // 报名成功后，发送短信
        // String studentApplyUrl = sysConfigDao.findConfigValue(SysConfigService.STUDENT_APPLY_URL) + studentRegistration.getMusicGroupId();
        String serverPhone = sysConfigDao.findConfigValue(SysConfigService.SERVER_PHONE);
        Subject subject = subjectDao.get(studentRegistration.getSubjectId());
        // MusicGroup musicGroup = musicGroupDao.get(studentRegistration.getMusicGroupId());

        Map<Integer, String> map = new HashMap<>(1);
        map.put(sysUser.getId(), studentRegistration.getParentsPhone());
        sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.AWSMS, MessageTypeEnum.SMS_APPLY_MESSAGE, map, null, 0, "", "",
                studentRegistration.getParentsName(), subject.getName(), serverPhone);

        return studentRegistration;
    }

    @Override
    public StudentInfo queryStudentInfo(Integer userId) {
        return studentRegistrationDao.queryStudentInfo(userId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public StudentPaymentOrder addOrder(StudentRegistration studentRegistration, BigDecimal amount, String orderNo, String paymentChannel, BigDecimal courseFee, List<MusicGroupSubjectGoodsGroup> goodsGroups, List<Goods> goodsList, List<Goods> otherGoodsList, List<CourseFormDto> courseForms, BigDecimal remitFee, BigDecimal courseRemitFee, List<MusicGroupPaymentCalenderCourseSettings> newCourses) throws Exception {
        Date date = new Date();
        StudentPaymentOrder studentPaymentOrder = new StudentPaymentOrder();
        studentPaymentOrder.setUserId(studentRegistration.getUserId());
        studentPaymentOrder.setGroupType(GroupType.MUSIC);
        studentPaymentOrder.setOrderNo(orderNo);
        studentPaymentOrder.setType(OrderTypeEnum.APPLY);
        studentPaymentOrder.setExpectAmount(amount);
        studentPaymentOrder.setActualAmount(amount);
        studentPaymentOrder.setStatus(DealStatusEnum.ING);
        studentPaymentOrder.setPaymentChannel(paymentChannel);
        studentPaymentOrder.setMusicGroupId(studentRegistration.getMusicGroupId());
        studentPaymentOrderService.insert(studentPaymentOrder);

        ArrayList<StudentPaymentOrderDetail> studentPaymentOrderDetailList = new ArrayList<>();
        StudentPaymentOrderDetail studentPaymentOrderDetail = new StudentPaymentOrderDetail();
        studentPaymentOrderDetail.setType(OrderDetailTypeEnum.COURSE);
        studentPaymentOrderDetail.setPrice(BigDecimal.ZERO);
        studentPaymentOrderDetail.setRemitFee(BigDecimal.ZERO);
        studentPaymentOrderDetail.setCreateTime(date);
        studentPaymentOrderDetail.setUpdateTime(date);
        studentPaymentOrderDetail.setPaymentOrderId(studentPaymentOrder.getId());
        studentPaymentOrderDetailList.add(studentPaymentOrderDetail);
        //乐器及打包辅件
        if (goodsGroups != null && goodsGroups.size() > 0) {
            for (MusicGroupSubjectGoodsGroup goodsGroup : goodsGroups) {
                StudentPaymentOrderDetail studentPaymentOrderDetail4goodsGroup = new StudentPaymentOrderDetail();
                studentPaymentOrderDetail4goodsGroup.setRemitFee(BigDecimal.ZERO);
                OrderDetailTypeEnum type = null;
                if (goodsGroup.getType().equals(GoodsType.INSTRUMENT)) {
                    type = OrderDetailTypeEnum.MUSICAL;
                    goodsGroup.setPrice(goodsGroup.getPrice().subtract(remitFee));
                    studentPaymentOrderDetail4goodsGroup.setRemitFee(remitFee);
                } else if (goodsGroup.getType().equals(GoodsType.ACCESSORIES)) {
                    type = OrderDetailTypeEnum.ACCESSORIES;
                } else if (goodsGroup.getType().equals(GoodsType.OTHER)) {
                    type = OrderDetailTypeEnum.TEACHING;
                }
                studentPaymentOrderDetail4goodsGroup.setType(type);
                studentPaymentOrderDetail4goodsGroup.setPrice(goodsGroup.getPrice());
                studentPaymentOrderDetail4goodsGroup.setGoodsIdList(goodsGroup.getGoodsIdList());
                studentPaymentOrderDetail4goodsGroup.setCreateTime(date);
                studentPaymentOrderDetail4goodsGroup.setUpdateTime(date);
                studentPaymentOrderDetail4goodsGroup.setPaymentOrderId(studentPaymentOrder.getId());
                studentPaymentOrderDetail4goodsGroup.setKitGroupPurchaseType(goodsGroup.getKitGroupPurchaseType());
                studentPaymentOrderDetailList.add(studentPaymentOrderDetail4goodsGroup);
            }
        }

        //单独辅件
        if (goodsList != null && goodsList.size() > 0) {
            for (Goods goods : goodsList) {
                StudentPaymentOrderDetail studentPaymentOrderDetail4goods = new StudentPaymentOrderDetail();
                OrderDetailTypeEnum orderDetailType = goods.getType().equals(GoodsType.INSTRUMENT) ? OrderDetailTypeEnum.MUSICAL : OrderDetailTypeEnum.ACCESSORIES;
                studentPaymentOrderDetail4goods.setType(orderDetailType);
                studentPaymentOrderDetail4goods.setPrice(goods.getGroupPurchasePrice());
                studentPaymentOrderDetail4goods.setGoodsIdList(goods.getId().toString());
                studentPaymentOrderDetail4goods.setCreateTime(date);
                studentPaymentOrderDetail4goods.setUpdateTime(date);
                studentPaymentOrderDetail4goods.setPaymentOrderId(studentPaymentOrder.getId());
                studentPaymentOrderDetailList.add(studentPaymentOrderDetail4goods);
            }
        }
        //单独教谱
        if (otherGoodsList != null && otherGoodsList.size() > 0) {
            for (Goods goods : otherGoodsList) {
                StudentPaymentOrderDetail studentPaymentOrderDetail4otherGoods = new StudentPaymentOrderDetail();
                studentPaymentOrderDetail4otherGoods.setType(OrderDetailTypeEnum.TEACHING);
                studentPaymentOrderDetail4otherGoods.setPrice(goods.getGroupPurchasePrice());
                studentPaymentOrderDetail4otherGoods.setGoodsIdList(goods.getId().toString());
                studentPaymentOrderDetail4otherGoods.setCreateTime(date);
                studentPaymentOrderDetail4otherGoods.setUpdateTime(date);
                studentPaymentOrderDetail4otherGoods.setPaymentOrderId(studentPaymentOrder.getId());
                studentPaymentOrderDetailList.add(studentPaymentOrderDetail4otherGoods);
            }
        }
        //可选课程
        if (courseForms != null && courseForms.size() > 0) {
            for (CourseFormDto courseForm : courseForms) {
                StudentPaymentOrderDetail studentPaymentOrderDetailCourse = new StudentPaymentOrderDetail();
                studentPaymentOrderDetailCourse.setType(OrderDetailTypeEnum.HIGH_ONLINE_COURSE);
                studentPaymentOrderDetailCourse.setPrice(courseForm.getPrice());
                studentPaymentOrderDetailCourse.setCreateTime(date);
                studentPaymentOrderDetailCourse.setUpdateTime(date);
                studentPaymentOrderDetailCourse.setPaymentOrderId(studentPaymentOrder.getId());
                studentPaymentOrderDetailList.add(studentPaymentOrderDetailCourse);
            }
        }
        //新的课程形态
        if (newCourses != null && newCourses.size() > 0) {
            for (MusicGroupPaymentCalenderCourseSettings newCourse : newCourses) {
                StudentPaymentOrderDetail studentPaymentOrderDetailCourse = new StudentPaymentOrderDetail();
                studentPaymentOrderDetailCourse.setType(OrderDetailTypeEnum.valueOf(newCourse.getCourseType().getCode()));
                studentPaymentOrderDetailCourse.setPrice(newCourse.getCourseCurrentPrice());
                if (courseRemitFee.compareTo(BigDecimal.ZERO) > 0 && !newCourse.getIsStudentOptional()) {
                    studentPaymentOrderDetailCourse.setPrice(BigDecimal.ZERO);
                    studentPaymentOrderDetailCourse.setRemitFee(newCourse.getCourseCurrentPrice());
                } else {
                    studentPaymentOrderDetailCourse.setPrice(newCourse.getCourseCurrentPrice());
                    studentPaymentOrderDetailCourse.setRemitFee(BigDecimal.ZERO);
                }
                studentPaymentOrderDetailCourse.setCreateTime(date);
                studentPaymentOrderDetailCourse.setUpdateTime(date);
                studentPaymentOrderDetailCourse.setPaymentOrderId(studentPaymentOrder.getId());
                studentPaymentOrderDetailList.add(studentPaymentOrderDetailCourse);
            }
        }
        studentPaymentOrderDetailService.batchAdd(studentPaymentOrderDetailList);

        //增加缴费学生数
        boolean updateFlag = false;
        for (int i = 0; i < 10; i++) {
//            if (amount.compareTo(BigDecimal.ZERO) == 0) { //0元订单不增加报名人数
//                updateFlag = true;
//                break;
//            }
            MusicGroupSubjectPlan musicOneSubjectClassPlan = musicGroupSubjectPlanService.getMusicOneSubjectClassPlan(studentRegistration.getMusicGroupId(), studentRegistration.getActualSubjectId());
            int paidNum = musicOneSubjectClassPlan.getPaidStudentNum() == null ? 0 : musicOneSubjectClassPlan.getPaidStudentNum();
            musicOneSubjectClassPlan.setPaidStudentNum(paidNum + 1);
            if (studentRegistration.getTemporaryCourseFee() == null && musicOneSubjectClassPlan.getPaidStudentNum() > musicOneSubjectClassPlan.getExpectedStudentNum()) {
                throw new BizException("乐团该声部人数暂时已满，请稍后再试");
            }
            int count = musicGroupSubjectPlanService.update(musicOneSubjectClassPlan);
            if (count >= 1) {
                updateFlag = true;
                break;
            }
        }
        if (!updateFlag) {
            throw new BizException("系统繁忙，更新缴费人数失败");
        }

        return studentPaymentOrder;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public StudentPaymentOrder reAddOrder(Integer userId, BigDecimal amount, String orderNo, String paymentChannel, BigDecimal courseFee, List<MusicGroupSubjectGoodsGroup> goodsGroups, List<Goods> goodsList, List<Goods> otherGoodsList, String musicGroupId, StudentPaymentOrder oldOrder, List<CourseFormDto> courseForms, BigDecimal remitFee, BigDecimal courseRemitFee, List<MusicGroupPaymentCalenderCourseSettings> newCourses) {
        //关闭老订单
        oldOrder.setStatus(DealStatusEnum.CLOSE);
        studentPaymentOrderService.update(oldOrder);
        if (oldOrder.getBalancePaymentAmount() != null && oldOrder.getBalancePaymentAmount().compareTo(BigDecimal.ZERO) > 0) {
            sysUserCashAccountService.updateBalance(oldOrder.getUserId(), oldOrder.getBalancePaymentAmount(), PlatformCashAccountDetailTypeEnum.REFUNDS, "关闭订单");
        }
        Date date = new Date();
        StudentPaymentOrder studentPaymentOrder = new StudentPaymentOrder();
        studentPaymentOrder.setUserId(userId);
        studentPaymentOrder.setGroupType(GroupType.MUSIC);
        studentPaymentOrder.setOrderNo(orderNo);
        studentPaymentOrder.setType(OrderTypeEnum.APPLY);
        studentPaymentOrder.setExpectAmount(amount);
        studentPaymentOrder.setActualAmount(amount);
        studentPaymentOrder.setStatus(DealStatusEnum.ING);
        studentPaymentOrder.setPaymentChannel(paymentChannel);
        studentPaymentOrder.setMusicGroupId(musicGroupId);
        studentPaymentOrderService.insert(studentPaymentOrder);

        List<StudentPaymentOrderDetail> studentPaymentOrderDetailList = new ArrayList<>();
        StudentPaymentOrderDetail studentPaymentOrderDetail = new StudentPaymentOrderDetail();
        studentPaymentOrderDetail.setType(OrderDetailTypeEnum.COURSE);
        studentPaymentOrderDetail.setPrice(BigDecimal.ZERO);
        studentPaymentOrderDetail.setRemitFee(BigDecimal.ZERO);
        studentPaymentOrderDetail.setCreateTime(date);
        studentPaymentOrderDetail.setUpdateTime(date);
        studentPaymentOrderDetail.setPaymentOrderId(studentPaymentOrder.getId());
        studentPaymentOrderDetailList.add(studentPaymentOrderDetail);
        //乐器及打包辅件
        if (goodsGroups != null && goodsGroups.size() > 0) {
            for (MusicGroupSubjectGoodsGroup goodsGroup : goodsGroups) {
                StudentPaymentOrderDetail studentPaymentOrderDetail4goodsGroup = new StudentPaymentOrderDetail();
                studentPaymentOrderDetail4goodsGroup.setRemitFee(BigDecimal.ZERO);
                OrderDetailTypeEnum type = null;
                if (goodsGroup.getType().equals(GoodsType.INSTRUMENT)) {
                    type = OrderDetailTypeEnum.MUSICAL;
                    goodsGroup.setPrice(goodsGroup.getPrice().subtract(remitFee));
                    studentPaymentOrderDetail4goodsGroup.setRemitFee(remitFee);
                } else if (goodsGroup.getType().equals(GoodsType.ACCESSORIES)) {
                    type = OrderDetailTypeEnum.ACCESSORIES;
                } else if (goodsGroup.getType().equals(GoodsType.OTHER)) {
                    type = OrderDetailTypeEnum.TEACHING;
                }
                studentPaymentOrderDetail4goodsGroup.setType(type);
                studentPaymentOrderDetail4goodsGroup.setPrice(goodsGroup.getPrice());
                studentPaymentOrderDetail4goodsGroup.setGoodsIdList(goodsGroup.getGoodsIdList());
                studentPaymentOrderDetail4goodsGroup.setCreateTime(date);
                studentPaymentOrderDetail4goodsGroup.setUpdateTime(date);
                studentPaymentOrderDetail4goodsGroup.setPaymentOrderId(studentPaymentOrder.getId());
                studentPaymentOrderDetail4goodsGroup.setKitGroupPurchaseType(goodsGroup.getKitGroupPurchaseType());
                studentPaymentOrderDetailList.add(studentPaymentOrderDetail4goodsGroup);
            }
        }

        //单独辅件
        if (goodsList != null && goodsList.size() > 0) {
            for (Goods goods : goodsList) {
                StudentPaymentOrderDetail studentPaymentOrderDetail4goods = new StudentPaymentOrderDetail();
                OrderDetailTypeEnum orderDetailType = goods.getType().equals(GoodsType.INSTRUMENT) ? OrderDetailTypeEnum.MUSICAL : OrderDetailTypeEnum.ACCESSORIES;
                studentPaymentOrderDetail4goods.setType(orderDetailType);
                studentPaymentOrderDetail4goods.setPrice(goods.getGroupPurchasePrice());
                studentPaymentOrderDetail4goods.setGoodsIdList(goods.getId().toString());
                studentPaymentOrderDetail4goods.setCreateTime(date);
                studentPaymentOrderDetail4goods.setUpdateTime(date);
                studentPaymentOrderDetail4goods.setPaymentOrderId(studentPaymentOrder.getId());
                studentPaymentOrderDetailList.add(studentPaymentOrderDetail4goods);

            }
        }
        //单独教谱
        if (otherGoodsList != null && otherGoodsList.size() > 0) {
            for (Goods goods : otherGoodsList) {
                StudentPaymentOrderDetail studentPaymentOrderDetail4otherGoods = new StudentPaymentOrderDetail();
                studentPaymentOrderDetail4otherGoods.setType(OrderDetailTypeEnum.TEACHING);
                studentPaymentOrderDetail4otherGoods.setPrice(goods.getGroupPurchasePrice());
                studentPaymentOrderDetail4otherGoods.setGoodsIdList(goods.getId().toString());
                studentPaymentOrderDetail4otherGoods.setCreateTime(date);
                studentPaymentOrderDetail4otherGoods.setUpdateTime(date);
                studentPaymentOrderDetail4otherGoods.setPaymentOrderId(studentPaymentOrder.getId());
                studentPaymentOrderDetailList.add(studentPaymentOrderDetail4otherGoods);
            }
        }
        //可选课程
        if (courseForms != null && courseForms.size() > 0) {
            for (CourseFormDto courseForm : courseForms) {
                StudentPaymentOrderDetail studentPaymentOrderDetailCourse = new StudentPaymentOrderDetail();
                studentPaymentOrderDetailCourse.setType(OrderDetailTypeEnum.HIGH_ONLINE_COURSE);
                studentPaymentOrderDetailCourse.setPrice(courseForm.getPrice());
                studentPaymentOrderDetailCourse.setCreateTime(date);
                studentPaymentOrderDetailCourse.setUpdateTime(date);
                studentPaymentOrderDetailCourse.setPaymentOrderId(studentPaymentOrder.getId());
                studentPaymentOrderDetailList.add(studentPaymentOrderDetailCourse);
            }
        }
        //新的课程形态
        if (newCourses != null && newCourses.size() > 0) {
            for (MusicGroupPaymentCalenderCourseSettings newCourse : newCourses) {
                StudentPaymentOrderDetail studentPaymentOrderDetailCourse = new StudentPaymentOrderDetail();
                studentPaymentOrderDetailCourse.setType(OrderDetailTypeEnum.valueOf(newCourse.getCourseType().getCode()));
                if (courseRemitFee.compareTo(BigDecimal.ZERO) > 0 && !newCourse.getIsStudentOptional()) {
                    studentPaymentOrderDetailCourse.setPrice(BigDecimal.ZERO);
                    studentPaymentOrderDetailCourse.setRemitFee(newCourse.getCourseCurrentPrice());
                } else {
                    studentPaymentOrderDetailCourse.setPrice(newCourse.getCourseCurrentPrice());
                    studentPaymentOrderDetailCourse.setRemitFee(BigDecimal.ZERO);
                }
                studentPaymentOrderDetailCourse.setCreateTime(date);
                studentPaymentOrderDetailCourse.setUpdateTime(date);
                studentPaymentOrderDetailCourse.setPaymentOrderId(studentPaymentOrder.getId());
                studentPaymentOrderDetailList.add(studentPaymentOrderDetailCourse);
            }
        }
        studentPaymentOrderDetailService.batchAdd(studentPaymentOrderDetailList);

        return studentPaymentOrder;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public StudentRegistration queryByUserIdAndMusicGroupId(Integer userId, String musicGroupId) {
        StudentRegistration registration = studentRegistrationDao.queryByUserIdAndMusicGroupId(userId, musicGroupId);
        if (registration == null) {
            return null;
        }
        SysUserCashAccount account = sysUserCashAccountDao.getLocked(userId);
        registration.setBalance(account.getBalance());
        registration.setTransferStudent(registration.getTemporaryCourseFee() == null ? 0 : 1);
        return registration;
    }

    @Override
    public StudentRegistration getByPhoneAndMusicGroupId(String musicGroupId, String parentsPhone) {
        return studentRegistrationDao.getByPhoneAndMusicGroupId(musicGroupId, parentsPhone);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer insertStudent(StudentAddDto studentAddDto) throws Exception {
        StudentRegistration studentRegistration = studentAddDto.getStudentRegistration();
        if (studentRegistration == null) {
            throw new BizException("参数校验失败");
        }
        /*if(studentAddDto.getSignClassId() == null && studentAddDto.getMixClassId() == null){
            throw new BizException("参数校验失败: 单技班或合奏班必填一项");
        }*/
        Date date = new Date();
        String musicGroupId = studentRegistration.getMusicGroupId();
        
        studentRegistration.setCreateTime(date);
        studentRegistration.setUpdateTime(date);

        StudentRegistration phoneAndMusicGroupId = studentRegistrationDao.getByPhoneAndMusicGroupId(musicGroupId, studentRegistration.getParentsPhone());
        if (phoneAndMusicGroupId != null && phoneAndMusicGroupId.getMusicGroupStatus() != StudentMusicGroupStatusEnum.QUIT && phoneAndMusicGroupId.getMusicGroupStatus() != StudentMusicGroupStatusEnum.APPLY) {
            throw new BizException("该学员已存在");
        } else {
            SysUser sysUser = studentRegistrationDao.getSysUserByPhone(studentRegistration.getParentsPhone());
            MusicGroup musicGroup = musicGroupDao.get(musicGroupId);
            Integer userId;
            if (sysUser == null) {
                //新增user
                sysUser = new SysUser();
                sysUser.setPhone(studentRegistration.getParentsPhone());
                sysUser.setRealName(studentRegistration.getParentsName());
                sysUser.setUsername(studentRegistration.getName());
                sysUser.setGender(studentRegistration.getGender());
                sysUser.setUserType("STUDENT");
                sysUser.setIdCardNo(studentRegistration.getIdCardNo());
                sysUser.setOrganId(musicGroup.getOrganId());
                sysUser.setBirthdate(studentRegistration.getBirthdate());
                teacherDao.addSysUser(sysUser);
                userId = sysUser.getId();
                studentDao.insert(new Student(userId, studentRegistration.getSubjectId().toString()));
                //添加用户现金账户
                sysUserCashAccountDao.insert(new SysUserCashAccount(userId, "CNY"));
                //添加用户电子签章账户
//                contractService.register(userId, sysUser.getRealName(), sysUser.getIdCardNo(), sysUser.getPhone());
                ImResult register = imFeignService.register(new ImUserModel(userId.toString(), sysUser.getUsername(), null));
                sysUser.setImToken(register.getToken());
                teacherDao.updateUser(sysUser);
            } else {
                if (StringUtils.isNotEmpty(sysUser.getUsername())) {
                    if (!sysUser.getUsername().equals(studentRegistration.getName())) {
                        throw new BizException("操作失败：账户已被注册");
                    }
                }
                if (!sysUser.getUserType().contains("STUDENT")) {
                    sysUser.setUserType(sysUser.getUserType() + ",STUDENT");
                }
                sysUser.setPhone(studentRegistration.getParentsPhone());
                sysUser.setRealName(studentRegistration.getParentsName());
                sysUser.setUsername(studentRegistration.getName());
                sysUser.setGender(studentRegistration.getGender());
                sysUser.setOrganId(musicGroup.getOrganId());
                sysUser.setBirthdate(studentRegistration.getBirthdate());
                teacherDao.updateUser(sysUser);
                userId = sysUser.getId();
                Student student = studentDao.get(userId);
                if (student == null) {
                    studentDao.insert(new Student(userId, studentRegistration.getSubjectId().toString()));
                } else if (StringUtils.isEmpty(student.getSubjectIdList())) {
                    student.setSubjectIdList(studentRegistration.getSubjectId().toString());
                    student.setUpdateTime(date);
                    studentDao.update(student);
                } else if (StringUtils.isNotEmpty(student.getSubjectIdList())) {
                    String[] split = student.getSubjectIdList().split(",");
                    List<String> list = new ArrayList<>(Arrays.asList(split));
                    if (!list.contains(studentRegistration.getSubjectId().toString())) {
                        list.add(studentRegistration.getSubjectId().toString());
                        student.setSubjectIdList(StringUtils.join(list, ","));
                        student.setUpdateTime(date);
                        studentDao.update(student);
                    }
                }
            }
            MusicGroupStudentFee studentFeeDaoByUser = musicGroupStudentFeeDao.findByUser(userId, musicGroupId);
            if (studentFeeDaoByUser != null) {
                throw new BizException("该学员已存在");
            }
            studentRegistration.setActualSubjectId(studentRegistration.getSubjectId());
            studentRegistration.setUserId(userId);
            studentRegistration.setPaymentStatus(PaymentStatusEnum.OPEN);
            studentRegistration.setMusicGroupStatus(StudentMusicGroupStatusEnum.APPLY);
            studentRegistration.setTemporaryCourseFee(studentAddDto.getTemporaryCourseFee());
            //学生报名表
            Set<Integer> roleIds = new HashSet<>(1);
            roleIds.add(SysUserRole.OPERATION_EXECUTIVE);

            sysMessageService.batchSeoMessage(musicGroupDao.queryUserIdByRoleId(roleIds, musicGroup.getOrganId()), MessageTypeEnum.BACKSTAGE_MUSIC_GROUP_ADD_STUDENT, "", musicGroup.getName(), studentRegistration.getName());
            //增加报名学生数
            musicGroupSubjectPlanService.addApplyStudentNum(musicGroupId, studentRegistration.getSubjectId(), 1);
            //汇总金额

            MusicGroupStudentFee musicGroupStudentFee = new MusicGroupStudentFee(musicGroupId,
                    userId, studentRegistration.getSubjectId(), studentAddDto.getCourseFee(),
                    null, studentAddDto.getTemporaryCourseFee(), null);

            /*if (musicGroup.getFeeType() != null && musicGroup.getFeeType() != MusicGroupPaymentCalender.FeeType.OFFLINE && musicGroupStudentFee.getTemporaryCourseFee().doubleValue() * 100 == 0) {
                musicGroupStudentFee.setRemainNetworkClassTimes(musicGroupStudentFee.getRemainNetworkClassTimes() + 1);
            }*/
            musicGroupStudentFeeDao.insert(musicGroupStudentFee);

            StudentPaymentOrder waitPayOrder = studentPaymentOrderService.findMusicGroupApplyOrderByStatus(userId, studentRegistration.getMusicGroupId(), DealStatusEnum.WAIT_PAY);

            if (waitPayOrder != null) {
                waitPayOrder.setStatus(DealStatusEnum.CLOSE);
                studentPaymentOrderService.update(waitPayOrder);
            }
            //生成订单
            StudentPaymentOrder studentPaymentOrder = new StudentPaymentOrder();
            studentPaymentOrder.setUserId(userId);
            studentPaymentOrder.setGroupType(GroupType.MUSIC);
            studentPaymentOrder.setType(OrderTypeEnum.APPLY);
            studentPaymentOrder.setStatus(DealStatusEnum.WAIT_PAY);
            studentPaymentOrder.setMusicGroupId(musicGroupId);
            studentPaymentOrder.setClassGroupId(studentAddDto.getSignClassId());
            studentPaymentOrder.setOrganId(musicGroup.getOrganId());
            studentPaymentOrder.setRoutingOrganId(musicGroup.getOrganId());

            //生成订单明细
            List<StudentPaymentOrderDetail> studentPaymentOrderDetails = studentAddDto.getStudentPaymentOrderDetails();
            if (studentPaymentOrderDetails == null) {
                studentPaymentOrderDetails = new ArrayList<>();
            }
            //汇总金额

            BigDecimal reduce = studentPaymentOrderDetails.stream().map(StudentPaymentOrderDetail::getPrice).reduce(BigDecimal.ZERO, BigDecimal::add);
            if (reduce.compareTo(BigDecimal.ZERO) == 0) {
                studentPaymentOrder.setStatus(DealStatusEnum.SUCCESS);
                studentPaymentOrder.setActualAmount(reduce);
                studentPaymentOrder.setPayTime(date);
            }
            studentPaymentOrder.setExpectAmount(reduce);
            studentPaymentOrderService.insert(studentPaymentOrder);
            
            //当前学员是否以前存在过当前乐团
            if (phoneAndMusicGroupId != null) {
                studentRegistration.setId(phoneAndMusicGroupId.getId());
                studentRegistrationDao.update(studentRegistration);
            } else {
                studentRegistrationDao.insertBasic(studentRegistration);
            }
            studentRegistrationDao.updateCurrentClass(studentRegistration);

            return userId;
        }
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void insertStudent(String studentIds,String oldMusicGroupId,String newMusicGroupId,Map<Integer, List<MusicGroupPaymentCalenderStudentDetail>> collect){
        SysUser sysUser1 = sysUserFeignService.queryUserInfo();
        //获取旧乐团学员注册信息
        List<StudentRegistration> studentRegistrations = studentRegistrationDao.queryByUserIdsAndMusicGroupId(studentIds,oldMusicGroupId);
        List<StudentCourseFeeDetail> studentCourseFeeDetails = new ArrayList<>();
        BigDecimal amount = BigDecimal.ZERO;
        for (StudentRegistration studentRegistration : studentRegistrations) {
            List<MusicGroupPaymentCalenderStudentDetail> details = collect.get(studentRegistration.getUserId());
            BigDecimal masterTotalPrice = details.stream().map(e->e.getCutAmount()).reduce(BigDecimal.ZERO, BigDecimal::add);
            if(masterTotalPrice.doubleValue() > studentRegistration.getSurplusCourseFee().doubleValue()){
                throw new BizException("用户信息发生变动，请重新提交");
            }
            if(oldMusicGroupId == newMusicGroupId){
                continue;
            }
            courseScheduleStudentPaymentService.updateCourseActualPrice(Arrays.asList(oldMusicGroupId),null, GroupType.MUSIC);
            //记录课程余额消费日志
            if(studentRegistration.getSurplusCourseFee().doubleValue() > 0d && masterTotalPrice.doubleValue() > 0d){
                StudentCourseFeeDetail studentCourseFeeDetail = new StudentCourseFeeDetail();
                if(studentRegistration.getSurplusCourseFee().doubleValue() > masterTotalPrice.doubleValue()){
                    amount = masterTotalPrice;
                    studentCourseFeeDetail.setAmount(masterTotalPrice.negate());
                    studentCourseFeeDetail.setSurplusCourseFee(studentRegistration.getSurplusCourseFee().subtract(masterTotalPrice));
                }else {
                    amount = studentRegistration.getSurplusCourseFee();
                    studentCourseFeeDetail.setAmount(studentRegistration.getSurplusCourseFee().negate());
                    studentCourseFeeDetail.setSurplusCourseFee(BigDecimal.ZERO);
                }
                studentCourseFeeDetail.setStudentRegistrationId(studentRegistration.getId());
                studentRegistration.setSurplusCourseFee(studentCourseFeeDetail.getSurplusCourseFee());
                studentCourseFeeDetail.setMemo("跨团合班消费");
                studentCourseFeeDetail.setOperator(sysUser1.getId());
                studentCourseFeeDetails.add(studentCourseFeeDetail);
                //修改原有乐团注册信息
                studentRegistrationDao.update(studentRegistration);
            }
            //用户是否在主乐团
            StudentRegistration registration = studentRegistrationDao.getByPhoneAndMusicGroupId(newMusicGroupId, studentRegistration.getParentsPhone());
            if (registration != null) {
                //修改剩余课程余额
                Date date = new Date();
                registration.setMusicGroupStatus(StudentMusicGroupStatusEnum.NORMAL);
                registration.setCreateTime(date);
                registration.setUpdateTime(date);
                registration.setSurplusCourseFee(registration.getSurplusCourseFee().add(amount));
                studentRegistrationDao.update(registration);
            }else {
                //生成学员乐团注册表
                studentRegistration.setOrganId(musicGroupDao.get(newMusicGroupId).getOrganId());
                studentRegistration.setSurplusCourseFee(amount);
                studentRegistration.setMusicGroupId(newMusicGroupId);
                studentRegistrationDao.insert(studentRegistration);
                registration = studentRegistration;

                //增加报名学生数
                musicGroupSubjectPlanService.addApplyStudentNum(newMusicGroupId, studentRegistration.getActualSubjectId(), 1);
                //新增Fee表
                MusicGroupStudentFee musicGroupStudentFee = musicGroupStudentFeeDao.findByUser(studentRegistration.getUserId(),newMusicGroupId);
                if(musicGroupStudentFee == null){
                    musicGroupStudentFee = new MusicGroupStudentFee(newMusicGroupId,
                            studentRegistration.getUserId(), studentRegistration.getSubjectId(),BigDecimal.ZERO,
                            null, studentRegistration.getTemporaryCourseFee(), studentRegistration.getPaymentStatus()==YES?PAID_COMPLETED:NON_PAYMENT);
                    musicGroupStudentFeeDao.insert(musicGroupStudentFee);
                }
            }
            //主班新增余额日志
            if(amount.doubleValue() != 0d && masterTotalPrice.doubleValue() > 0d){
                StudentCourseFeeDetail studentCourseFeeDetail = new StudentCourseFeeDetail();
                studentCourseFeeDetail.setAmount(amount);
                studentCourseFeeDetail.setSurplusCourseFee(registration.getSurplusCourseFee());
                studentCourseFeeDetail.setStudentRegistrationId(registration.getId());
                studentCourseFeeDetail.setMemo("跨团合班费用转移");
                studentCourseFeeDetail.setOperator(sysUser1.getId());
                studentCourseFeeDetails.add(studentCourseFeeDetail);
            }
        }
        if(studentCourseFeeDetails.size() > 0){
            studentCourseFeeDetailDao.batchInsert(studentCourseFeeDetails);
        }
    }

    private List<CourseSchedule> addStudent(Integer classGroupId, Integer userId, Date date, List<CourseSchedule> courseScheduleList) {
        ClassGroup classGroup = classGroupDao.get(classGroupId);
        ClassGroupStudentMapper classGroupStudentMapper = classGroupStudentMapperDao.findClassStudentMapperByUserIdAndClassGroupId(userId, classGroupId, null);
        if (classGroupStudentMapper != null) {
            classGroupStudentMapper.setStatus(ClassGroupStudentStatusEnum.NORMAL);
            classGroupStudentMapper.setClassGroupId(classGroup.getId());
            classGroupStudentMapperDao.update(classGroupStudentMapper);
        } else {
            classGroupStudentMapper = new ClassGroupStudentMapper();
            classGroupStudentMapper.setMusicGroupId(classGroup.getMusicGroupId());
            classGroupStudentMapper.setClassGroupId(classGroupId);
            classGroupStudentMapper.setUserId(userId);
            classGroupStudentMapper.setCreateTime(date);
            classGroupStudentMapper.setStatus(ClassGroupStudentStatusEnum.NORMAL);
            classGroupStudentMapper.setGroupType(GroupType.MUSIC);
            classGroupStudentMapperDao.insert(classGroupStudentMapper);
        }
        imGroupMemberService.join(classGroupId.longValue(), userId, null, false);
        //2、班级人数调整
//        classGroupDao.updateClassStudentNum(classGroupId.longValue(), 1);
        //3、学生加入新班级未开始课程
        List<CourseSchedule> noStartCoursesByClassGroupId = courseScheduleService.findNoStartCoursesByClassGroupId(classGroupId);
        if (noStartCoursesByClassGroupId != null && noStartCoursesByClassGroupId.size() > 0) {
            courseScheduleList.addAll(noStartCoursesByClassGroupId);
        }
        return courseScheduleList;
    }

    public void addStudents(StudentAddDto studentAddDto, Integer userId) {
        Date nowDate = new Date();

        String musicGroupId = studentAddDto.getStudentRegistration().getMusicGroupId();
        Integer signClassId = studentAddDto.getSignClassId();
        List<CourseSchedule> courseScheduleList = new ArrayList<>();
        if (signClassId != null) {
            addStudent(signClassId, userId, nowDate, courseScheduleList);
        }
        Integer mixClassId = studentAddDto.getMixClassId();
        if (mixClassId != null) {
            addStudent(mixClassId, userId, nowDate, courseScheduleList);
        }
        Integer highClassId = studentAddDto.getHighClassId();
        if (highClassId != null) {
            addStudent(highClassId, userId, nowDate, courseScheduleList);
        }
        String snapClassIds = studentAddDto.getSnapClassIds();
        if (StringUtils.isNotEmpty(snapClassIds)) {
            String[] split = snapClassIds.split(",");
            for (int i = 0; i < split.length; i++) {
                addStudent(Integer.parseInt(split[i]), userId, nowDate, courseScheduleList);
            }
        }
        List<CourseScheduleStudentPayment> courseScheduleStudentPayments = new ArrayList<>();
        for (CourseSchedule courseSchedule : courseScheduleList) {
            CourseScheduleStudentPayment courseScheduleStudentPayment = new CourseScheduleStudentPayment();
            courseScheduleStudentPayment.setGroupType(GroupType.MUSIC);
            courseScheduleStudentPayment.setMusicGroupId(musicGroupId);
            courseScheduleStudentPayment.setCourseScheduleId(courseSchedule.getId());
            courseScheduleStudentPayment.setUserId(userId);
            courseScheduleStudentPayment.setExpectPrice(BigDecimal.ZERO);
            courseScheduleStudentPayment.setClassGroupId(signClassId);
            courseScheduleStudentPayment.setCreateTime(nowDate);
            courseScheduleStudentPayment.setUpdateTime(nowDate);
            courseScheduleStudentPayments.add(courseScheduleStudentPayment);
        }

        if (courseScheduleStudentPayments.size() == 0) {
            return;
        }
        courseScheduleStudentPaymentService.batchInsert(courseScheduleStudentPayments);
    }

    @Override
    public List<StudentRegistration> findClassGroupStu(String musicGroupId, Integer classGroupId) {
        //获取所有声部
        List<Subject> subjectList = subjectService.findAll(new HashMap<>());
        List<StudentRegistration> classGroupStuList = studentRegistrationDao.findClassGroupStu(musicGroupId, classGroupId);
        for (StudentRegistration studentRegistration : classGroupStuList) {
            for (Subject subject : subjectList) {
                if (studentRegistration.getActualSubjectId().equals(subject.getId())) {
                    studentRegistration.setSubjectName(subject.getName());
                    break;
                }
            }
        }
        return classGroupStuList;
    }

    @Transactional(rollbackFor = Exception.class, isolation = Isolation.READ_COMMITTED)
    public void updateCalender(Long calenderDetailId, Integer userId) {
        Date date = new Date();
        MusicGroupPaymentCalenderDetail calenderDetail = musicGroupPaymentCalenderDetailDao.get(calenderDetailId);
        MusicGroupPaymentCalender calender = musicGroupPaymentCalenderService.get(calenderDetail.getMusicGroupPaymentCalenderId());
        MusicGroupStudentFee musicGroupStudentFee = musicGroupStudentFeeDao.findByUser(userId, calender.getMusicGroupId());
        if (calender.getIsGiveMusicNetwork()) {
            //赠送网管课
            musicGroupStudentFee.setRemainNetworkClassTimes(musicGroupStudentFee.getRemainNetworkClassTimes() + 1);
        }
        //更新学生的缴费记录状态
        calenderDetail.setPaymentStatus(PAID_COMPLETED);
        calenderDetail.setActualAmount(calenderDetail.getExpectAmount());
        calenderDetail.setPayTime(date);
        calenderDetail.setUpdateTime(date);
        musicGroupPaymentCalenderDetailDao.update(calenderDetail);

        //更新实际缴费人数
        Integer actualNum = calender.getActualNum() == null ? 0 : calender.getActualNum();
        calender.setActualNum(actualNum + 1);
        calender.setUpdateTime(date);
        musicGroupPaymentCalenderDao.update(calender);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public StudentPaymentOrder updateApplyOrder(StudentPaymentOrder studentPaymentOrder) throws Exception {
        //更新订单状态
        int updateCount = studentPaymentOrderService.update(studentPaymentOrder);
        if (updateCount <= 0) {
            throw new BizException("订单更新失败");
        }
        Date nowDate = new Date();

        //成功报名状态变更
        StudentRegistration studentRegistration = studentRegistrationDao.queryByUserIdAndMusicGroupId(studentPaymentOrder.getUserId(), studentPaymentOrder.getMusicGroupId());

        if (studentRegistration.getPaymentStatus().equals(YES)) {
            return studentPaymentOrder;
        }
        MusicGroupSubjectPlan musicOneSubjectClassPlan = musicGroupSubjectPlanService.getMusicOneSubjectClassPlan(studentRegistration.getMusicGroupId(), studentRegistration.getActualSubjectId());

        if (studentPaymentOrder.getStatus().equals(DealStatusEnum.SUCCESS)) {
            MusicGroup musicGroup = musicGroupDao.getLocked(studentRegistration.getMusicGroupId());

            if (studentRegistration.getTemporaryCourseFee() != null) {
                studentRegistration.setTemporaryCourseFee(new BigDecimal(0));
            }
            studentRegistration.setPaymentStatus(YES);
            studentRegistration.setMusicGroupStatus(StudentMusicGroupStatusEnum.NORMAL);

            List<StudentPaymentOrderDetail> orderDetails = studentPaymentOrderDetailService.getOrderDetail(studentPaymentOrder.getId());

            List<StudentPaymentOrderDetail> allDetails = studentPaymentOrderDetailDao.getOrderDetailByOrderId(studentPaymentOrder.getId());
            BigDecimal courseFee = allDetails.stream().filter(o -> !o.getType().getCode().equals("MUSICAL")).filter(o -> !o.getType().getCode().equals("ACCESSORIES")).map(o -> o.getPrice().subtract(o.getRemitFee() == null ? BigDecimal.ZERO : o.getRemitFee()))
                    .reduce(BigDecimal.ZERO, BigDecimal::add);

            //累加充值金额
            studentRegistration.setSurplusCourseFee(studentRegistration.getSurplusCourseFee().add(courseFee));
            studentRegistrationDao.update(studentRegistration);

            //添加日志
            StudentCourseFeeDetail studentCourseFeeDetail = new StudentCourseFeeDetail();
            studentCourseFeeDetail.setStudentRegistrationId(studentRegistration.getId());
            studentCourseFeeDetail.setAmount(studentPaymentOrder.getExpectAmount());
            studentCourseFeeDetail.setSurplusCourseFee(studentRegistration.getSurplusCourseFee());
            studentCourseFeeDetail.setMemo("充值");
            studentCourseFeeDetail.setOperator(studentPaymentOrder.getUserId());
            studentCourseFeeDetailDao.insert(studentCourseFeeDetail);

            MusicGroupStudentFee musicGroupStudentFee = musicGroupStudentFeeDao.findByUser(studentRegistration.getUserId(), studentRegistration.getMusicGroupId());
            //进行中乐团加入学生缴费
            if (studentRegistration.getTemporaryCourseFee() != null) {
                //关闭待支付订单
                StudentPaymentOrder waitPayOrder = studentPaymentOrderService.findMusicGroupApplyOrderByStatus(studentRegistration.getUserId(), studentRegistration.getMusicGroupId(), DealStatusEnum.WAIT_PAY);
                waitPayOrder.setStatus(DealStatusEnum.CLOSE);
                studentPaymentOrderService.update(waitPayOrder);
                musicGroupStudentFee.setLatestPaidTime(nowDate);
                musicGroupStudentFee.setPaymentStatus(PAID_COMPLETED);
                musicGroupStudentFee.setTemporaryCourseFee(BigDecimal.ZERO);
                musicGroupStudentFee.setUpdateTime(nowDate);
            }
            //插入交易明细
            BigDecimal amount = studentPaymentOrder.getActualAmount();
            SysUserCashAccount cashAccount = sysUserCashAccountService.get(studentRegistration.getUserId());
            //充值
            SysUserCashAccountDetail rechargeDetail = new SysUserCashAccountDetail();
            rechargeDetail.setAmount(amount);
            rechargeDetail.setBalance(cashAccount.getBalance().add(amount));
            rechargeDetail.setComment("缴费前充值");
            rechargeDetail.setCreateTime(nowDate);
            rechargeDetail.setStatus(DealStatusEnum.SUCCESS);
            rechargeDetail.setTransNo(studentPaymentOrder.getTransNo());
            rechargeDetail.setType(PlatformCashAccountDetailTypeEnum.RECHARGE);
            rechargeDetail.setUpdateTime(nowDate);
            rechargeDetail.setUserId(studentRegistration.getUserId());
            rechargeDetail.setChannel(studentPaymentOrder.getPaymentChannel());
            rechargeDetail.setComAmount(studentPaymentOrder.getComAmount());
            rechargeDetail.setPerAmount(studentPaymentOrder.getPerAmount());
            sysUserCashAccountDetailService.insert(rechargeDetail);

            //缴费
            SysUserCashAccountDetail paymentDetail = new SysUserCashAccountDetail();
            paymentDetail.setAmount(amount.negate());
            paymentDetail.setBalance(cashAccount.getBalance());
            paymentDetail.setComment("报名缴费");
            paymentDetail.setCreateTime(nowDate);
            paymentDetail.setStatus(DealStatusEnum.SUCCESS);
            paymentDetail.setTransNo(studentPaymentOrder.getTransNo());
            paymentDetail.setType(PlatformCashAccountDetailTypeEnum.PAY_FEE);
            paymentDetail.setUpdateTime(nowDate);
            paymentDetail.setUserId(studentRegistration.getUserId());
            rechargeDetail.setChannel(studentPaymentOrder.getPaymentChannel());
            if (studentPaymentOrder.getComAmount() != null) {
                rechargeDetail.setComAmount(studentPaymentOrder.getComAmount().negate());
                rechargeDetail.setPerAmount(studentPaymentOrder.getPerAmount().negate());
            }
            sysUserCashAccountDetailService.insert(paymentDetail);

            //销售订单详情
            if (orderDetails.size() > 0) {
                sellOrderService.addOrderDetail2SellOrder(orderDetails, studentPaymentOrder, musicGroup);
            }

            addCalenderDetail(studentPaymentOrder, studentRegistration);

            //三方乐团不发送缴费通知
            if (musicGroup.getOwnershipType() != null && musicGroup.getOwnershipType() == CooperationOrgan.OwnershipType.OWN) {
                //发送缴费成功通知（短信 + push）
                Map<Integer, String> map = new HashMap<>(1);
                map.put(studentPaymentOrder.getUserId(), studentRegistration.getParentsPhone());
                sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.AWSMS,
                        MessageTypeEnum.STUDENT_SMS_PAYMENT_SUCCESS, map, null, 0, "1", "",
                        studentRegistration.getName(), studentPaymentOrder.getActualAmount());
                //push
                Map<Integer, String> map1 = new HashMap<>(1);
                map1.put(studentPaymentOrder.getUserId(), studentPaymentOrder.getUserId().toString());
                sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG,
                        MessageTypeEnum.STUDENT_SMS_PAYMENT_SUCCESS, map1, null, 0, "1", "STUDENT",
                        studentRegistration.getName(), studentPaymentOrder.getActualAmount());
            }
            try {
                //生成课程协议
                contractService.transferMusicGroupCoursesContract(studentRegistration.getUserId(), studentRegistration.getMusicGroupId());
                // 商品协议(租赁时候有)
                StudentPaymentOrderDetail applyOrderMusical = studentPaymentOrderDetailService.findApplyOrderMusical(studentPaymentOrder.getId());
                if (applyOrderMusical != null && applyOrderMusical.getKitGroupPurchaseType() != null && applyOrderMusical.getKitGroupPurchaseType().equals(KitGroupPurchaseTypeEnum.LEASE)) {
                    contractService.transferGoodsContract(studentPaymentOrder.getUserId(), studentPaymentOrder.getMusicGroupId(),
                            applyOrderMusical.getGoodsIdList(), applyOrderMusical.getKitGroupPurchaseType());
                }
            } catch (Exception e) {
                LOGGER.error("协议生成失败", e);
            }
        }


        //减去缴费人数
        if (studentPaymentOrder.getStatus().equals(DealStatusEnum.FAILED)) {
            musicOneSubjectClassPlan.setPaidStudentNum(musicOneSubjectClassPlan.getPaidStudentNum() - 1);
            updateCount = musicGroupSubjectPlanService.update(musicOneSubjectClassPlan);
            if (updateCount <= 0) {
                throw new BizException("减去缴费人数失败");
            }
            if (studentPaymentOrder.getBalancePaymentAmount() != null && studentPaymentOrder.getBalancePaymentAmount().compareTo(BigDecimal.ZERO) > 0) {
                sysUserCashAccountService.updateBalance(studentPaymentOrder.getUserId(), studentPaymentOrder.getBalancePaymentAmount(), PlatformCashAccountDetailTypeEnum.REFUNDS, "报名缴费失败");
            }
            MusicGroup musicGroup = musicGroupDao.get(studentRegistration.getMusicGroupId());
            //三方乐团不发送缴费通知
            if (musicGroup.getOwnershipType() != null && musicGroup.getOwnershipType() == CooperationOrgan.OwnershipType.OWN) {
                String studentApplyUrl = sysConfigDao.findConfigValue(SysConfigService.STUDENT_APPLY_URL) + studentRegistration.getMusicGroupId();
                Map<Integer, String> map = new HashMap<>(1);
                map.put(studentPaymentOrder.getUserId(), studentRegistration.getParentsPhone());
                sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.AWSMS,
                        MessageTypeEnum.STUDENT_SMS_PAYMENT_FAILED, map, null, 0, "1", "",
                        HttpUtil.getSortUrl(studentApplyUrl));
            }
//            sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.JIGUANG,
//                    MessageTypeEnum.STUDENT_SMS_PAYMENT_FAILED,map,null,0,"1",
//                    studentApplyUrl);
        }

        return studentPaymentOrder;
    }


    private boolean addCalenderDetail(StudentPaymentOrder studentPaymentOrder, StudentRegistration studentRegistration) {
        Date nowDate = new Date();
        MusicGroupStudentFee musicGroupStudentFee = new MusicGroupStudentFee();
        musicGroupStudentFee.setLatestPaidTime(nowDate);
        musicGroupStudentFee.setPaymentStatus(PAID_COMPLETED);
        musicGroupStudentFee.setUpdateTime(nowDate);
        musicGroupStudentFee.setContinuousAbsenteeismTimes(0);
        musicGroupStudentFee.setSubjectId(studentRegistration.getActualSubjectId());
        musicGroupStudentFee.setIsLock(0);
        musicGroupStudentFee.setMusicGroupId(studentRegistration.getMusicGroupId());
        musicGroupStudentFee.setUserId(studentRegistration.getUserId());

        String currentMusicGroupId = studentRegistration.getMusicGroupId();

        //缴费详情 calender detail
        MusicGroupPaymentCalender musicGroupRegCalender = musicGroupPaymentCalenderService.findByMusicGroupRegCalender(currentMusicGroupId);
        if (musicGroupRegCalender == null) {
            musicGroupStudentFeeDao.insert(musicGroupStudentFee);
            return true;
        }

        String batchNo = musicGroupRegCalender.getBatchNo();
        Long currentPaymentCalenderId = musicGroupRegCalender.getId();

        List<MusicGroupPaymentCalender> musicGroupPaymentCalenderList = musicGroupPaymentCalenderDao.findByBatchNo(batchNo);

        if (musicGroupRegCalender.getIsGiveMusicNetwork() != null && musicGroupRegCalender.getIsGiveMusicNetwork()) {
            //赠送网管课
            musicGroupStudentFee.setRemainNetworkClassTimes(musicGroupStudentFee.getRemainNetworkClassTimes() + musicGroupPaymentCalenderList.size());
        }
        musicGroupStudentFeeDao.insert(musicGroupStudentFee);

        for (MusicGroupPaymentCalender musicGroupPaymentCalender : musicGroupPaymentCalenderList) {
            if (currentPaymentCalenderId.longValue() == musicGroupPaymentCalender.getId()) {
                // 更新实际缴费人数
                if (musicGroupPaymentCalender.getActualNum() == null) {
                    musicGroupPaymentCalender.setActualNum(1);
                } else {
                    musicGroupPaymentCalender.setActualNum(musicGroupPaymentCalender.getActualNum() + 1);
                }
            }
            if (musicGroupPaymentCalender.getExpectNum() == null) {
                musicGroupPaymentCalender.setExpectNum(1);
            } else {
                musicGroupPaymentCalender.setExpectNum(musicGroupPaymentCalender.getExpectNum() + 1);
            }
            musicGroupPaymentCalender.setUpdateTime(nowDate);
        }
        if (musicGroupPaymentCalenderList.size() > 0) {
            musicGroupPaymentCalenderDao.batchUpdate(musicGroupPaymentCalenderList);
        }

        List<String> orderDetailTypes = studentPaymentOrderDetailDao.getOrderDetailType(studentPaymentOrder.getId());
        List<MusicGroupPaymentCalenderCourseSettings> courseSettings = musicGroupPaymentCalenderCourseSettingsDao.getWithPaymentCalender(musicGroupRegCalender.getId());
        BigDecimal courseTotalPrice = courseSettings.stream().filter(e -> orderDetailTypes.contains(e.getCourseType().getCode())).map(MusicGroupPaymentCalenderCourseSettings::getCourseCurrentPrice).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal optionalCourseFee = courseSettings.stream().filter(MusicGroupPaymentCalenderCourseSettings::getIsStudentOptional).filter(e -> orderDetailTypes.contains(e.getCourseType().getCode())).map(MusicGroupPaymentCalenderCourseSettings::getCourseCurrentPrice).reduce(BigDecimal.ZERO, BigDecimal::add);

        List<MusicGroupPaymentStudentCourseDetail> musicGroupPaymentStudentCourseDetails = new ArrayList<>();

        for (MusicGroupPaymentCalender musicGroupPaymentCalender : musicGroupPaymentCalenderList) {
            MusicGroupPaymentCalenderDetail musicGroupPaymentCalenderDetail = new MusicGroupPaymentCalenderDetail();
            musicGroupPaymentCalenderDetail.setMusicGroupPaymentCalenderId(musicGroupPaymentCalender.getId());
            musicGroupPaymentCalenderDetail.setUserId(studentPaymentOrder.getUserId());
            musicGroupPaymentCalenderDetail.setResponsibleUserId(musicGroupPaymentCalender.getOperator());

            if (currentPaymentCalenderId.longValue() == musicGroupPaymentCalender.getId()) {
                musicGroupPaymentCalenderDetail.setExpectAmount(courseTotalPrice);
                if (studentPaymentOrder.getCourseRemitFee() != null && (studentPaymentOrder.getCourseRemitFee().compareTo(BigDecimal.ZERO) > 0)) {
                    musicGroupPaymentCalenderDetail.setActualAmount(optionalCourseFee);
                } else {
                    musicGroupPaymentCalenderDetail.setActualAmount(courseTotalPrice);
                }
                musicGroupPaymentCalenderDetail.setPaymentStatus(PAID_COMPLETED);
                musicGroupPaymentCalenderDetail.setPayTime(nowDate);
                musicGroupPaymentCalenderDetail.setPaymentOrderId(studentPaymentOrder.getId());
                musicGroupPaymentCalenderDetail.setUseInCourse(0);
                musicGroupPaymentCalenderDetail.setOpen(1);
            } else {
                musicGroupPaymentCalenderDetail.setExpectAmount(musicGroupPaymentCalender.getPaymentAmount());
                musicGroupPaymentCalenderDetail.setPaymentStatus(MusicGroupStudentFee.PaymentStatus.NON_PAYMENT);
            }
            musicGroupPaymentCalenderDetail.setUserStatus(null);
            musicGroupPaymentCalenderDetail.setDeadlinePaymentDate(musicGroupPaymentCalender.getDeadlinePaymentDate());
            musicGroupPaymentCalenderDetail.setStartPaymentDate(musicGroupPaymentCalender.getStartPaymentDate());
            musicGroupPaymentCalenderDetail.setCreateTime(nowDate);
            musicGroupPaymentCalenderDetail.setUpdateTime(nowDate);

            musicGroupPaymentCalenderDetailDao.insert(musicGroupPaymentCalenderDetail);

            List<MusicGroupPaymentCalenderCourseSettings> courseSettingsList = musicGroupPaymentCalenderCourseSettingsDao
                    .getWithPaymentCalender(musicGroupPaymentCalender.getId());
            for (MusicGroupPaymentCalenderCourseSettings courseSetting : courseSettingsList) {
                if (musicGroupRegCalender.getPayUserType().equals(MusicGroupPaymentCalender.PayUserType.STUDENT)
                        && !orderDetailTypes.contains(courseSetting.getCourseType().getCode())) {
                    continue;
                }
                if (courseSetting.getCourseTotalMinuties() == null || courseSetting.getCourseTotalMinuties() == 0) {
                    continue;
                }
                MusicGroupPaymentStudentCourseDetail musicGroupPaymentStudentCourseDetail = new MusicGroupPaymentStudentCourseDetail();
                musicGroupPaymentStudentCourseDetail.setMusicGroupPaymentCalenderId(musicGroupPaymentCalender.getId());
                musicGroupPaymentStudentCourseDetail.setMusicGroupPaymentCalenderDetailId(musicGroupPaymentCalenderDetail.getId());
                musicGroupPaymentStudentCourseDetail.setUserId(studentPaymentOrder.getUserId());
                musicGroupPaymentStudentCourseDetail.setCourseType(courseSetting.getCourseType());
                musicGroupPaymentStudentCourseDetail.setTotalCourseMinutes(courseSetting.getCourseTotalMinuties());
                musicGroupPaymentStudentCourseDetail.setUsedCourseMinutes(0);
                musicGroupPaymentStudentCourseDetail.setCreateTime(nowDate);
                musicGroupPaymentStudentCourseDetail.setUpdateTime(nowDate);

                musicGroupPaymentStudentCourseDetails.add(musicGroupPaymentStudentCourseDetail);
            }
        }

        if (musicGroupPaymentStudentCourseDetails.size() > 0) {
            musicGroupPaymentStudentCourseDetailDao.batchInsert(musicGroupPaymentStudentCourseDetails);
        }
        return true;
    }

    @Override
    public List<StudentRegistration> findMusicGroupNoClassGroupStudent(String musicGroupId, Integer actualSubjectId) {
        //获取所有声部
        List<Subject> subjectList = subjectService.findAll(new HashMap<>());
        List<StudentRegistration> classGroupStuList = studentRegistrationDao.findMusicGroupNoClassGroupStudent(musicGroupId, actualSubjectId);
        for (StudentRegistration studentRegistration : classGroupStuList) {
            for (Subject subject : subjectList) {
                if (studentRegistration.getActualSubjectId().equals(subject.getId())) {
                    studentRegistration.setSubjectName(subject.getName());
                    break;
                }
            }
        }
        return classGroupStuList;
    }

    @Override
    public List<StudentRegistration> findStudentListByIdList(List<Long> idList) {
        return studentRegistrationDao.findStudentListByIdList(idList);
    }

    @Override
    public int batchInsert(List<StudentRegistration> studentRegistrationList) {
        return studentRegistrationDao.batchInsert(studentRegistrationList);
    }

    @Override
    public StudentRegistration findStudentByClassGroupIdAndUserId(Integer userId, Integer classGroupId) {
        return studentRegistrationDao.findStudentByClassGroupIdAndUserId(userId, classGroupId);
    }

    @Override
    public List<StudentRegistration> findMusicGroupStudent(String musicGroupId, String actualSubjectId) {
        List<Subject> subjectList = subjectService.findAll(new HashMap<>());
        List<StudentRegistration> musicGroupStudents = studentRegistrationDao.findMusicGroupStudent(musicGroupId, actualSubjectId);
        for (StudentRegistration musicGroupStudent : musicGroupStudents) {
            for (Subject subject : subjectList) {
                if (musicGroupStudent.getActualSubjectId().equals(subject.getId())) {
                    musicGroupStudent.setSubjectName(subject.getName());
                }
            }
        }
        return musicGroupStudents;
    }

    @Override
    public List<StudentRegistration> findStudentListByUserIdList(String musicGroupId, List<Integer> userIdList) {
        return studentRegistrationDao.findStudentListByUserIdList(musicGroupId, userIdList);
    }

    @Override
    public int openPayment(String ids) throws IOException {
        if (StringUtils.isNotEmpty(ids)) {
            //发送短信通知
            List<Long> list = JSONObject.parseArray(JSONObject.toJSONString(Arrays.asList(ids.split(","))), Long.class);
            MusicGroup musicGroup = musicGroupDao.findMusicGroup(list);
            MusicGroupPaymentCalender regCalender = musicGroupPaymentCalenderService.findByMusicGroupRegCalender(musicGroup.getId());
            if (regCalender != null && regCalender.getPayUserType().equals(MusicGroupPaymentCalender.PayUserType.STUDENT)) {
                regCalender.setStatus(MusicGroupPaymentCalender.PaymentCalenderStatusEnum.OPEN);
                musicGroupPaymentCalenderService.update(regCalender);
            }

            //三方乐团不发送缴费通知
            if (musicGroup.getOwnershipType() != null && musicGroup.getOwnershipType() == CooperationOrgan.OwnershipType.OWN) {
                List<StudentRegistration> registrations = studentRegistrationDao.findStudentListByIdList(list);
                String configValue = sysConfigDao.findConfigValue(SysConfigService.STUDENT_APPLY_URL);
                HashMap<Integer, String> receivers = new HashMap<>(registrations.size());
                registrations.forEach(e -> {
                    receivers.put(e.getUserId(), e.getParentsPhone());
                });
                sysMessageService.batchSendMessage(MessageSenderPluginContext.MessageSender.AWSMS,
                        MessageTypeEnum.SMS_STUDENT_OPEN_PAYMENT, receivers, null, 0, null, "",
                        musicGroup.getName(), HttpUtil.getSortUrl(configValue + musicGroup.getId()));
            }
        }
        return studentRegistrationDao.batchOpenPay(ids, PaymentStatusEnum.OPEN);
    }

    @Override
    public List<StudentRegistration> queryStudentByMusicGroupId(String musicGroupId) {
        return studentRegistrationDao.queryStudentByMusicGroupId(musicGroupId);
    }

    @Override
    public List<Map<Integer, String>> findParentId(String parentPhones) {
        return studentRegistrationDao.findParentId(parentPhones);
    }

    @Override
    @Transactional
    public StudentRegistration updateStudent(StudentRegistration studentRegistration) {
        if(StringUtils.isBlank(studentRegistration.getCertificateType())){
            studentRegistration.setCertificateType(CertificateTypeEnum.IDENTITY.getCode());
        }
        StudentRegistration student = get(studentRegistration.getId());
        if (student == null) {
            throw new BizException("用户注册信息不存在，无法更新");
        }
        student.setParentsName(studentRegistration.getParentsName());
        student.setIdCardNo(studentRegistration.getIdCardNo());
        update(student);
        studentRegistrationDao.updateUser(student.getUserId(), student.getParentsName(), student.getIdCardNo(), studentRegistration.getCertificateType());
        // 添加用户电子签章账户
        if(CertificateTypeEnum.IDENTITY.getCode().equals(studentRegistration.getCertificateType())){
            contractService.register(student.getUserId(), student.getParentsName(), student.getIdCardNo(), student.getParentsPhone());
        }
        return student;
    }

    @Override
    public StudentRegistration queryUserByPhone(String mobile) {
        return studentRegistrationDao.queryUserByPhone(mobile);
    }

    @Override
    public List<StudentRegistration> findMusicGroupStuNoClassType(String musicGroupId, Long classGroupId, ClassGroupTypeEnum type, String subjectId) {
        List<StudentRegistration> students = studentRegistrationDao.findMusicGroupStudent(musicGroupId, subjectId);
        List<Subject> subjectList = subjectService.findAll(new HashMap<>());

        Map<CourseSchedule.CourseScheduleType, Integer> courseTypeCourseDurationMap = new HashMap<>();
        Map<CourseSchedule.CourseScheduleType, List<CourseSchedule>> typeCourseMap = new HashMap<>();
        if (Objects.nonNull(classGroupId)) {
            List<CourseSchedule> classGroupNotStartCourse = courseScheduleDao.findCoursesByClassGroupId(classGroupId.intValue(), CourseStatusEnum.NOT_START);
            typeCourseMap = classGroupNotStartCourse.stream().collect(Collectors.groupingBy(CourseSchedule::getType));
            for (Map.Entry<CourseSchedule.CourseScheduleType, List<CourseSchedule>> typeCoursesEntry : typeCourseMap.entrySet()) {
                int totalCourseDuration = 0;
                for (CourseSchedule courseSchedule : typeCoursesEntry.getValue()) {
                    //课程时长
                    int courseDuration = DateUtil.minutesBetween(courseSchedule.getStartClassTime(), courseSchedule.getEndClassTime());
                    totalCourseDuration += courseDuration;
                }
                courseTypeCourseDurationMap.put(typeCoursesEntry.getKey(), totalCourseDuration);
            }
        }

        List<ClassGroupStudentMapper> classGroupStudentMappers = classGroupStudentMapperDao.findMusicGroupClassGroupByType(musicGroupId, type);
        Iterator<StudentRegistration> iterator = students.iterator();
        while (iterator.hasNext()) {
            StudentRegistration student = iterator.next();

            boolean courseMinutesNotEnough = false;

            for (Map.Entry<CourseSchedule.CourseScheduleType, List<CourseSchedule>> courseScheduleTypeListEntry : typeCourseMap.entrySet()) {
                //当前课程类型总课程时长
                Integer typeCourseDuration = courseTypeCourseDurationMap.get(courseScheduleTypeListEntry.getKey());

                String batchNo = musicGroupPaymentStudentCourseDetailDao.getUnUseBatchNoWithStudentAndCourseTypeAndCourseMinutes(musicGroupId, student.getUserId(), courseScheduleTypeListEntry.getKey(), null);

                List<MusicGroupPaymentStudentCourseDetail> musicGroupPaymentStudentCourseDetails = musicGroupPaymentStudentCourseDetailDao.getUnUseWithStudentAndCourseTypeAndCourseMinutes(batchNo, student.getUserId(), courseScheduleTypeListEntry.getKey());
                int totalCourseMinutes = musicGroupPaymentStudentCourseDetails.stream().mapToInt(MusicGroupPaymentStudentCourseDetail::getTotalCourseMinutes).reduce(0, Integer::sum);
                if (CollectionUtils.isEmpty(musicGroupPaymentStudentCourseDetails) || totalCourseMinutes < typeCourseDuration) {
                    iterator.remove();
                    courseMinutesNotEnough = true;
                    break;
                }
            }

            if (courseMinutesNotEnough) {
                continue;
            }

            for (Subject subject : subjectList) {
                if (student.getActualSubjectId().equals(subject.getId())) {
                    student.setSubjectName(subject.getName());
                    break;
                }
            }
            if (type.equals(ClassGroupTypeEnum.SNAP)) continue;
            for (ClassGroupStudentMapper classGroupStudentMapper : classGroupStudentMappers) {
                if (student.getUserId().equals(classGroupStudentMapper.getUserId())) {
                    iterator.remove();
                    break;
                }
            }
        }
        return students;
    }

    @Override
    public List<Subject> findMusicGroupAllStudentSubjects(String musicGroupId) {
        return studentRegistrationDao.findMusicGroupAllStudentSubjects(musicGroupId);
    }

    @Override
    public StudentMusicDetailDto getStudentDetail(Integer studentId) {
        return studentRegistrationDao.getStudentDetail(studentId);
    }

    @Override
    public List<StudentPaymentOrderDetail> getStudentApplyDetail(Integer studentId, String musicGroupId) {
        SubjectChange studentLastChange = subjectChangeDao.getStudentLastChange(studentId, musicGroupId);
        List<StudentPaymentOrderDetail> details = new ArrayList<>();
        if (studentLastChange != null) {
            StudentPaymentOrderDetail course = new StudentPaymentOrderDetail();
            course.setType(OrderDetailTypeEnum.COURSE);
            course.setPrice(studentLastChange.getChangeCourseFee());
            details.add(course);
            if (studentLastChange.getChangeMusical() != null) {
                StudentPaymentOrderDetail musical = new StudentPaymentOrderDetail();
                musical.setType(OrderDetailTypeEnum.MUSICAL);
                musical.setKitGroupPurchaseType(studentLastChange.getKitGroupPurchaseType());
                musical.setPrice(studentLastChange.getChangeMusicalPrice());
                musical.setGoodsList(goodsDao.findGoodsByIds(studentLastChange.getChangeMusical().toString()));
                details.add(musical);
            }

            if (studentLastChange.getChangeAccessories() != null) {
                StudentPaymentOrderDetail accessories = new StudentPaymentOrderDetail();
                accessories.setType(OrderDetailTypeEnum.ACCESSORIES);
                accessories.setPrice(studentLastChange.getChangeAccessoriesPrice());
                accessories.setGoodsList(goodsDao.findGoodsByIds(studentLastChange.getChangeAccessories()));
                details.add(accessories);
            }
        }
        if (details.size() <= 0) {
            details = studentPaymentOrderDetailDao.getStudentApplyDetail(studentId, musicGroupId);
        }
        return details;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public StudentRegistration changeStudentSubject(Integer studentId, String musicGroupId, Integer originalSubjectId, Integer changeSubjectId) {
        studentDao.lockUser(studentId);
        //1、更换学生的声部
        StudentRegistration studentRegistration = studentRegistrationDao.getStudentRegister(musicGroupId, studentId);
        studentRegistration.setActualSubjectId(changeSubjectId);
        studentRegistrationDao.update(studentRegistration);

        //2、减去原声部的已缴费数量,加上现声部的缴费人数
        boolean updateFlag = false;
        for (int i = 0; i < 10; i++) {
            MusicGroupSubjectPlan originalSubjectPlan = musicGroupSubjectPlanService.getMusicOneSubjectClassPlan(musicGroupId, originalSubjectId);
            int originalPaidNum = originalSubjectPlan.getPaidStudentNum() == null ? 0 : originalSubjectPlan.getPaidStudentNum();
            int originalPaidCount = 1;
            if (originalPaidNum > 0) {
                originalSubjectPlan.setPaidStudentNum(originalPaidNum - 1);
                originalPaidCount = musicGroupSubjectPlanService.update(originalSubjectPlan);
            }
            MusicGroupSubjectPlan changeSubjectPlan = musicGroupSubjectPlanService.getMusicOneSubjectClassPlan(musicGroupId, changeSubjectId);
            int changelPaidNum = changeSubjectPlan.getPaidStudentNum() == null ? 0 : changeSubjectPlan.getPaidStudentNum();
            changeSubjectPlan.setPaidStudentNum(changelPaidNum + 1);
            int changePaidCount = musicGroupSubjectPlanService.update(changeSubjectPlan);
            if (originalPaidCount > 0 && changePaidCount > 0) {
                updateFlag = true;
                break;
            }
        }
        if (!updateFlag) {
            throw new BizException("系统繁忙，更新学生声部失败，请重试");
        }
        return studentRegistration;
    }

    @Override
    public BigDecimal getClassGroupCourseExpectPrice(List<Integer> classGroupIds) {
        List<CourseScheduleStudentPayment> classGroupNoStartCourse = courseScheduleStudentPaymentService.getClassGroupNoStartCourse(classGroupIds);
        return classGroupNoStartCourse.stream().map(CourseScheduleStudentPayment::getExpectPrice).reduce(BigDecimal.ZERO, BigDecimal::add);
    }

    @Override
    @Transactional(rollbackFor = Exception.class, isolation = Isolation.READ_COMMITTED)
    public BigDecimal updateUserSurplusCourseFee(Integer userId, String musicGroupId, BigDecimal amount, String memo, Integer operatorId) {
        StudentRegistration studentRegistration = studentRegistrationDao.lockWithUserAndMusic(userId, musicGroupId);
        if (Objects.isNull(studentRegistration)) {
            LOGGER.error("学员可用排课余额更新失败{}：学员注册信息不存在", amount);
            return BigDecimal.ZERO;
        }

        if (BigDecimal.ZERO.compareTo(amount) > 0 && amount.abs().compareTo(studentRegistration.getSurplusCourseFee()) > 0) {
            amount = studentRegistration.getSurplusCourseFee().negate();
        }

        studentRegistration.setSurplusCourseFee(studentRegistration.getSurplusCourseFee().add(amount));

        if (BigDecimal.ZERO.compareTo(amount) == 0) {
            return BigDecimal.ZERO;
        }

        StudentCourseFeeDetail studentCourseFeeDetail = new StudentCourseFeeDetail();
        studentCourseFeeDetail.setStudentRegistrationId(studentRegistration.getId());
        studentCourseFeeDetail.setAmount(amount);
        studentCourseFeeDetail.setSurplusCourseFee(studentRegistration.getSurplusCourseFee());
        studentCourseFeeDetail.setMemo(memo);
        studentCourseFeeDetail.setOperator(operatorId);
        studentCourseFeeDetailDao.insert(studentCourseFeeDetail);

        studentRegistrationDao.update(studentRegistration);
        return amount;
    }

	@Override
	public List<StudentMusicGroupDto> queryStudentMusicGroupInfo(Integer userId) {
		return studentRegistrationDao.queryStudentMusicGroupInfo(userId);
	}

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean delReg(Long id) {
        StudentRegistration studentRegistration = studentRegistrationDao.get(id);
        MusicGroupSubjectPlan subjectPlan = musicGroupSubjectPlanDao.findSubjectPlan(studentRegistration.getMusicGroupId(), studentRegistration.getSubjectId());
        int delNum = studentRegistrationDao.delete(id);
        subjectPlan.setApplyStudentNum(subjectPlan.getApplyStudentNum() - 1);
        int updateNum = musicGroupSubjectPlanDao.update(subjectPlan);
        if (delNum <= 0 || updateNum <= 0) {
            throw new BizException("删除失败，请重试");
        }
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean batchDelRegs(String musicGroupId, List<Integer> userIds) {
        List<StudentRegistration> registrations = studentRegistrationDao.findStudentListByUserIdList(musicGroupId, userIds);
        for (StudentRegistration registration : registrations) {
            if(registration.getPaymentStatus().equals(PaymentStatusEnum.OPEN)||registration.getPaymentStatus().equals(PaymentStatusEnum.YES)){
                throw new BizException(registration.getName()+"（"+registration.getPaymentStatus().getDesc()+"），不能删除");
            }
        }
        if (registrations.size() <= 0) {
            throw new BizException("删除的学员不存在，请核查");
        }
        Map<Integer, List<StudentRegistration>> regMap = registrations.stream().collect(Collectors.groupingBy(StudentRegistration::getSubjectId));
        //更新声部信息
        for (Map.Entry<Integer, List<StudentRegistration>> regEntry : regMap.entrySet()) {
            MusicGroupSubjectPlan subjectPlan = musicGroupSubjectPlanDao.findSubjectPlan(musicGroupId, regEntry.getKey());
            subjectPlan.setApplyStudentNum(subjectPlan.getApplyStudentNum() - regEntry.getValue().size());
            int updateNum = musicGroupSubjectPlanDao.update(subjectPlan);
            if (updateNum <= 0) {
                throw new BizException("声部信息更新失败");
            }
        }
        //删除注册信息
        List<Long> ids = registrations.stream().map(StudentRegistration::getId).collect(Collectors.toList());
        int delNum = studentRegistrationDao.batchDelete(ids);
        if (delNum <= 0) {
            throw new BizException("学员删除失败");
        }
        return true;
    }

    @Override
    public List<StudentRegistration> getMusicGroupStuReBack(String musicGroupId) {
        courseScheduleStudentPaymentService.updateCourseActualPrice(Arrays.asList(musicGroupId), null, GroupType.MUSIC);
        return this.findMusicGroupStudent(musicGroupId,null);
    }
}
