package cn.hnthyy.thmz.service.impl.his.mz;

import cn.hnthyy.thmz.Utils.CloneUtil;
import cn.hnthyy.thmz.Utils.DateUtil;
import cn.hnthyy.thmz.common.Constants;
import cn.hnthyy.thmz.entity.MzException;
import cn.hnthyy.thmz.entity.his.mz.*;
import cn.hnthyy.thmz.entity.thmz.*;
import cn.hnthyy.thmz.enums.OrderStatusEnum;
import cn.hnthyy.thmz.enums.YesNoEnum;
import cn.hnthyy.thmz.mapper.his.mz.*;
import cn.hnthyy.thmz.mapper.thmz.ConfigMapper;
import cn.hnthyy.thmz.mapper.thmz.ReceiptMapper;
import cn.hnthyy.thmz.mapper.thmz.ReqrecRequestRelationMapper;
import cn.hnthyy.thmz.mapper.thmz.WindowsMapper;
import cn.hnthyy.thmz.pageDto.MzyReqrecPageDto;
import cn.hnthyy.thmz.service.his.mz.*;
import cn.hnthyy.thmz.service.his.zd.ZdUnitCodeService;
import cn.hnthyy.thmz.service.thmz.*;
import cn.hnthyy.thmz.vo.ThmzmxsrParamsVo;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;

@Service
public class MzyReqrecServiceImpl implements MzyReqrecService {
    @SuppressWarnings("all")
    @Autowired
    private MzyReqrecMapper mzyReqrecMapper;
    @SuppressWarnings("all")
    @Autowired
    private MzVisitTableMapper mzVisitTableMapper;
    @SuppressWarnings("all")
    @Autowired
    private WindowsMapper windowsMapper;
    @SuppressWarnings("all")
    @Autowired
    private MzPatientMiMapper mzPatientMiMapper;
    @SuppressWarnings("all")
    @Autowired
    private MzyZdChargeTypeMapper mzyZdChargeTypeMapper;
    @SuppressWarnings("all")
    @Autowired
    private MzyRequestMapper mzyRequestMapper;
    @SuppressWarnings("all")
    @Autowired
    private ReceiptMapper receiptMapper;
    @SuppressWarnings("all")
    @Autowired
    private MzfzPatientOrderMapper mzfzPatientOrderMapper;
    @SuppressWarnings("all")
    @Autowired
    private MzReceiptSerialMapper mzReceiptSerialMapper;
    @SuppressWarnings("all")
    @Autowired
    private ReqrecRequestRelationMapper reqrecRequestRelationMapper;
    @SuppressWarnings("all")
    @Autowired
    private MzZdWorkTimeMapper mzZdWorkTimeMapper;
    @SuppressWarnings("all")
    @Autowired
    private CovidPojoMapper covidPojoMapper;
    @SuppressWarnings("all")
    @Autowired
    private ConfigMapper configMapper;
    @Autowired
    private MzyRequestService mzyRequestService;
    @Autowired
    private MzSerialNoService mzSerialNoService;
    @Autowired
    private MzfzConfigService mzfzConfigService;
    @Autowired
    private ConfigService configService;
    @Autowired
    private EmployeeService employeeService;
    @Autowired
    private MessageService messageService;
    @Autowired
    private ZdUnitCodeService zdUnitCodeService;
    @Autowired
    private MzyZdChargeTypeService mzyZdChargeTypeService;
    @Autowired
    private OrderStatusChangeService orderStatusChangeService;
    @Autowired
    private HolidaysService holidaysService;
    @Autowired
    private MzVisitTableService mzVisitTableService;
//    @Autowired
//    private HaiCiAdapterService haiCiAdapterService;

    //无需新冠调查的科室
    private List notCovid=Arrays.asList("1040200","1040000","1040100","1070000","1260000");
    @Value("${lxbdcwjUrl}")
    private String lxbdcwjUrl;

    //驾驶员id集合
    private List<String> patientIds = Arrays.asList(new String[]{"422429-4", "400758-4", "399163-4", "400429-4", "377323-4", "309261-4", "134402-4", "209695-4"});
    //不做重复挂号控制的号别
    private List<String> jsyChargeTypes = Arrays.asList(new String[]{"26", "27"});

    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 36000, rollbackFor = Exception.class)
    public int saveMzyReqrec(MzyReqrecPageDto mzyReqrecPageDto) throws MzException {
        MzyReqrec mzyReqrec = mzyReqrecPageDto.getMzyReqrec();
        MzPatientMi mzPatientMi = mzPatientMiMapper.selectByPatientId(mzyReqrec.getPatientId());
        if (mzPatientMi == null) {
            throw new MzException("当前挂号的病人信息不存在，请先保存病人信息！");
        }
        Windows windows = windowsMapper.selectLastWindowsByUserIdCode(mzyReqrec.getOpId(),null);
        if (windows == null) {
            throw new MzException("当前操作人未设置窗口号，请先设置！");
        }
        MzyZdChargeType mzyZdChargeType = mzyRequestService.calculateAddition(mzyReqrecPageDto.getMzyRequestId(),mzPatientMi.getBirthDay());
        if (mzyZdChargeType == null) {
            throw new MzException("当前号别不存在，请先设置！");
        }
        MzyRequest mzyRequest = mzyRequestMapper.selectMzyRequestById(mzyReqrecPageDto.getMzyRequestId());
        //covidManage(mzyReqrec, mzPatientMi, mzyRequest);


        int times = getTimes(mzyReqrec, mzPatientMi);
        int serialNo = mzSerialNoService.getMzSerialNo();
        Date now = new Date();
        MzVisitTable newMzVisitTable = getMzVisitTable(mzyReqrecPageDto, mzyReqrec, mzPatientMi, windows, times, serialNo, now);
        mzVisitTableMapper.insertMzVisitTable(newMzVisitTable);
        fomartReqrec(mzyReqrec, mzPatientMi, windows, mzyZdChargeType, times, serialNo, now, mzyRequest);
        BigDecimal tempFee =BigDecimal.ZERO;
        if(mzyReqrec.getOthFee()!=null){
            tempFee=tempFee.add(mzyReqrec.getOthFee());
        }
        if(mzyReqrec.getReqFee()!=null){
            tempFee=tempFee.add(mzyReqrec.getReqFee());
        }
        if(mzyReqrec.getClinicFee()!=null){
            tempFee=tempFee.add(mzyReqrec.getClinicFee());
        }
        if(tempFee.compareTo(mzyReqrecPageDto.getTotalFee())!=0){
            throw new MzException("当前病人已经挂号失败，实缴费用与实际费用不一致!");
        }
        //不需要做重复挂号的校验id集合 ，只有入库的时候需要该参数
        mzyReqrec.setCanRepeatedly((jsyChargeTypes.contains(mzyReqrec.getChargeType()) && patientIds.contains(mzyReqrec.getPatientId())) ? YesNoEnum.YES.code : YesNoEnum.NO.code);
        int num = mzyReqrecMapper.insertMzyReqrec(mzyReqrec);
        if (num <= 0) {
            throw new MzException("当前病人已经挂号成功，请不要重复挂号!");
        }
        MzfzPatientOrder mzfzPatientOrder = getMzfzPatientOrder(mzyReqrec, mzPatientMi, times, serialNo, now);
        mzfzPatientOrderMapper.insertMzfzPatientOrder(mzfzPatientOrder);
        MzPatientMi updateMzPatientMi = new MzPatientMi();
        updateMzPatientMi.setPatientId(mzPatientMi.getPatientId());
        updateMzPatientMi.setTimes(times);
        updateMzPatientMi.setLvDate(mzyReqrec.getRequestDay() == null ? now : mzyReqrec.getRequestDay());
        mzPatientMiMapper.updateMzPatientMi(updateMzPatientMi);
        ReqrecRequestRelation reqrecRequestRelation = new ReqrecRequestRelation(mzyRequest.getId(), serialNo);
        reqrecRequestRelationMapper.insertReqrecRequestRelation(reqrecRequestRelation);
        //发送挂号成功MQ
        orderStatusChangeService.orderStatusChange(mzyReqrec.getPatientId() + "_" + mzyReqrec.getTimes() + "," + OrderStatusEnum.REGISTRATION_SUCCESS.code);
        if (sendAlarmMessage(mzyRequest)) return 1;
        return 1;
    }

    /**
     * 获取新的缴费次数
     * @param mzyReqrec
     * @param mzPatientMi
     * @return
     */
    private int getTimes(MzyReqrec mzyReqrec, MzPatientMi mzPatientMi) {
        MzVisitTable lastMzVisitTable = mzVisitTableService.queryLastMzVisitTableByPatientId(mzyReqrec.getPatientId());
        int times = 0;
        if (lastMzVisitTable != null && lastMzVisitTable.getTimes() != null && lastMzVisitTable.getTimes() > times) {
            times = lastMzVisitTable.getTimes();
        }
        if (mzPatientMi.getTimes() != null && mzPatientMi.getTimes() > times) {
            times = mzPatientMi.getTimes();
        }
        times++;
        return times;
    }

//    /**
//     * 新冠拦截手机挂号
//     * @param mzyReqrec
//     * @param mzPatientMi
//     * @param mzyRequest
//     * @throws MzException
//     */
//    private void covidManage(MzyReqrec mzyReqrec, MzPatientMi mzPatientMi, MzyRequest mzyRequest) throws MzException {
//        //手机挂号 除了儿科与急诊科外都需要做新冠调查
//        if(Constants.BRZZJF_CODE.equals(mzyReqrec.getOpId()) && !notCovid.contains(mzyRequest.getUnitCode())){
//            CovidPojo covidPojo = covidPojoMapper.selectLastCovidPojoByIdcard(mzPatientMi.getSocialNo(), mzPatientMi.getPatientId());
//            if (covidPojo == null) {
//                haiCiAdapterService.commonMessageNotice(mzPatientMi.getIcCardNo(),"{\"data\":{\"first\":{\"color\":\"#FF0000\",\"value\":\"很抱歉，您的暂时无法进行挂号，详情如下:\"},\"keyword1\":{\"color\":\"#173177\",\"value\":\"\"},\"keyword2\":{\"color\":\"#173177\",\"value\":\"挂号失败\"},\"keyword2\":{\"color\":\"#173177\",\"value\":\"\"},\"keyword3\":{\"color\":\"#173177\",\"value\":\"您还未做新型冠状病毒感染流行病学史问卷,请前往填写\"},\"remark\":{\"color\":\"#FF0000\",\"value\":\"\"}},\"miniprogram\":{\"appid\":\"\",\"pagepath\":\"\"},\"template_id\":\"PEDh0niCG93uQsY5P6XS-J3haoB8sn4Pq-ZSrEZ6gGo\",\"touser\":\"\",\"url\":\""+lxbdcwjUrl+mzyReqrec.getPatientId()+"\"}",new Date());
//                throw new MzException("当前挂号的病人还未做新型冠状病毒感染流行病学史问卷,请告知病人及时前往填写！");
//            }
//            boolean temperature =false;
//            if(covidPojo.getTemperature()==2){
//                BigDecimal feverNumber = new BigDecimal(covidPojo.getFeverNumber());
//                temperature= feverNumber.compareTo(BigDecimal.valueOf(37.3)) >= 0;
//            }
//            if (temperature|| covidPojo.getItem1() != 14 || covidPojo.getItem2() != 24 || covidPojo.getItem3() != 32 || covidPojo.getItem4() != 42 ) {
//                throw new MzException("当前病人新型冠状病毒感染流行病学史问卷未通过，请挂发热门诊并告知病人");
//            }
//        }
//    }




    /**
     * 新冠拦截手机挂号
     * @param patientId
     * @param unitCode
     * @throws MzException
     */
    @Override
    public void covidManageForHaici(String patientId, String unitCode) throws MzException {
        // 除了儿科与急诊科外都需要做新冠调查
        if(!notCovid.contains(unitCode)){
            MzPatientMi mzPatientMi = mzPatientMiMapper.selectByPatientId(patientId);
            if (mzPatientMi == null) {
                throw new MzException("当前挂号的病人信息不存在，请先保存病人信息！");
            }
            CovidPojo covidPojo = covidPojoMapper.selectLastCovidPojoByIdcard(mzPatientMi.getSocialNo(), mzPatientMi.getPatientId());
            if (covidPojo == null) {
                //haiCiAdapterService.commonMessageNotice(mzPatientMi.getIcCardNo(),"{\"data\":{\"first\":{\"color\":\"#FF0000\",\"value\":\"很抱歉，您的暂时无法进行挂号，详情如下:\"},\"keyword1\":{\"color\":\"#173177\",\"value\":\"\"},\"keyword2\":{\"color\":\"#173177\",\"value\":\"挂号失败\"},\"keyword2\":{\"color\":\"#173177\",\"value\":\"\"},\"keyword3\":{\"color\":\"#173177\",\"value\":\"您还未做新型冠状病毒感染流行病学史问卷,请前往填写\"},\"remark\":{\"color\":\"#FF0000\",\"value\":\"\"}},\"miniprogram\":{\"appid\":\"\",\"pagepath\":\"\"},\"template_id\":\"PEDh0niCG93uQsY5P6XS-J3haoB8sn4Pq-ZSrEZ6gGo\",\"touser\":\"\",\"url\":\""+lxbdcwjUrl+patientId+"\"}",new Date());
                throw new MzException(-1,"当前挂号的病人还未做新型冠状病毒感染流行病学史问卷,请告知病人及时前往填写！");
            }
            boolean temperature =false;
            if(covidPojo.getTemperature()==2){
                BigDecimal feverNumber = new BigDecimal(covidPojo.getFeverNumber());
                temperature= feverNumber.compareTo(BigDecimal.valueOf(37.3)) >= 0;
            }
            if (temperature|| covidPojo.getItem1() != 14 || covidPojo.getItem2() != 24 || covidPojo.getItem3() != 32 || covidPojo.getItem4() != 42 ) {
                throw new MzException(-2,"当前病人新型冠状病毒感染流行病学史问卷未通过，请挂发热门诊并告知病人");
            }
        }
    }

    @Override
    public int modifyMzyReqrec(MzyReqrec mzyReqrec) {
        return mzyReqrecMapper.updateMzyReqrec(mzyReqrec);
    }

    /**
     * 发送号表剩余号数预警消息
     *
     * @param mzyRequest
     * @return
     */
    private boolean sendAlarmMessage(MzyRequest mzyRequest) {
        try {
            Config config = configService.queryUserByKey(Constants.ALARM_NUM_KEY);
            if (config == null) {
                return true;
            }
            if (mzyRequest.getLeftNum() <= Integer.valueOf(config.getConfigValue())) {
                config = configService.queryUserByKey(Constants.ALARM_USER_KEY);
                if (config == null || StringUtils.isBlank(config.getConfigValue())) {
                    return true;
                }
                String[] arr = config.getConfigValue().split(",");
                if (arr == null || arr.length == 0) {
                    return true;
                }
                List<Employee> employees = employeeService.queryByCodes(Arrays.asList(arr));
                if (employees == null || employees.size() == 0) {
                    return true;
                }
                String codes = null;
                for (Employee employee : employees) {
                    if (codes == null) {
                        codes = employee.getCodeRs();
                    } else {
                        codes += "," + employee.getCodeRs();
                    }
                }
                if (codes != null) {
                    StringBuffer sbf = new StringBuffer("警告：日期【");
                    sbf.append(DateUtil.fomart(mzyRequest.getRequestDay(), "yyyy-MM-dd")).append("】");
                    sbf.append("科室【").append(zdUnitCodeService.queryDeptNameByIdInCache(mzyRequest.getUnitCode())).append("】");
                    if (StringUtils.isNotBlank(mzyRequest.getDoctorCode())) {
                        Employee employee = employeeService.queryByUserCode(mzyRequest.getDoctorCode());
                        if (employee != null) {
                            sbf.append("医生【").append(employee.getEmployeeName()).append("】");
                        }
                    }
                    if (StringUtils.isNotBlank(mzyRequest.getAmpm())) {
                        MzZdWorkTime mzZdWorkTime = mzZdWorkTimeMapper.selectMzZdWorkTimeByCode(mzyRequest.getAmpm());
                        if (mzZdWorkTime != null) {
                            sbf.append("号段【").append(mzZdWorkTime.getName()).append("】");
                        }
                    }
                    if (StringUtils.isNotBlank(mzyRequest.getChargeType())) {
                        MzyZdChargeType mzyZdChargeType1 = mzyZdChargeTypeService.queryByCode(mzyRequest.getChargeType());
                        if (mzyZdChargeType1 != null) {
                            sbf.append("号别【").append(mzyZdChargeType1.getName()).append("】");
                        }
                    }
                    sbf.append("剩余号数").append(mzyRequest.getLeftNum()).append("低于预警值，请及时关注处理！");
                    messageService.sendWxMessage(codes, sbf.toString());
                }
            }
            return false;
        } catch (Exception e) {
            return true;
        }
    }


    private MzfzPatientOrder getMzfzPatientOrder(MzyReqrec mzyReqrec, MzPatientMi mzPatientMi, int times, int serialNo, Date now) throws MzException {
        MzfzPatientOrder mzfzPatientOrder = new MzfzPatientOrder();
        mzfzPatientOrder.setPatientId(mzyReqrec.getPatientId());
        mzfzPatientOrder.setTimes(times);
        mzfzPatientOrder.setName(mzPatientMi.getName());
        mzfzPatientOrder.setDeptCode(mzyReqrec.getUnitCode());
        mzfzPatientOrder.setDoctorCode(mzyReqrec.getDoctorCode());
        mzfzPatientOrder.setGhNo(mzfzConfigService.getGhNo());
        mzfzPatientOrder.setVisitDate(mzyReqrec.getRequestDay() == null ? now : mzyReqrec.getRequestDay());
        mzfzPatientOrder.setSlowFlag(YesNoEnum.NO.code);
        mzfzPatientOrder.setSerialNo(serialNo);
        mzfzPatientOrder.setReqType(mzyReqrec.getChargeType());
        mzfzPatientOrder.setReqOrder(mzyReqrec.getReqOrder());
        mzfzPatientOrder.setAmpm(mzyReqrec.getAmpm());
        return mzfzPatientOrder;
    }

    /**
     *
     * @param mzyReqrec 挂号对象
     * @param mzPatientMi 门诊病人
     * @param windows 窗口记录
     * @param mzyZdChargeType 收费类型
     * @param times 挂号次数
     * @param serialNo 流水号
     * @param now 当前时间
     * @param mzyRequest 挂号记录
     * @throws MzException
     */
    private void fomartReqrec(MzyReqrec mzyReqrec, MzPatientMi mzPatientMi, Windows windows, MzyZdChargeType mzyZdChargeType, int times, int serialNo, Date now, MzyRequest mzyRequest) throws MzException {
        mzyReqrec.setTimes(times);
        mzyReqrec.setName(mzPatientMi.getName());
        Integer reqOrder = mzyRequestService.getReqOrder(mzyRequest);
        mzyReqrec.setReqOrder(reqOrder);

        mzyReqrec.setOpDay(now);
        mzyReqrec.setVisitedMark(YesNoEnum.NO.code);
        mzyReqrec.setCancelMark(YesNoEnum.NO.code);
        mzyReqrec.setWindowsNo(windows.getWindowsNo());
        mzyReqrec.setSerialNo(serialNo);
        mzyReqrec.setDoctorCode(mzyRequest.getDoctorCode() == null ? "" : mzyRequest.getDoctorCode());
        mzyReqrec.setReqType("0");
        if (mzyReqrec.getRequestDay() == null) {
            mzyReqrec.setRequestDay(now);
        }
        mzyReqrec.setPlusMark(YesNoEnum.NO.code);
        mzyReqrec.setPrintFlag(YesNoEnum.NO.code.toString());
        mzyReqrec.setDcountNo(YesNoEnum.NO.code);
        mzyReqrec.setPrintDcountNo(YesNoEnum.NO.code);
        //节假日减免挂号费，不收挂号费
        if (Constants.BRZZJF_CODE.equals(mzyReqrec.getOpId()) && notPayGhFee(mzyReqrec.getUnitCode(), mzyReqrec.getRequestDay(), mzyRequest.getAmpm())) {
            mzyReqrec.setOthFee(BigDecimal.ZERO);
            mzyReqrec.setClinicFee(BigDecimal.ZERO);
            mzyReqrec.setReqFee(BigDecimal.ZERO);
        } else {
            BigDecimal checkFee=BigDecimal.ZERO;
//            if(mzyRequest.getCheckFee()!=null){
//                checkFee=mzyRequest.getCheckFee();
//            }
            if(mzyZdChargeType.getOthFee()!=null){
                checkFee=checkFee.add(mzyZdChargeType.getOthFee());
            }
            mzyReqrec.setOthFee(checkFee);
            mzyReqrec.setClinicFee(mzyZdChargeType.getClinicFee());
            mzyReqrec.setReqFee(mzyZdChargeType.getReqFee());
        }
        mzyReqrec.setBrochureFee(BigDecimal.ZERO);

        mzyReqrec.setDeptNo("01");
    }

    private MzVisitTable getMzVisitTable(MzyReqrecPageDto mzyReqrecPageDto, MzyReqrec mzyReqrec, MzPatientMi mzPatientMi, Windows windows, int times, int serialNo, Date now) {
        MzVisitTable newMzVisitTable = new MzVisitTable();
        newMzVisitTable.setPatientId(mzyReqrec.getPatientId());
        newMzVisitTable.setTimes(times);
        newMzVisitTable.setVisitDeptCode(mzyReqrec.getUnitCode());
        newMzVisitTable.setDoctorCode(mzyReqrec.getDoctorCode());
        newMzVisitTable.setVisitDate(now);
        newMzVisitTable.setReqFee(mzyReqrec.getReqFee());
        newMzVisitTable.setOpId(mzyReqrec.getOpId());
        newMzVisitTable.setOpDay(now);
        newMzVisitTable.setReqDeptCode(mzyReqrec.getUnitCode());
        newMzVisitTable.setReqDoctor(mzyReqrec.getDoctorCode());
        newMzVisitTable.setWindowsNo(windows.getWindowsNo());
        newMzVisitTable.setFirstOrNot(times == 1 ? YesNoEnum.NO.code : YesNoEnum.YES.code);
        newMzVisitTable.setReceiveFlag(YesNoEnum.YES.code);
        newMzVisitTable.setResponceType(mzyReqrecPageDto.getResponceType());
        newMzVisitTable.setDwmc(mzPatientMi.getAddress());
        newMzVisitTable.setGhSerialNo(serialNo);
        return newMzVisitTable;
    }

    @Override
    public Integer countMzyReqrec(MzyReqrecPageDto mzyReqrecPageDto) {
        //清洗挂号数据
        // mzyReqrecMapper.updateCanCelMark();
        if(StringUtils.isBlank(mzyReqrecPageDto.getTableName())){
            mzyReqrecPageDto.setTableName("mzy_reqrec");
        }
        return mzyReqrecMapper.countMzyReqrec(mzyReqrecPageDto);
    }

    @Override
    public List<MzyReqrec> queryMzyReqrecWithPage(MzyReqrecPageDto mzyReqrecPageDto) {
        if(StringUtils.isBlank(mzyReqrecPageDto.getTableName())){
            mzyReqrecPageDto.setTableName("mzy_reqrec");
        }
        return mzyReqrecMapper.selectMzyReqrecWithPage(mzyReqrecPageDto);
    }

    @Override
    public List<MzyReqrec> queryAllCancel() {
        return mzyReqrecMapper.selectAllCancel();
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 36000, rollbackFor = Exception.class)
    public int modifyMzyReqrec(MzyReqrec mzyReqrec, User tokenUser) {
        if (YesNoEnum.YES.code.equals(mzyReqrec.getCancelMark())) {
            //此时是退号，需要把就诊信息也标记成退号
            MzVisitTable mzVisitTable = new MzVisitTable();
            mzVisitTable.setPatientId(mzyReqrec.getPatientId());
            mzVisitTable.setTimes(mzyReqrec.getTimes());
            mzVisitTable.setCancelMark(mzyReqrec.getCancelMark());
            mzVisitTableMapper.updateMzVisitTable(mzVisitTable);
            //将原记录查出，并设置相关字段为负数，新增该记录，用于费用统计
            MzyReqrec dbMzyReqrec = mzyReqrecMapper.selectMzyReqrecByPatientIdAndTimes(mzyReqrec.getPatientId(), mzyReqrec.getTimes());
            ReqrecRequestRelation reqrecRequestRelation = reqrecRequestRelationMapper.selectReqrecRequestRelation(dbMzyReqrec.getSerialNo());
            if (reqrecRequestRelation != null && reqrecRequestRelation.getRequestId() != null) {
                mzyRequestMapper.updateLeftNumById(reqrecRequestRelation.getRequestId());
            }
            dbMzyReqrec.setTimes(-dbMzyReqrec.getTimes());
            dbMzyReqrec.setReqFee(BigDecimal.ZERO.subtract(dbMzyReqrec.getReqFee()));
            dbMzyReqrec.setClinicFee(BigDecimal.ZERO.subtract(dbMzyReqrec.getClinicFee()));
            dbMzyReqrec.setOthFee(BigDecimal.ZERO.subtract(dbMzyReqrec.getOthFee()));
            dbMzyReqrec.setSerialNo(-dbMzyReqrec.getSerialNo());
            dbMzyReqrec.setCancelMark(mzyReqrec.getCancelMark());
            dbMzyReqrec.setOpDay(new Date());
            dbMzyReqrec.setOpId(tokenUser.getUserIdCode());
            dbMzyReqrec.setDcountNo(YesNoEnum.NO.code);
            dbMzyReqrec.setClosingDate(null);
            if (!Constants.BYJZ.equals(dbMzyReqrec.getPaymode())) {
                dbMzyReqrec.setPaymode(Constants.CASH);
            }

            mzyReqrecMapper.insertMzyReqrec(dbMzyReqrec);
            reqrecRequestRelationMapper.selectReqrecRequestRelation(dbMzyReqrec.getSerialNo());
        }
        return mzyReqrecMapper.updateMzyReqrec(mzyReqrec);
    }

    @Override
    public MzyReqrec queryMzyReqrecByPatientIdAndTimes(String patientId, Integer times) {
        return mzyReqrecMapper.selectMzyReqrecByPatientIdAndTimes(patientId, times);
    }

    @Override
    public MzyReqrec queryMzyReqrecBySerialNo(Integer serialNo) {
        return mzyReqrecMapper.selectMzyReqrecBySerialNo(serialNo);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 36000, rollbackFor = Exception.class)
    public MzyReqrec chargeFeeForByjz(Integer serialNo, String paymode, String opId) throws MzException {
        if (serialNo==null) {
          throw new MzException("需要退费重收的流水号不能为空");
        }
        if (StringUtils.isBlank(paymode)) {
            throw new MzException("收款方式不能为空");
        }
        if (Constants.BYJZ.equals(paymode)) {
            throw new MzException("新收款方式不能为本院记账");
        }
        if (StringUtils.isBlank(opId)) {
            throw new MzException("操作员不能为空");
        }
        MzyReqrec dbMzyReqrec=mzyReqrecMapper.selectMzyReqrecBySerialNo(serialNo);
        if(dbMzyReqrec==null){
            throw new MzException("流水号对应的挂号信息不存在");
        }
        if(!Constants.BYJZ.equals(dbMzyReqrec.getPaymode())){
            throw new MzException("当前挂号记录非本院记账支付，无法进行退费重收操作！");
        }
        MzPatientMi mzPatientMi = mzPatientMiMapper.selectByPatientId(dbMzyReqrec.getPatientId());
        if (mzPatientMi == null) {
            throw new MzException("当前病人信息不存在");
        }
        MzVisitTable mzVisitTable=mzVisitTableMapper.selectByPatientIdAndTimes(dbMzyReqrec.getPatientId(),dbMzyReqrec.getTimes(),"mz_visit_table");
        if(mzVisitTable==null){
            throw new MzException("流水号对应的病人就诊记录信息不存在");
        }
        //退费之前记账信息，需要把就诊信息也标记成退号
        MzVisitTable updateMzVisitTable = new MzVisitTable();
        updateMzVisitTable.setPatientId(dbMzyReqrec.getPatientId());
        updateMzVisitTable.setTimes(dbMzyReqrec.getTimes());
        updateMzVisitTable.setCancelMark(dbMzyReqrec.getCancelMark());
        mzVisitTableMapper.updateMzVisitTable(updateMzVisitTable);
        int times = getTimes(dbMzyReqrec, mzPatientMi);
        int newSerialNo = mzSerialNoService.getMzSerialNo();
        Date now = new Date();
        mzVisitTable.setTimes(times);
        mzVisitTable.setOpDay(now);
        mzVisitTable.setOpId(opId);
        mzVisitTable.setGhSerialNo(newSerialNo);
        mzVisitTableMapper.insertMzVisitTable(mzVisitTable);
        //复制新记录
        MzyReqrec newMzyReqrec = CloneUtil.clone(dbMzyReqrec);
        //更新老记录为退号
        dbMzyReqrec.setCancelMark(YesNoEnum.YES.code);
        mzyReqrecMapper.updateMzyReqrec(dbMzyReqrec);
        //将原记录退费
        dbMzyReqrec.setTimes(-dbMzyReqrec.getTimes());
        dbMzyReqrec.setReqFee(BigDecimal.ZERO.subtract(dbMzyReqrec.getReqFee()));
        dbMzyReqrec.setClinicFee(BigDecimal.ZERO.subtract(dbMzyReqrec.getClinicFee()));
        dbMzyReqrec.setOthFee(BigDecimal.ZERO.subtract(dbMzyReqrec.getOthFee()));
        dbMzyReqrec.setSerialNo(-dbMzyReqrec.getSerialNo());
        dbMzyReqrec.setOpDay(now);
        dbMzyReqrec.setOpId(opId);
        dbMzyReqrec.setDcountNo(YesNoEnum.NO.code);
        dbMzyReqrec.setClosingDate(null);
        dbMzyReqrec.setPrintClosingDate(null);
        dbMzyReqrec.setPrintDcountNo(YesNoEnum.NO.code);
        mzyReqrecMapper.insertMzyReqrec(dbMzyReqrec);
        //入库新的挂号记录
        newMzyReqrec.setTimes(times);
        newMzyReqrec.setOpDay(now);
        newMzyReqrec.setOpId(opId);
        newMzyReqrec.setDcountNo(YesNoEnum.NO.code);
        newMzyReqrec.setClosingDate(null);
        newMzyReqrec.setPrintClosingDate(null);
        newMzyReqrec.setPrintDcountNo(YesNoEnum.NO.code);
        newMzyReqrec.setPaymode(paymode);
        newMzyReqrec.setSerialNo(newSerialNo);
        mzyReqrecMapper.insertMzyReqrec(newMzyReqrec);
        return newMzyReqrec;
    }

    @Override
    public MzyReqrec queryLastMzyReqrecByPatientId(String patientId) {
        return mzyReqrecMapper.selectLastMzyReqrecByPatientId(patientId);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 36000, rollbackFor = Exception.class)
    public int printMzyReqrecRecept(MzyReqrec mzyReqrec) throws MzException {
        //有时候发票打印失败，需要补打，补打不增加发票号码
        boolean isReprint = StringUtils.isNotBlank(mzyReqrec.getReceiptBill()) && mzyReqrec.getReceiptBill().trim().length() == 8;
        MzyReqrec newMzyReqrec = new MzyReqrec();
        newMzyReqrec.setPatientId(mzyReqrec.getPatientId());
        newMzyReqrec.setTimes(mzyReqrec.getTimes());
        Receipt receipt = null;
        String printer = Constants.BRZZJF_CODE.equals(mzyReqrec.getOpId()) ? mzyReqrec.getPrinterId() : mzyReqrec.getOpId();
        if (!isReprint) {
            receipt = receiptMapper.selectByUserIdCode(printer);
            if (receipt == null || StringUtils.isBlank(receipt.getReceiptCurrent())) {
                throw new MzException("用户id=" + mzyReqrec.getOpId() + "没有可用的发票,请先维护发票。");
            }
            newMzyReqrec.setReceiptBill(receipt.getReceiptCurrent());
            mzyReqrec.setReceiptBill(receipt.getReceiptCurrent());
        }
        newMzyReqrec.setPrinterId(mzyReqrec.getPrinterId());
        int num = mzyReqrecMapper.updateMzyReqrec(newMzyReqrec);
        if (receipt == null) {
            return num;
        }
        //维护发票号码
        if (receipt.getReceiptCurrent() == receipt.getReceiptEnd()) {
            //此时发票号已经用完，当前发票号是最后一个
            receipt.setReceiptCurrent(null);
        } else {
            Integer temp = Integer.valueOf(receipt.getReceiptCurrent()) + 1;
            receipt.setReceiptCurrent(temp.toString());
        }
        receipt.setUpdateDate(new Date());
        return receiptMapper.updateReceipt(receipt);
    }

    @Override
    public List<Map<String, Object>> queryMzhbCount(ThmzmxsrParamsVo thmzmxsrParamsVo) {
        if (YesNoEnum.YES.equals(thmzmxsrParamsVo.getHisData())) {
            thmzmxsrParamsVo.setFirstTableName("mzy_reqrec_b");
        } else {
            thmzmxsrParamsVo.setFirstTableName("mzy_reqrec");
        }
        return mzyReqrecMapper.selectMzhbCount(thmzmxsrParamsVo);
    }

    @Override
    public List<Map<String, Object>> countAndAmountMzyReqrec(MzyReqrecPageDto mzyReqrecPageDto) {
        return mzyReqrecMapper.countAndAmountMzyReqrec(mzyReqrecPageDto);
    }

    @Override
    public MzyReqrec queryMzyReqrecByAgtordnum(String psordnum, String agtordnum,String tableName) {
        if(tableName==null){
            tableName="mzy_reqrec";
        }
        return mzyReqrecMapper.selectMzyReqrecByAgtordnum(psordnum, agtordnum,tableName);
    }

    @Override
    public boolean notPayGhFee(String unitCode, Date requestDayD, String ampm) {
        //驾驶员体检，周末和节假日挂号费正常收费，不减免挂号费
        if (Constants.JSYTJJX.equals(unitCode)) {
            return false;
        }
        Calendar cal = Calendar.getInstance();
        cal.setTime(requestDayD);
        //设置了免费
        Config config= configMapper.selectUserByKey("weekend_fee");
        if ((config!=null && YesNoEnum.YES.code.toString().equals(config.getConfigValue()))
                && ((cal.get(Calendar.DAY_OF_WEEK) == Calendar.SATURDAY && Constants.PM.equals(ampm)) || cal.get(Calendar.DAY_OF_WEEK) == Calendar.SUNDAY)) {
            return true;
        }
        List<Holidays> holidaysList = holidaysService.queryHolidaysByDate(requestDayD);
        if (holidaysList != null && holidaysList.size() > 0) {
            Holidays holidays = holidaysList.get(0);
            //如果开始时间段是上午，那么应该包含下午和全天
            List<String> beginAmpms = new ArrayList<>();
            beginAmpms.add(holidays.getBeginAmpm());
            if (Constants.AM.equals(holidays.getBeginAmpm())) {
                beginAmpms.add(Constants.PM);
                beginAmpms.add(Constants.DAY);
            }
            //如果结束时间段是下午，那么应该包含上午和全天
            List<String> endAmpms = new ArrayList<>();
            endAmpms.add(holidays.getEndAmpm());
            if (Constants.PM.equals(holidays.getBeginAmpm())) {
                endAmpms.add(Constants.AM);
                endAmpms.add(Constants.DAY);
            }
            if ((holidays.getBeginDate().equals(requestDayD) && beginAmpms.contains(ampm))
                    || (holidays.getEndDate().equals(requestDayD) && endAmpms.contains(ampm))
                    || (requestDayD.after(holidays.getBeginDate()) && requestDayD.before(holidays.getEndDate()))) {
                return true;
            }
        }
        return false;
    }
}
