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.common.SpringUtil;
import cn.hnthyy.thmz.entity.MzException;
import cn.hnthyy.thmz.entity.his.*;
import cn.hnthyy.thmz.entity.his.mz.*;
import cn.hnthyy.thmz.entity.his.zd.ZdChargeItem;
import cn.hnthyy.thmz.entity.thmz.Discount;
import cn.hnthyy.thmz.entity.thmz.ReceiptSerialFee;
import cn.hnthyy.thmz.entity.thmz.Windows;
import cn.hnthyy.thmz.enums.*;
import cn.hnthyy.thmz.mapper.his.*;
import cn.hnthyy.thmz.mapper.his.mz.*;
import cn.hnthyy.thmz.mapper.thmz.WindowsMapper;
import cn.hnthyy.thmz.pageDto.MzChargeDetailPageDto;
import cn.hnthyy.thmz.service.his.*;
import cn.hnthyy.thmz.service.his.mz.*;
import cn.hnthyy.thmz.service.his.zd.ZdChargeItemService;
import cn.hnthyy.thmz.service.his.zd.ZdUnitCodeService;
import cn.hnthyy.thmz.service.thmz.DiscountService;
import cn.hnthyy.thmz.service.thmz.OrderStatusChangeService;
import cn.hnthyy.thmz.service.thmz.TsmzService;
import cn.hnthyy.thmz.vo.MzDepositFileVo;
import cn.hnthyy.thmz.vo.MzPrescriptionVo;
import cn.hnthyy.thmz.vo.ThmzmxsrParamsVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.lang3.StringUtils;
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 java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Service
public class MzChargeDetailServiceImpl implements MzChargeDetailService {
    @SuppressWarnings("all")
    @Autowired
    private MzChargeDetailMapper mzChargeDetailMapper;
    @Autowired
    private MzYjReqService mzYjReqService;
    @Autowired
    private JcJyItemChargeService jcJyItemChargeService;
    @Autowired
    private MzPatientMiService mzPatientMiService;
    @Autowired
    private ZdChargeItemService zdChargeItemService;
    @Autowired
    private MzZdSupplyChargeService mzZdSupplyChargeService;
    @Autowired
    private JyZdItemService jyZdItemService;
    @Autowired
    private JyZdTubeChargeService jyZdTubeChargeService;
    @Autowired
    private MzSerialNoService mzSerialNoService;
    @Autowired
    private MzDrugWinService mzDrugWinService;
    @Autowired
    private MzYshConfigService mzYshConfigService;
    @Autowired
    private YpConfigService ypConfigService;
    @Autowired
    private MzDepositFileService mzDepositFileService;
    @Autowired
    private MzReceiptSerialService mzReceiptSerialService;
    @Autowired
    private ZdUnitCodeService zdUnitCodeService;
    @Autowired
    private EmployeeService employeeService;
    @Autowired
    private YpZdDictService ypZdDictService;
    @Autowired
    private OrderStatusChangeService orderStatusChangeService;
    @Autowired
    private MzVisitTableService mzVisitTableService;
    @Autowired
    private DiscountService discountService;
    @SuppressWarnings("all")
    @Autowired
    private MzDepositFileMapper mzDepositFileMapper;
    @SuppressWarnings("all")
    @Autowired
    private MzReceiptSerialMapper mzReceiptSerialMapper;
    @SuppressWarnings("all")
    @Autowired
    private MzPatientMiMapper mzPatientMiMapper;
    @SuppressWarnings("all")
    @Autowired
    private WindowsMapper windowsMapper;
    @SuppressWarnings("all")
    @Autowired
    private MzYpFydlMapper mzYpFydlMapper;
    @SuppressWarnings("all")
    @Autowired
    private MzVisitTableMapper mzVisitTableMapper;
    @SuppressWarnings("all")
    @Autowired
    private MzYjReqMapper mzYjReqMapper;
    @SuppressWarnings("all")
    @Autowired
    private YpMzFytjMapper ypMzFytjMapper;
    @SuppressWarnings("all")
    @Autowired
    private JcZdItemMapper jcZdItemMapper;
    @SuppressWarnings("all")
    @Autowired
    private MzBaRecordMapper mzBaRecordMapper;
    @SuppressWarnings("all")
    @Autowired
    private MzBlRecordMapper mzBlRecordMapper;
    @SuppressWarnings("all")
    @Autowired
    private YpBaseYfMapper ypBaseYfMapper;
    @SuppressWarnings("all")
    @Autowired
    private MzChargeDetailYbMapper mzChargeDetailYbMapper;
    @Autowired
    private TsmzService tsmzService;

    @Override
    public int countMzChargeDetail(MzChargeDetailPageDto mzChargeDetailPageDto) {
        mzChargeDetailPageDto.setTableName("mz_charge_detail");
        Integer num = mzChargeDetailMapper.countMzChargeDetail(mzChargeDetailPageDto);
        if (num == null || num == 0) {
            mzChargeDetailPageDto.setTableName("mz_charge_detail_b");
            num = mzChargeDetailMapper.countMzChargeDetail(mzChargeDetailPageDto);
        }
        return num;
    }

    @Override
    public List<MzChargeDetail> queryMzChargeDetailWithPage(MzChargeDetailPageDto mzChargeDetailPageDto) {
        mzChargeDetailPageDto.setTableName("mz_charge_detail");
        String receiptSerialTableName = "mz_receipt_serial";
        List<MzChargeDetail> mzChargeDetailList = mzChargeDetailMapper.selectMzChargeDetailWithPage(mzChargeDetailPageDto);
        if (mzChargeDetailList == null || mzChargeDetailList.size() == 0) {
            mzChargeDetailPageDto.setTableName("mz_charge_detail_b");
            receiptSerialTableName = "mz_receipt_serial_b";
            mzChargeDetailList = mzChargeDetailMapper.selectMzChargeDetailWithPage(mzChargeDetailPageDto);
            if (mzChargeDetailList == null || mzChargeDetailList.size() == 0) {
                return mzChargeDetailList;
            }
        }
        for (MzChargeDetail mzChargeDetail : mzChargeDetailList) {
            MzChargeDetail temp = mzChargeDetailMapper.selectWarnDeptAndDoctor(mzChargeDetail.getPatientId(), mzChargeDetail.getTimes(), mzChargeDetailPageDto.getTableName());
            mzChargeDetail.setWarnDept(temp.getWarnDept());
            mzChargeDetail.setDoctorCode(temp.getDoctorCode());
            mzChargeDetail.setPrintFlag(temp.getPrintFlag());
            if (PayMarkEnum.CHARGED.code.equals(mzChargeDetailPageDto.getMzChargeDetail().getPayMark())) {
                List<MzReceiptSerial> mzReceiptSerials = mzReceiptSerialMapper.selectReceiptDetails(mzChargeDetail.getPatientId(), mzChargeDetail.getTimes(), mzChargeDetail.getReceiptNo(), receiptSerialTableName);
                if (mzReceiptSerials != null && mzReceiptSerials.size() > 0) {
                    MzReceiptSerial mzReceiptSerial = mzReceiptSerials.get(0);
                    //此时发票号为空，判断收费类型，如果是Y，（说明是本院记账或者单病种缴费），不允许打印发票 如果其他类型，说明非本院记账，可以打印 故设置打印标记为未打印
                    if (StringUtils.isBlank(mzReceiptSerial.getReceiptBill())) {
                        if (Constants.BYJZ.equals(mzReceiptSerial.getChequeType()) || Constants.DBZJF_CODE.equals(mzReceiptSerial.getOperatorId())) {
                            mzChargeDetail.setPrintFlag("-" + YesNoEnum.YES.code.toString());
                        } else {
                            mzChargeDetail.setPrintFlag(YesNoEnum.NO.code.toString());
                        }
                        //此时发票号为8位，说明已经打印了
                    } else if (mzReceiptSerial.getReceiptBill().length() == 8) {
                        mzChargeDetail.setPrintFlag(YesNoEnum.YES.code.toString());
                        //此时发票号大于8 ，只有本院记账和手机缴费会大于8 ，手机缴费的原始操作人是99999，故判断操作人即可
                    } else if (mzReceiptSerial.getReceiptBill().length() > 8) {
                        if (Constants.BRZZJF_CODE.equals(mzReceiptSerial.getOperatorId())) {
                            mzChargeDetail.setPrintFlag(YesNoEnum.NO.code.toString());
                        } else {
                            mzChargeDetail.setPrintFlag("-" + YesNoEnum.YES.code.toString());
                        }
                    }
                }
            }
        }
        return mzChargeDetailList;

    }
//
//    @Override
//    public List<MzChargeDetail> queryMzChargeDetail(MzChargeDetailPageDto mzChargeDetailPageDto) {
//        return mzChargeDetailMapper.selectMzChargeDetail(mzChargeDetailPageDto);
//    }

//    @Override
//    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 36000, rollbackFor = Exception.class)
//    public int saveFullMzChargeDetail(MzChargeDetail mzChargeDetail) throws MzException {
//        List<MzChargeDetail> mzChargeDetails = getMzChargeDetails(mzChargeDetail);
//        if (saveMzChargeDetail(mzChargeDetails)) {
//            return 0;
//        }
//        mzChargeDetail.setPayMark(PayMarkEnum.WAIT_CHARGE.code);
//        mzChargeDetail.setPrintFlag(YesNoEnum.NO.code.toString());
//        mzChargeDetail.setReceiptNo(1);
//        mzChargeDetailMapper.updatePayMakAndPrintFlag(mzChargeDetail);
//        MzYjReq updateMzYjReq = new MzYjReq();
//        updateMzYjReq.setPatientId(mzChargeDetail.getPatientId());
//        updateMzYjReq.setTimes(mzChargeDetail.getTimes());
//        updateMzYjReq.setPayMark(mzChargeDetail.getPayMark());
//        updateMzYjReq.setReceiptNo(1);
//        mzYjReqService.modifyMzYjReq(updateMzYjReq);
//        return mzChargeDetails.size();
//    }

//    @Override
//    public List<Map<String, Object>> queryUnPaidChargeDetail(String patientId) {
//        return mzChargeDetailMapper.selectUnPaidChargeDetail(patientId);
//    }

    /**
     * 将未缴费的处方转成完整的收费明细 只能看不会入库
     *
     * @param mzChargeDetail
     * @return
     */
    @Override
    public MzChargeDetail unPaidToFullChargeDetail(MzChargeDetail mzChargeDetail) throws MzException {
        MzVisitTable mzVisitTable = mzVisitTableMapper.selectByPatientIdAndTimes(mzChargeDetail.getPatientId(), mzChargeDetail.getTimes(), "mz_visit_table");
        if (mzVisitTable == null) {
            throw new MzException("当前病人就诊基础资料【MzVisitTable】不存在，请检查");
        }
        Integer receiptNo = mzVisitTable.getReceiptNo() + 1;
        List<MzChargeDetail> mzChargeDetails = getMzChargeDetails(mzChargeDetail, YesNoEnum.YES, receiptNo);
        if (mzChargeDetails == null || mzChargeDetails.size() == 0) {
            return null;
        }
        MzChargeDetail returnMzChargeDetail = new MzChargeDetail();
        returnMzChargeDetail.setSerialNo(0);
        returnMzChargeDetail.setPatientId(mzChargeDetail.getPatientId());
        returnMzChargeDetail.setTimes(mzChargeDetail.getTimes());
        returnMzChargeDetail.setAmount(BigDecimal.ZERO);
        returnMzChargeDetail.setNotDiscountAmount(BigDecimal.ZERO);
        for (MzChargeDetail md : mzChargeDetails) {
            if (StringUtils.isBlank(returnMzChargeDetail.getName())) {
                returnMzChargeDetail.setName(md.getName());
            }
            if (returnMzChargeDetail.getReceiptNo() == null) {
                returnMzChargeDetail.setReceiptNo(md.getReceiptNo());
            }
            if (StringUtils.isBlank(returnMzChargeDetail.getDoctorCode())) {
                returnMzChargeDetail.setDoctorCode(md.getDoctorCode());
            }
            if (StringUtils.isBlank(returnMzChargeDetail.getWarnDept())) {
                returnMzChargeDetail.setWarnDept(md.getWarnDept());
            }
            if (returnMzChargeDetail.getPriceTime() == null) {
                returnMzChargeDetail.setPriceTime(md.getPriceTime());
            }
            BigDecimal unitPrice = md.getUnitPrice() == null ? BigDecimal.ZERO : md.getUnitPrice().setScale(2, BigDecimal.ROUND_HALF_UP);
            if (!Constants.TC.equals(md.getBillItemCode()) && Constants.ZY_GROUP_NO.equals(md.getGroupNo()) && BigDecimal.ZERO.compareTo(unitPrice) == 0) {
                unitPrice = BigDecimal.valueOf(0.01D);
                md.setUnitPrice(unitPrice);
            }
            returnMzChargeDetail.setAmount(returnMzChargeDetail.getAmount().add(unitPrice.multiply(BigDecimal.valueOf(md.getQuantity() == null ? 1D : md.getQuantity())).multiply(BigDecimal.valueOf(md.getDrugWin() == null ? 1D : md.getDrugWin()))));
            returnMzChargeDetail.setNotDiscountAmount(returnMzChargeDetail.getNotDiscountAmount().add((md.getOrigPrice() == null ? BigDecimal.ZERO : md.getOrigPrice()).multiply(BigDecimal.valueOf(md.getQuantity() == null ? 1D : md.getQuantity())).multiply(BigDecimal.valueOf(md.getDrugWin() == null ? 1D : md.getDrugWin()))));
        }
        returnMzChargeDetail.setDiscountAmount(returnMzChargeDetail.getNotDiscountAmount().subtract(returnMzChargeDetail.getAmount()).setScale(1, BigDecimal.ROUND_HALF_UP));
        return returnMzChargeDetail;
    }

    /**
     * 构造所有的收费明细
     *
     * @param mzChargeDetail
     * @param yesNo          是否预览 yes 预览需要将原数据库中已存在的明细与临时生成的一起返回， no 保存，不用将数据库已存在的返回
     * @return
     * @throws MzException
     */
    private List<MzChargeDetail> getMzChargeDetails(MzChargeDetail mzChargeDetail, YesNoEnum yesNo, Integer receiptNo) throws MzException {
        if (mzChargeDetail == null || mzChargeDetail.getPatientId() == null || mzChargeDetail.getTimes() == null) {
            throw new MzException("病人编号和就诊次数不能为空！");
        }
        List<MzChargeDetail> mzChargeDetails = new ArrayList<>();
        List<MzYjReq> mzYjReqs = mzYjReqService.queryNotPayMzYjReq(new MzYjReq(mzChargeDetail.getPatientId(), mzChargeDetail.getTimes()));
        MzPatientMi mzPatientMi = mzPatientMiService.queryByPatientId(mzChargeDetail.getPatientId());
        List<MzChargeDetail> mzChargeDetailList = mzChargeDetailMapper.selectMzChargeDetailByPatientId(mzChargeDetail.getPatientId(), mzChargeDetail.getTimes(), null, PayMarkEnum.NO_CHARGE.code);
        Integer maxOrderNo = 0;
        Integer itemNo = 100;
        Date priceTime = null;
        String priceId = null;
        if (mzChargeDetailList != null && mzChargeDetailList.size() > 0) {
            MzChargeDetail firstMzChargeDetail = mzChargeDetailList.get(0);
            maxOrderNo = firstMzChargeDetail.getOrderNo();
            priceId = firstMzChargeDetail.getPriceId();
            priceTime = firstMzChargeDetail.getPriceTime();
            itemNo = formatSupplyFee(mzChargeDetails, mzChargeDetailList, itemNo, receiptNo);
        }
        maxOrderNo++;
        Map<String, MzYjReq> mzYjReqMap = new HashMap<>();
        Map<String, MzChargeDetail> tcNoMap = new HashMap<>();
        if (mzYjReqs != null && mzYjReqs.size() > 0) {
            List<String> jianYans = new ArrayList<>();
            List<String> jianChas = new ArrayList<>();
            Integer index = 1;
            for (MzYjReq mzYjReq : mzYjReqs) {
                //不为空且没有划价
                if (mzYjReq != null && (mzYjReq.getPercentFt() == null || mzYjReq.getPercentFt().compareTo(BigDecimal.ONE) < 0)) {
                    String temp = maxOrderNo.toString();
                    temp = temp + index++;
                    itemNo = formatYjChargeDetail(mzChargeDetail, mzChargeDetails, maxOrderNo, mzPatientMi, itemNo, jianYans, jianChas, mzYjReq, temp, priceId, priceTime, tcNoMap, receiptNo);
                    mzYjReqMap.put(mzYjReq.getOrderCode(), mzYjReq);
                }
            }
            List<JcJyItemCharge> jcJyItemCharges = null;
            //医生有可能同一个检验检查反复开，需要记录每种开了几次
            Map<String, Integer> jyjcCount = new HashMap<>();
            countSameYjCode(jianYans, jyjcCount);
            countSameYjCode(jianChas, jyjcCount);
            if (jianYans.size() > 0) {
                jcJyItemCharges = jcJyItemChargeService.queryJcItemChargeByCodeList(jianYans, ReqTypeEnum.JIAN_YAN.code);
                itemNo = formatCxFeeItem(mzChargeDetail, mzChargeDetails, mzPatientMi, maxOrderNo, itemNo, mzYjReqMap, jianYans, tcNoMap, priceId, priceTime, receiptNo);
            }
            if (jianChas.size() > 0) {
                List<JcJyItemCharge> temps = jcJyItemChargeService.queryJcItemChargeByCodeList(jianChas, ReqTypeEnum.JIAN_CHA.code);
                if (jcJyItemCharges == null) {
                    jcJyItemCharges = temps;
                } else {
                    jcJyItemCharges.addAll(temps);
                }
            }
            if (jcJyItemCharges != null && jcJyItemCharges.size() > 0) {
                for (JcJyItemCharge jcJyItemCharge : jcJyItemCharges) {
                    Integer count = jyjcCount.get(jcJyItemCharge.getCode());
                    for (int i = 0; i < count; i++) {
                        itemNo = formatYjDetailChargeDetail(mzChargeDetail, mzChargeDetails, maxOrderNo, mzPatientMi, itemNo, mzYjReqMap, jcJyItemCharge, tcNoMap, priceId, priceTime, receiptNo);
                    }
                }
            }
        }
        //预览的时候获取费用明细，需要打折，不是预览而是入库的时候不打折，因为入库后会有一次重新计算
        formatPriceRoundDetail(mzChargeDetail, mzChargeDetails, mzPatientMi, mzChargeDetailList, maxOrderNo, itemNo, receiptNo, YesNoEnum.YES.equals(yesNo) ? true : false);
        //yes 预览需要将原数据库中已存在的明细与临时生成的一起返回
        if (YesNoEnum.YES.equals(yesNo)) {
            for (MzChargeDetail mcd : mzChargeDetailList) {
                mcd.setReceiptNo(receiptNo);
                mzChargeDetails.add(mcd);
            }
        } else {
            //判断新生产的服务项是否已经入库了，如果存在相同的组合键，则重新生成iemNo
            Set<String> tempSet = new HashSet<>();
            StringBuffer sbf = new StringBuffer();
            for (MzChargeDetail mz : mzChargeDetailList) {
                sbf.append(mz.getPatientId()).append("_").append(mz.getTimes()).append("_").append(receiptNo).append("_").append(mz.getOrderNo()).append("_").append(mz.getItemNo()).append("_").append(mz.getChargeItemCode());
                tempSet.add(sbf.toString());
                sbf.setLength(0);
            }
            for (MzChargeDetail mz : mzChargeDetails) {
                sbf.append(mz.getPatientId()).append("_").append(mz.getTimes()).append("_").append(receiptNo).append("_").append(mz.getOrderNo()).append("_").append(mz.getItemNo()).append("_").append(mz.getChargeItemCode());
                if (tempSet.contains(sbf.toString())) {
                    mz.setItemNo(itemNo++);
                }
                sbf.setLength(0);
            }
        }
        return mzChargeDetails;
    }

    private void countSameYjCode(List<String> jianChas, Map<String, Integer> jyjcCount) {
        for (String str : jianChas) {
            Integer count = jyjcCount.get(str);
            if (count == null) {
                count = 0;
            }
            count++;
            jyjcCount.put(str, count);
        }
    }

    /**
     * 将未缴费的处方转成完整的收费明细
     *
     * @param patientId 病人id
     * @return
     */
    @Override
    public List<MzChargeDetail> unPaidToFullChargeDetail(String patientId, String name) throws MzException {
        if (StringUtils.isBlank(patientId)) {
            throw new MzException("病人编号不能为空！");
        }
        if (StringUtils.isBlank(name)) {
            throw new MzException("病人姓名不能为空！");
        }
        List<Map<String, Object>> unPaidChargeDetails = mzChargeDetailMapper.selectUnPaidChargeDetail(patientId);
        List<Map<String, Object>> unPaidYjReqs = mzYjReqService.queryUnPaidYjReq(patientId);
        unPaidChargeDetails.addAll(unPaidYjReqs);
        List<MzChargeDetail> returnMzChargeDetails = new ArrayList<>();
        if (unPaidChargeDetails.size() > 0) {
            Set<String> hasHandle = new HashSet<>();
            MzChargeDetail mzChargeDetail = new MzChargeDetail();
            for (Map<String, Object> map : unPaidChargeDetails) {
                String key = map.get("patient_id") + "-" + map.get("times");
                if (hasHandle.contains(key)) {
                    continue;
                }
                hasHandle.add(key);
                mzChargeDetail.setPatientId((String) map.get("patient_id"));
                try {
                    mzChargeDetail.setTimes((Integer) map.get("times"));
                } catch (ClassCastException e) {
                    mzChargeDetail.setTimes(Integer.valueOf((Short) map.get("times")));
                }
                MzChargeDetail mzChargeDetail1 = unPaidToFullChargeDetail(mzChargeDetail);
                mzChargeDetail1.setName(name);
                returnMzChargeDetails.add(mzChargeDetail1);
            }
        }
        return returnMzChargeDetails;
    }

    @Override
    public List<MzChargeDetail> queryMzChargeDetailByBillItemCode(String patientId, Integer times, Integer receiptNo, String payMark, String billItemCode, List<String> billItemTypes) {
        return mzChargeDetailMapper.selectMzChargeDetailByBillItemCode(patientId, times, receiptNo, payMark, billItemCode, billItemTypes);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 36000, rollbackFor = Exception.class)
    public int chargeFee(String opId, MzDepositFileVo mzDepositFileVo) throws MzException {
        Windows windows = windowsMapper.selectLastWindowsByUserIdCode(opId, null);
        if (windows == null) {
            throw new MzException("当前操作人未设置窗口号，请先设置！");
        }
        MzVisitTable mzVisitTable = mzVisitTableMapper.selectByPatientIdAndTimes(mzDepositFileVo.getPatientId(), mzDepositFileVo.getTimes(), "mz_visit_table");
        if (mzVisitTable == null) {
            throw new MzException("当前病人就诊基础资料【MzVisitTable】不存在，请检查");
        }
        MzPatientMi mzPatientMi = mzPatientMiService.queryByPatientId(mzDepositFileVo.getPatientId());
        Integer receiptNo = mzVisitTable.getReceiptNo() + 1;
        //入库收费明细数据开始
        MzChargeDetail mzChargeDetail = new MzChargeDetail(mzDepositFileVo.getPatientId(), mzDepositFileVo.getTimes());
        List<MzChargeDetail> mzChargeDetails = getMzChargeDetails(mzChargeDetail, YesNoEnum.NO, receiptNo);
        getMzChargeDetailService().saveMzChargeDetail(mzChargeDetails);
        mzChargeDetail.setPrintFlag(YesNoEnum.NO.code.toString());
        mzChargeDetail.setReceiptNo(receiptNo);
        mzChargeDetail.setName(mzPatientMi.getName());
        mzChargeDetailMapper.setTempDataReceiptNo(mzChargeDetail.getPatientId(), mzChargeDetail.getTimes(), receiptNo);
        mzChargeDetailMapper.updateMzChargeDetailFull(mzChargeDetail);
        //入库收费明细数据结束
        List<MzChargeDetail> mzChargeDetailList = mzChargeDetailMapper.selectMzChargeDetailByPatientId(mzDepositFileVo.getPatientId(), mzDepositFileVo.getTimes(), null, PayMarkEnum.NO_CHARGE.code);
        //所有应收费用的明细 将所有费用按照类型归类
        Map<String, BigDecimal> feeMap = new HashMap<>();
        //实际应付金额
        BigDecimal totalPayable = getTotalPayable(mzChargeDetailList, feeMap, true);
        //实际应付金额  四舍五入后的值 收费员收的钱小数点后只有一位有效值
        BigDecimal totalPayableRound = totalPayable.setScale(1, BigDecimal.ROUND_HALF_UP);
        //单病种收费不设置金额，所以自动设置金额
        if (Constants.DBZJF_CODE.equals(opId)) {
            mzDepositFileVo.getMzDepositFiles().get(0).setAmount(totalPayableRound);
        }
        Date now = new Date();
        int serialNo = mzSerialNoService.getSerialNo();
        MzReceiptSerial mzReceiptSerial = new MzReceiptSerial();
        ReceiptSerialFee receiptSerialFee = new ReceiptSerialFee();
        //实际支付金额 收银员收的钱
        BigDecimal hadPayable = getHadPayable(opId, mzDepositFileVo, windows, mzPatientMi, feeMap, now, serialNo, mzReceiptSerial, receiptNo, receiptSerialFee);
        if (hadPayable.compareTo(totalPayableRound) != 0) {
            throw new MzException("收款金额有误，实际应付" + totalPayableRound.toString() + "元,实收" + hadPayable.toString() + "元，患者处方有修改，请重新刷当前病人收费数据");
        }
        getMzChargeDetailService().updateChargeFlag(opId, mzDepositFileVo.getPatientId(), mzDepositFileVo.getTimes(), mzPatientMi.getName(), mzChargeDetailList, now, serialNo, mzReceiptSerial.getChequeType(), null);
        getMzChargeDetailService().afterChargeFee(mzDepositFileVo.getPatientId(), mzDepositFileVo.getTimes(), mzDepositFileVo.getMzDepositFiles(), now, serialNo, mzReceiptSerial, totalPayable, receiptSerialFee);
        if (Constants.JZ_IC_CARD.equals(mzPatientMi.getIcCardNo())) {
            mzChargeDetailMapper.updateNameByPatientIdAndTimes(mzPatientMi.getName(), mzDepositFileVo.getPatientId(), mzDepositFileVo.getTimes());
        }
        //本院记账,设置收款方式
        if (receiptSerialFee.getByjzje() != null && receiptSerialFee.getByjzje().compareTo(BigDecimal.ZERO) == 1) {
            mzChargeDetailMapper.updateChequeTypeByserialNo(Constants.BYJZ, serialNo);
        }
        //发送缴费成功MQ
        orderStatusChangeService.orderStatusChange(mzDepositFileVo.getPatientId() + "_" + mzDepositFileVo.getTimes() + "_" + receiptNo + "," + OrderStatusEnum.SUCCESSFUL_PRESCRIPTION_PAYMENT.code);
        return receiptNo;
    }

    /**
     * 收费后续处理，入库收费发票表记录 和 收费方式
     *
     * @param patientId
     * @param times
     * @param mzDepositFiles
     * @param now
     * @param serialNo
     * @param mzReceiptSerial
     * @throws MzException
     */
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 36000, rollbackFor = Exception.class)
    @Override
    public void afterChargeFee(String patientId, Integer times, List<MzDepositFile> mzDepositFiles, Date now, int serialNo, MzReceiptSerial mzReceiptSerial, BigDecimal totalPayable, ReceiptSerialFee receiptSerialFee) throws MzException {
        if (mzDepositFileMapper.selectBySameParams(mzDepositFiles.get(0)) > 0) {
            throw new MzException("当前病人本次处方已经成功缴费，无需重复缴费");
        }
        MzYjReq updateMzYjReq = new MzYjReq(patientId, times);
        updateMzYjReq.setSerialNo(serialNo);
        updateMzYjReq.setPayMark(PayMarkEnum.CHARGED.code);
        updateMzYjReq.setReceiptNo(mzReceiptSerial.getReceiptNo());
        mzYjReqService.modifyMzYjReq(updateMzYjReq);
        //新增收费方式记录
        mzDepositFileMapper.batchInsertMzDepositFile(mzDepositFiles);
        if (mzReceiptSerial.getTotalCharge().compareTo(BigDecimal.ZERO) == 1) {
            mzReceiptSerialMapper.insertMzReceiptSerial(mzReceiptSerial);
        }
        //本院记账金额
        if (receiptSerialFee.getByjzje() != null && receiptSerialFee.getByjzje().compareTo(BigDecimal.ZERO) == 1) {
            MzReceiptSerial jzMzReceiptSerial = CloneUtil.clone(mzReceiptSerial);
            //当前付款方式有除本院记账以外的，需要清空发票表的明细数据
            if (receiptSerialFee.getZfTotalPayable().compareTo(BigDecimal.ZERO) == 1 || receiptSerialFee.getYbjzje().compareTo(BigDecimal.ZERO) == 1) {
                resetParams(jzMzReceiptSerial);
            }
            jzMzReceiptSerial.setTotalCharge(receiptSerialFee.getByjzje());
            jzMzReceiptSerial.setChequeType(Constants.BYJZ);
            mzReceiptSerialMapper.insertMzReceiptSerial(jzMzReceiptSerial);
        }
        //医保记账金额
        if (receiptSerialFee.getYbjzje() != null && receiptSerialFee.getYbjzje().compareTo(BigDecimal.ZERO) == 1) {
            MzReceiptSerial jzMzReceiptSerial = CloneUtil.clone(mzReceiptSerial);
            resetParams(jzMzReceiptSerial);
            jzMzReceiptSerial.setTotalCharge(receiptSerialFee.getYbjzje());
            jzMzReceiptSerial.setChequeType(Constants.YBJZ);
            mzReceiptSerialMapper.insertMzReceiptSerial(jzMzReceiptSerial);
        }
        MzVisitTable newMzVisitTable = new MzVisitTable();
        newMzVisitTable.setPatientId(patientId);
        newMzVisitTable.setTimes(times);
        newMzVisitTable.setOrderNo(1);
        newMzVisitTable.setReceiptNo(mzReceiptSerial.getReceiptNo());
        newMzVisitTable.setReceiveFlag(YesNoEnum.YES.code);
        mzVisitTableMapper.updateMzVisitTable(newMzVisitTable);
    }

    private void resetParams(MzReceiptSerial jzMzReceiptSerial) {
        jzMzReceiptSerial.setCharge1(BigDecimal.ZERO);
        jzMzReceiptSerial.setCharge2(BigDecimal.ZERO);
        jzMzReceiptSerial.setCharge3(BigDecimal.ZERO);
        jzMzReceiptSerial.setCharge4(BigDecimal.ZERO);
        jzMzReceiptSerial.setCharge5(BigDecimal.ZERO);
        jzMzReceiptSerial.setCharge6(BigDecimal.ZERO);
        jzMzReceiptSerial.setCharge7(BigDecimal.ZERO);
        jzMzReceiptSerial.setCharge8(BigDecimal.ZERO);
        jzMzReceiptSerial.setCharge9(BigDecimal.ZERO);
        jzMzReceiptSerial.setCharge10(BigDecimal.ZERO);
        jzMzReceiptSerial.setCharge11(BigDecimal.ZERO);
        jzMzReceiptSerial.setCharge12(BigDecimal.ZERO);
        jzMzReceiptSerial.setCharge13(BigDecimal.ZERO);
        jzMzReceiptSerial.setCharge14(BigDecimal.ZERO);
        jzMzReceiptSerial.setCharge15(BigDecimal.ZERO);
        jzMzReceiptSerial.setCharge16(BigDecimal.ZERO);
        jzMzReceiptSerial.setCharge17(BigDecimal.ZERO);
        jzMzReceiptSerial.setCharge18(BigDecimal.ZERO);
        jzMzReceiptSerial.setCharge19(BigDecimal.ZERO);
        jzMzReceiptSerial.setCharge20(BigDecimal.ZERO);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 36000, rollbackFor = Exception.class)
    public int chargeFeeForByjz(String opId, MzDepositFileVo mzDepositFileVo) throws MzException {
        Date now = new Date();
        int serialNo = mzSerialNoService.getSerialNo();
        List<MzDepositFile> newMzDepositFileList = getMzDepositFiles(mzDepositFileVo, now, serialNo, opId);
        if (newMzDepositFileList.size() > 0 && mzDepositFileMapper.selectBySameParams(newMzDepositFileList.get(0)) > 0) {
            throw new MzException("当前病人本次处方已经成功缴费，无需重复缴费");
        }
        //如果当前数据是在备份库中，那么久会还原到正式库
        List<MzChargeDetail> mzChargeDetailList = mzChargeDetailMapper.selectByPatientIdAndTimesAndReceiptNo(mzDepositFileVo.getPatientId(), mzDepositFileVo.getTimes(), mzDepositFileVo.getReceiptNo());
        MzChargeDetail mzChargeDetail = new MzChargeDetail(mzDepositFileVo.getPatientId(), mzDepositFileVo.getTimes());
        mzChargeDetail.setReceiptNo(mzDepositFileVo.getReceiptNo());
        if (mzChargeDetailList == null || mzChargeDetailList.size() == 0) {
            mzChargeDetailMapper.reInsertDetail(mzChargeDetail);
            mzChargeDetailMapper.deleteFromBak(mzChargeDetail);
            mzChargeDetail.setChequType(Constants.BYJZ);
            mzChargeDetailMapper.updateMzChargeDetailFull(mzChargeDetail);
        }
        //本院记账需要把原缴费记录保存
        mzChargeDetailList = mzChargeDetailMapper.selectByPatientIdAndTimesAndReceiptNo(mzDepositFileVo.getPatientId(), mzDepositFileVo.getTimes(), mzDepositFileVo.getReceiptNo());
        mzDepositFileService.batchSaveMzDepositFile(newMzDepositFileList);
        List<MzReceiptSerial> newMzReceiptSerialList = getMzReceiptSerials(opId, mzDepositFileVo, now, serialNo);
        mzReceiptSerialService.batchSaveMzReceiptSerial(newMzReceiptSerialList);
        //将新生成的收费流水号设置到收费明细
        mzChargeDetail.setSerialNo(serialNo);
        mzChargeDetail.setRealNo(serialNo);
        mzChargeDetail.setReceiptNo(mzDepositFileVo.getReceiptNo());
        mzChargeDetail.setNewReceiptNo(newMzDepositFileList.get(0).getReceiptNo());
        //如果有发药队列，修改发药统计的流水号
        MzYpFydl mzYpFydl = new MzYpFydl();
        mzYpFydl.setSerialNo(serialNo);
        mzYpFydl.setPatientId(mzDepositFileVo.getPatientId());
        mzYpFydl.setTimes(mzDepositFileVo.getTimes());
        mzYpFydl.setReceiptNo(mzChargeDetail.getNewReceiptNo());
        mzYpFydlMapper.updateSeralNoForByjz(mzYpFydl);
        //如果有发药统计，修改发药统计的流水号
        YpMzFytj ypMzFytj = new YpMzFytj();
        ypMzFytj.setSerialNo(serialNo);
        ypMzFytj.setPatientId(mzDepositFileVo.getPatientId());
        ypMzFytj.setTimes(mzDepositFileVo.getTimes());
        ypMzFytj.setReceiptNo(mzChargeDetail.getNewReceiptNo());
        ypMzFytj.setRealNo(serialNo);
        ypMzFytjMapper.updateSeralNoForByjz(ypMzFytj);
        mzChargeDetailMapper.updateMzChargeDetailFull(mzChargeDetail);
        for (MzChargeDetail md : mzChargeDetailList) {
            md.setPayMark(PayMarkEnum.BYJZ_CHARGED_ORI_DATA.code);
        }
        getMzChargeDetailService().saveMzChargeDetail(mzChargeDetailList);
        return newMzDepositFileList.get(0).getReceiptNo();
    }

    @Override
    public List<Map<String, Object>> queryChargeListByPatient(YesNoEnum hisDate, String patientId, String name, String serialNo, Date beginDate, Date endDate) {
        List<Map<String, Object>> chargeListByPatient;
        if (YesNoEnum.YES.equals(hisDate)) {
            chargeListByPatient = mzChargeDetailMapper.selectHisChargeListByPatient(patientId, name, serialNo, beginDate, endDate);
        } else {
            chargeListByPatient = mzChargeDetailMapper.selectChargeListByPatient(patientId, name, serialNo, beginDate, endDate);
        }
        for (Map<String, Object> map : chargeListByPatient) {
            String patientIdTemp = (String) map.get("patient_id");
            Integer times = (Integer) map.get("times");
            List<MzReceiptSerial> lists = mzReceiptSerialMapper.selectSerialForJzTfThisTime(patientIdTemp, times);
            if (lists != null && lists.size() > 0) {
                map.put("cheque_type", "本院记账已结算");
            }
        }
        return chargeListByPatient;
    }

    @Override
    public List<Map<String, Object>> queryChargeDetailByPatient(YesNoEnum hisDate, String patientId, String serialNo) {
        if (YesNoEnum.YES.equals(hisDate)) {
            return mzChargeDetailMapper.selectHisChargeDetailByPatient(patientId, serialNo);
        }
        return mzChargeDetailMapper.selectChargeDetailByPatient(patientId, serialNo);
    }

    @Override
    public int refshOldSystemReceiptData() {
        return mzChargeDetailMapper.refshOldSystemReceiptData();
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 36000, rollbackFor = Exception.class)
    public int modifyNameByPatientIdAndTimes(String name, String patientId, Integer times) {
        mzChargeDetailMapper.updateNameByPatientIdAndTimes(name, patientId, times);
        MzPatientMi mzPatientMi = new MzPatientMi();
        mzPatientMi.setPatientId(patientId);
        mzPatientMi.setTimes(times);
        mzPatientMi.setName(name);
        mzPatientMiMapper.updateMzPatientMi(mzPatientMi);
        return mzYjReqMapper.updateNameByPatientIdAndTimes(name, patientId, times);
    }

    @Override
    public String queryJZName(String patientId, Integer times) {
        return mzChargeDetailMapper.selectJZName(patientId, times);
    }

    @Override
    public List<Map<String, Object>> queryDepetBusinessReport(ThmzmxsrParamsVo thmzmxsrParamsVo) {
        return mzChargeDetailMapper.selectDepetBusinessReport(thmzmxsrParamsVo);
    }

    @Override
    public void formatMzChargeDetail(List<MzChargeDetail> mzChargeDetails) {
        if (mzChargeDetails == null) {
            return;
        }
        List<String> doctorCodes = mzChargeDetails.stream().filter(u -> StringUtils.isNotBlank(u.getDoctorCode())).map(u -> u.getDoctorCode()).collect(Collectors.toList());
        Map<String, String> employeeMap = null;
        List<Employee> employees = employeeService.queryByCodes(doctorCodes);
        if (employees != null) {
            employeeMap = employees.stream().collect(Collectors.toMap(Employee::getEmployeeCode, Employee::getEmployeeName));
        }
        for (MzChargeDetail mzChargeDetail : mzChargeDetails) {
            if (mzChargeDetail != null) {
                mzChargeDetail.setWarnDept(zdUnitCodeService.queryDeptNameByIdInCache(mzChargeDetail.getWarnDept()));
                if (employeeMap != null) {
                    String doctorCode = employeeMap.get(mzChargeDetail.getDoctorCode());
                    mzChargeDetail.setDoctorCode(doctorCode == null ? "" : doctorCode);
                }
                if (mzChargeDetail.getAmount() != null) {
                    mzChargeDetail.setAmount(mzChargeDetail.getAmount().setScale(1, BigDecimal.ROUND_HALF_UP));
                    if (mzChargeDetail.getNotDiscountAmount() != null) {
                        mzChargeDetail.setNotDiscountAmount(mzChargeDetail.getNotDiscountAmount().setScale(1, BigDecimal.ROUND_HALF_UP));
                        mzChargeDetail.setDiscountAmount(mzChargeDetail.getNotDiscountAmount().subtract(mzChargeDetail.getAmount()).setScale(1, BigDecimal.ROUND_HALF_UP));
                    }
                }
            }
        }
    }

    @Override
    public List<MzChargeDetail> getMzChargeDetails(List<MzChargeDetail> mzChargeDetailList) {
        if (mzChargeDetailList != null) {
            for (MzChargeDetail md : mzChargeDetailList) {
                BigDecimal unitPrice = md.getUnitPrice() == null ? BigDecimal.ZERO : md.getUnitPrice().setScale(2, BigDecimal.ROUND_HALF_UP);
                if (!Constants.TC.equals(md.getBillItemCode()) && BigDecimal.ZERO.compareTo(unitPrice) == 0) {
                    unitPrice = BigDecimal.valueOf(0.01D);
                    md.setUnitPrice(unitPrice);
                }
                md.setAmount(unitPrice.multiply(BigDecimal.valueOf(md.getQuantity() == null ? 1D : md.getQuantity())).multiply(BigDecimal.valueOf(md.getDrugWin() == null ? 1D : md.getDrugWin())).setScale(2, BigDecimal.ROUND_HALF_UP));
                if (!Constants.YJ_GROUP_NO.equals(md.getGroupNo())) {
                    YpZdDict ypZdDict = ypZdDictService.queryYpZdDictByCodeAndSerial(md.getChargeItemCode(), md.getSerial());
                    if (ypZdDict != null) {
                        md.setTcName(ypZdDict.getName());
                    }
                } else {
                    ZdChargeItem zdChargeItem = zdChargeItemService.queryZdChargeItemByCode(md.getChargeItemCode());
                    if (zdChargeItem != null) {
                        md.setTcName(zdChargeItem.getName());
                    }
                }
            }
            Collections.sort(mzChargeDetailList); // 按处方号排序
        }
        return mzChargeDetailList;
    }


    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 36000, rollbackFor = Exception.class)
    @Override
    public int savePrescription(MzPrescriptionVo mzPrescriptionVo) throws MzException {
        if (mzPrescriptionVo == null) {
            throw new MzException("保存处方失败，处方参数不能为空");
        }
        if (StringUtils.isBlank(mzPrescriptionVo.getVisitDeptCode())) {
            throw new MzException("保存处方失败，就诊科室不能为空");
        }
        if (StringUtils.isBlank(mzPrescriptionVo.getDoctorCode())) {
            throw new MzException("保存处方失败，就诊医生不能为空");
        }
        if (StringUtils.isBlank(mzPrescriptionVo.getPatientId())) {
            throw new MzException("保存处方失败，病人ID不能为空");
        }
        if (mzPrescriptionVo.getJzFlag() == null) {
            throw new MzException("保存处方失败，急诊标志不能为空");
        }
        if (!Arrays.asList(YesNoEnum.YES.code, YesNoEnum.NO.code).contains(mzPrescriptionVo.getJzFlag())) {
            throw new MzException("保存处方失败，急诊标志值错误");
        }
        List<MzChargeDetail> dbMzChargeDetailList = mzChargeDetailMapper.selectNotPayMzChargeDetailByPatientId(mzPrescriptionVo.getPatientId());
        if (dbMzChargeDetailList != null && dbMzChargeDetailList.size() > 0) {
            for (MzChargeDetail mzChargeDetail : dbMzChargeDetailList) {
                if (Arrays.asList(Constants.XY_ZCY_GROUP_NO, Constants.ZY_GROUP_NO).contains(mzChargeDetail.getGroupNo())) {
                    ypBaseYfMapper.updateStockAmountVirtualAdd(mzChargeDetail.getChargeItemCode(), mzChargeDetail.getSerial(), mzChargeDetail.getGroupNo(), BigDecimal.valueOf(mzChargeDetail.getQuantity()).multiply(BigDecimal.valueOf(mzChargeDetail.getDrugWin())));
                }
            }
            mzChargeDetailMapper.deleteNotPayMzChargeDetailByPatientId(mzPrescriptionVo.getPatientId());
        }
        mzYjReqMapper.deleteNotPayYjReByPatientId(mzPrescriptionVo.getPatientId());
        int times = 0;
        MzVisitTable lastMzVisitTable = mzVisitTableService.queryLastMzVisitTableByPatientId(mzPrescriptionVo.getPatientId());
        if (lastMzVisitTable != null) {
            times = lastMzVisitTable.getTimes();
        }
        MzPatientMi mzPatientMi = mzPatientMiMapper.selectByPatientId(mzPrescriptionVo.getPatientId());
        if (mzPatientMi == null) {
            throw new MzException("当前病人信息不存在，请先保存病人信息！");
        }
        if (mzPatientMi.getTimes() != null && mzPatientMi.getTimes() > times) {
            times = mzPatientMi.getTimes();
        }
        times++;
        Date now = new Date();
        MzVisitTable newMzVisitTable = getMzVisitTable(mzPrescriptionVo, times, now, mzPatientMi.getResponseType());
        mzVisitTableMapper.insertMzVisitTable(newMzVisitTable);
        MzPatientMi updateMzPatientMi = new MzPatientMi();
        updateMzPatientMi.setPatientId(mzPrescriptionVo.getPatientId());
        updateMzPatientMi.setTimes(times);
        updateMzPatientMi.setLvDate(now);
        mzPatientMiMapper.updateMzPatientMi(updateMzPatientMi);
        //保存医技入库
        if (mzPrescriptionVo.getMzYjReqList() != null && mzPrescriptionVo.getMzYjReqList().size() > 0) {
            for (MzYjReq mzYjReq : mzPrescriptionVo.getMzYjReqList()) {
                if (StringUtils.isBlank(mzYjReq.getOrderCode())) {
                    throw new MzException("保存处方失败，医技项目编码不能为空");
                }
                mzYjReq.setReqNo(mzYshConfigService.getReqNo());
                mzYjReq.setPageNo(String.valueOf(mzYshConfigService.getReqPageNo()));
                mzYjReq.setReqDate(now);
                mzYjReq.setOrderNo(0);
                mzYjReq.setItemNo(0);
                mzYjReq.setReceiptNo(0);
                mzYjReq.setPatientId(mzPrescriptionVo.getPatientId());
                mzYjReq.setPatientName(mzPatientMi.getName());
                mzYjReq.setTimes(times);
                mzYjReq.setReqWard(mzPrescriptionVo.getVisitDeptCode());
                mzYjReq.setStatusFlag(YesNoEnum.YES.code.toString());
                mzYjReq.setBirthDate(mzPrescriptionVo.getBirthDate());
                mzYjReq.setPayMark(PayMarkEnum.NO_CHARGE.code);
                mzYjReq.setReqDoctor(mzPrescriptionVo.getDoctorCode());
                mzYjReq.setReceiveFlag(YesNoEnum.NO.code.toString());
                JcZdItem jcZdItem = jcZdItemMapper.selectJcZdItemByCode(mzYjReq.getOrderCode());
                if (jcZdItem != null) {
                    mzYjReq.setOrderName(jcZdItem.getName());
                    mzYjReq.setGroupName(jcZdItem.getName());
                    mzYjReq.setReqType(ReqTypeEnum.JIAN_CHA.code);
                    mzYjReq.setExecDept(jcZdItem.getExecUnit());
                    mzYjReq.setInspectPart(mzPrescriptionVo.getInspectPart());
                    mzYjReq.setReqComment(mzPrescriptionVo.getReqComment());
                    mzYjReq.setReqTzComment(mzPrescriptionVo.getReqTzComment());
                } else {
                    JyZdItem jyZdItem = jyZdItemService.queryJyZdItemByCode(mzYjReq.getOrderCode());
                    if (jyZdItem == null) {
                        throw new MzException("没有找到医技编码【" + mzYjReq.getOrderCode() + "】对应的医技项目，请确认参数是否正确！");
                    }
                    mzYjReq.setOrderName(jyZdItem.getName());
                    mzYjReq.setGroupName(jyZdItem.getName());
                    mzYjReq.setReqType(ReqTypeEnum.JIAN_YAN.code);
                    mzYjReq.setExecDept(jyZdItem.getExecUnit());
                }
                mzYjReqMapper.insertMzYjReq(mzYjReq);
            }
        }
        int blNo = mzYshConfigService.getBlNo();
        MzBaRecord mzBaRecord = MzBaRecord.getMzBaRecord(mzPrescriptionVo, times, now, blNo);
        mzBaRecordMapper.insertMzBaRecord(mzBaRecord);
        MzBlRecord mzBlRecord = mzPrescriptionVo.getMzBlRecord();
        mzBlRecord.setPatientId(mzPrescriptionVo.getPatientId());
        mzBlRecord.setTimes(times);
        mzBlRecord.setEmrNo(String.valueOf(blNo));
        mzBlRecord.setEmrType(YesNoEnum.YES.code.toString());
        mzBlRecord.setVisitDate(now);
        mzBlRecord.setDoctorCode(mzPrescriptionVo.getDoctorCode());
        mzBlRecord.setDeptCode(mzPrescriptionVo.getVisitDeptCode());
        mzBlRecordMapper.insertMzBlRecord(mzBlRecord);
        //保存药品入库
        int itemNo = 1;
        if (mzPrescriptionVo.getMzChargeDetailList() != null && mzPrescriptionVo.getMzChargeDetailList().size() > 0) {
            for (MzChargeDetail mzChargeDetail : mzPrescriptionVo.getMzChargeDetailList()) {
                if (StringUtils.isBlank(mzChargeDetail.getChargeItemCode())) {
                    throw new MzException("保存处方失败，第" + itemNo + "行药品缴费编码不能为空");
                }
                if (StringUtils.isBlank(mzChargeDetail.getSerial())) {
                    throw new MzException("保存处方失败，第" + itemNo + "行药品序号(规格)不能为空");
                }
                if (mzChargeDetail.getQuantity() == null) {
                    throw new MzException("保存处方失败，第" + itemNo + "行药品数量不能为空");
                }
                if (mzChargeDetail.getDrugQuan() == null) {
                    throw new MzException("保存处方失败，第" + itemNo + "行药品每次使用剂量不能为空");
                }
                if (mzChargeDetail.getSupplyAmount() == null) {
                    throw new MzException("保存处方失败，第" + itemNo + "行药品给药方式执行次数不能为空");
                }
                if (StringUtils.isBlank(mzChargeDetail.getDrugUnit())) {
                    throw new MzException("保存处方失败，第" + itemNo + "行药品剂量单位不能为空");
                }
                if (mzChargeDetail.getOrderDays() == null) {
                    throw new MzException("保存处方失败，第" + itemNo + "行药品处方天数不能为空");
                }
                if (StringUtils.isBlank(mzChargeDetail.getPaySelf())) {
                    throw new MzException("保存处方失败，第" + itemNo + "行药品是否是自备药不能为空");
                }
                if (StringUtils.isBlank(mzChargeDetail.getSupplyExec())) {
                    throw new MzException("保存处方失败，第" + itemNo + "行药品给药方式执行科室不能为空");
                }
                mzChargeDetail.setPatientId(mzPrescriptionVo.getPatientId());
                mzChargeDetail.setTimes(times);
                mzChargeDetail.setReceiptNo(0);
                mzChargeDetail.setOrderNo(1);
                mzChargeDetail.setSerialNo(0);
                mzChargeDetail.setConfirmFlag(0);
                mzChargeDetail.setJzFlag(mzPrescriptionVo.getJzFlag().toString());
                mzChargeDetail.setItemNo(itemNo);
                YpZdDict ypZdDict = ypZdDictService.queryYpZdDictByCodeAndSerial(mzChargeDetail.getChargeItemCode(), mzChargeDetail.getSerial());
                if (ypZdDict == null) {
                    throw new MzException("保存处方失败，第" + itemNo + "行对应的药品不存在");
                }
                String chargeBillCode = Constants.BILL_ITEM_CODE_prev + ypZdDict.getBillItemMz().substring(1);
                mzChargeDetail.setChargeBillCode(chargeBillCode);
                mzChargeDetail.setUnitPrice(ypZdDict.getPackRetprice());
                mzChargeDetail.setOrigPrice(ypZdDict.getPackRetprice());
                mzChargeDetail.setPayMark(PayMarkEnum.NO_CHARGE.code);
                mzChargeDetail.setCountryFlag(ypZdDict.getCountryFlag());
                if (Arrays.asList(Constants.XYF, Constants.ZCYF).contains(ypZdDict.getBillItemMz())) {
                    if (StringUtils.isBlank(mzChargeDetail.getFrequency())) {
                        throw new MzException("保存处方失败，第" + itemNo + "行药品频率不能为空");
                    }
                    mzChargeDetail.setGroupNo(Constants.XY_ZCY_GROUP_NO);
                    mzChargeDetail.setExecDept(Constants.XY_ZCY_EXEC_CODE);
                    mzChargeDetail.setDrugWin(1);
                    mzChargeDetail.setGroupType(Constants.XYF.equals(ypZdDict.getBillItemMz()) ? "1" : "2");
                } else if (Constants.CYF.equals(ypZdDict.getBillItemMz())) {
                    mzChargeDetail.setGroupNo(Constants.ZY_GROUP_NO);
                    mzChargeDetail.setExecDept(Constants.ZY_EXEC_CODE);
                    mzChargeDetail.setGroupType("3");
                    if (mzChargeDetail.getDrugWin() == null) {
                        throw new MzException("保存处方失败，第" + itemNo + "行药品的剂量为空");
                    }
                } else {
                    throw new MzException("保存处方失败，第" + itemNo + "行药品的账单类型错误");
                }
                mzChargeDetail.setWarnDept(mzPrescriptionVo.getVisitDeptCode());
                mzChargeDetail.setSupplyCode(ypZdDict.getSupplyType());
                mzChargeDetail.setPriceId(mzPrescriptionVo.getDoctorCode());
                mzChargeDetail.setPriceTime(now);
                mzChargeDetail.setRealNo(0);
                mzChargeDetail.setDoctorFlag(YesNoEnum.YES.code.toString());
                mzChargeDetail.setGlPercent(BigDecimal.ONE);
                mzChargeDetail.setBillItemCode(ypZdDict.getBillItemMz());
                mzChargeDetail.setDoctorCode(mzPrescriptionVo.getDoctorCode());
                mzChargeDetail.setName(mzPatientMi.getName());
                mzChargeDetail.setResponceType(mzPatientMi.getResponseType());
                mzChargeDetail.setYbbxFlag("");
                mzChargeDetail.setTcNo("");
                mzChargeDetail.setTcName(ypZdDict.getName());
                mzChargeDetail.setDetailFlag(YesNoEnum.NO.code.toString());
                mzChargeDetail.setOrderType(YesNoEnum.YES.code.toString());
                mzChargeDetail.setTryFlag(YesNoEnum.NO.code.toString());
                mzChargeDetail.setReqYj(YesNoEnum.NO.code.toString());
                mzChargeDetail.setReqNo(0);
                mzChargeDetail.setOrderBill(100);
                int num = ypBaseYfMapper.updateStockAmountVirtual(mzChargeDetail.getChargeItemCode(), mzChargeDetail.getSerial(), mzChargeDetail.getGroupNo(), BigDecimal.valueOf(mzChargeDetail.getQuantity()).multiply(BigDecimal.valueOf(mzChargeDetail.getDrugWin())));
                if (num == 0) {
                    throw new MzException("保存处方失败，第" + itemNo + "行药品库存锁定失败，没有对应的药品记录");
                }
                itemNo++;
            }
            getMzChargeDetailService().saveMzChargeDetail(mzPrescriptionVo.getMzChargeDetailList());
        }
        return 1;
    }

    @Override
    public List<String> queryGroupNo(MzChargeDetail mzChargeDetail) {
        return mzChargeDetailMapper.selectGroupNo(mzChargeDetail);
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 36000, rollbackFor = Exception.class)
    public int modifyChequType(String chequeType, Integer receiptSn, String oldChequeType) throws MzException {
        List<MzDepositFile> mzDepositFiles = mzDepositFileMapper.selectMzDepositFileBySerialNo(receiptSn, oldChequeType);
        if (mzDepositFiles == null || mzDepositFiles.size() == 0) {
            throw new MzException("当前病人不存在收费信息!");
        }
        List<MzDepositFile> mzDepositFileList = mzDepositFileMapper.selectMzDepositFileBySerialNo(receiptSn, chequeType);
        if (mzDepositFileList != null && mzDepositFileList.size() > 0) {
            throw new MzException("当前病人已经存在以新修改的收款方式收款的收费记录，请查证是否操作有误!");
        }
        MzDepositFile mzDepositFile = mzDepositFiles.get(0);
        mzDepositFileMapper.updateChequeType(chequeType, receiptSn, oldChequeType);
        MzReceiptSerial mzReceiptSerial = new MzReceiptSerial();
        mzReceiptSerial.setPatientId(mzDepositFile.getPatientId());
        mzReceiptSerial.setTimes(mzDepositFile.getTimes());
        mzReceiptSerial.setReceiptNo(mzDepositFile.getReceiptNo());
        mzReceiptSerial.setChequeType(oldChequeType);
        mzReceiptSerial.setNewChequeType(chequeType);
        mzReceiptSerialMapper.updateMzReceiptSerialByReceiptNo(mzReceiptSerial);
        //新的收款方式是记账，设置成记账方式
        if (Constants.BYJZ.equals(chequeType)) {
            MzChargeDetail mzChargeDetail = new MzChargeDetail(mzDepositFile.getPatientId(), mzDepositFile.getTimes());
            mzChargeDetail.setReceiptNo(mzDepositFile.getReceiptNo());
            mzChargeDetail.setChequType(chequeType);
            mzChargeDetailMapper.updateMzChargeDetailFull(mzChargeDetail);
        }
        //老的收费方式是记账，设置成空白
        if (Constants.BYJZ.equals(oldChequeType)) {
            MzChargeDetail mzChargeDetail = new MzChargeDetail(mzDepositFile.getPatientId(), mzDepositFile.getTimes());
            mzChargeDetail.setReceiptNo(mzDepositFile.getReceiptNo());
            mzChargeDetail.setChequType("");
            mzChargeDetailMapper.updateMzChargeDetailFull(mzChargeDetail);
        }
        return 1;
    }

//    @Override
//    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 36000, rollbackFor = Exception.class)
//    public int reSaveDetailFromBak(MzChargeDetail mzChargeDetail) {
//        mzChargeDetailMapper.reInsertDetail(mzChargeDetail);
//        mzChargeDetailMapper.deleteFromBak(mzChargeDetail);
//        mzChargeDetail.setChequType(Constants.BYJZ);
//        return  mzChargeDetailMapper.updateMzChargeDetailFull(mzChargeDetail);
//    }


    /**
     * 更新收费状态，并入库发药记录
     *
     * @param opId
     * @param patientId
     * @param times
     * @param name
     * @param mzChargeDetailList
     * @param now
     * @param serialNo
     * @param chequeType
     * @param refundTimes        被退费次数 为null 时是收费
     * @throws MzException
     */
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 36000, rollbackFor = Exception.class)
    @Override
    public void updateChargeFlag(String opId, String patientId, Integer times, String name, List<MzChargeDetail> mzChargeDetailList, Date now, int serialNo, String chequeType, Integer refundTimes) throws MzException {
        if (mzChargeDetailList == null || mzChargeDetailList.size() == 0) {
            return;
        }
        //更新费用明细表的收费状态和发票与收费流水号
        Map<String, MzDrugWin> mzDrugWinMap = new HashMap<>();
        Map<String, Integer> yffyNoMap = new HashMap<>();
        Map<String, Integer> orderNoMap = new HashMap<>();
        Map<String, Integer> itemNoMap = new HashMap<>();
        for (MzChargeDetail m : mzChargeDetailList) {
            m.setSerialNo(serialNo);
            m.setRealNo(serialNo);
            m.setCashId(opId);
            m.setChargeDate(now);
            m.setPayMark(PayMarkEnum.CHARGED.code);
            setChargeDetail(mzDrugWinMap, yffyNoMap, orderNoMap, m);
            mzChargeDetailMapper.updateMzChargeDetail(m);
            itemNoMap.put(m.getChargeItemCode().trim(), m.getItemNo());
        }
        //收费时药品库存操作
        if (refundTimes == null) {
            Set<String> keySet = yffyNoMap.keySet();
            if (keySet != null && keySet.size() > 0) {
                for (String key : keySet) {
                    Integer yffyNo = yffyNoMap.get(key);
                    if (yffyNo != null) {
                        MzYpFydl mzYpFydl = getMzYpFydl(patientId, times, name, now, serialNo, mzDrugWinMap, orderNoMap, key, yffyNo);
                        mzYpFydlMapper.insertMzYpFydl(mzYpFydl);
                    }
                }
            }
        }
        //退费时药品库存操作
        if (refundTimes != null) {
            //退费 此时药房还没有发药 直接修改发药队列数据
            List<MzYpFydl> mzYpFydls = mzYpFydlMapper.selectMzYpFydl(patientId, refundTimes);
            if (mzYpFydls != null && mzYpFydls.size() > 0) {
                mzYpFydlMapper.deleteMzYpFydl(patientId, refundTimes, null);
                Set<String> keySet = orderNoMap.keySet();
                for (MzYpFydl mzYpFydl : mzYpFydls) {
                    //如果新的组队列中不包含当前的发药队列，说明该药品全退了
                    if (!keySet.contains(mzYpFydl.getGroupNo())) {
                        continue;
                    }
                    mzYpFydl.setTimes(times);
                    mzYpFydl.setReceiptNo(1);
                    mzYpFydl.setOrderNo(orderNoMap.get(mzYpFydl.getGroupNo()));
                    mzYpFydl.setOrderTime(now);
                    mzYpFydl.setSerialNo(serialNo);
                    mzYpFydl.setYfNo(yffyNoMap.get(mzYpFydl.getGroupNo()));
                    mzYpFydlMapper.insertMzYpFydl(mzYpFydl);
                }
            }
            //查询当前病人本次已经确认发药了的发药统计记录
            List<YpMzFytj> ypMzFytjList = ypMzFytjMapper.selectConfirdYpMzFytj(patientId, refundTimes);
            if (ypMzFytjList != null && ypMzFytjList.size() > 0) {
                for (YpMzFytj ypMzFytj : ypMzFytjList) {
                    ypMzFytj.setSerialNo(-ypMzFytj.getSerialNo());
                    ypMzFytj.setRealNo(-ypMzFytj.getRealNo());
                    //将原数据改成退费后的记录 更改字段状态
                    ypMzFytjMapper.updateYpMzFytj(ypMzFytj);
                    ypMzFytj.setReceiptNo(-ypMzFytj.getReceiptNo());
                    ypMzFytj.setRealNo(-ypMzFytj.getRealNo());
                    //新增退费记录 新增负的对冲记录
                    ypMzFytjMapper.insertYpMzFytj(ypMzFytj);
                    //创建新的收款记录对应的发药统计记录
                    ypMzFytj.setTimes(times);
                    ypMzFytj.setReceiptNo(-ypMzFytj.getReceiptNo());
                    ypMzFytj.setReceiptNo(ypMzFytj.getReceiptNo() + 1);
                    ypMzFytj.setSerialNo(serialNo);
                    ypMzFytj.setRealNo(serialNo);
                    ypMzFytj.setItemNo(itemNoMap.get(ypMzFytj.getChargeItemCode().trim()));
                    ypMzFytjMapper.insertYpMzFytj(ypMzFytj);
                }
            }
            //查询当前病人本次已经退药的西药发药统计记录
            ypMzFytjList = ypMzFytjMapper.selectXyTyYpMzFytj(patientId, refundTimes);
            if (ypMzFytjList != null && ypMzFytjList.size() > 0) {
                for (YpMzFytj ypMzFytj : ypMzFytjList) {
                    List<MzChargeDetail> mzChargeDetails = mzChargeDetailMapper.selectMzChargeDetailByChargeItemCode(ypMzFytj.getPatientId(), ypMzFytj.getTimes(), ypMzFytj.getChargeItemCode(), ypMzFytj.getOrderNo());
                    if (mzChargeDetails == null || mzChargeDetails.size() == 0) {
                        continue;
                    }
                    for (MzChargeDetail mzChargeDetail : mzChargeDetails) {
                        Integer syCount = BigDecimal.valueOf(mzChargeDetail.getQuantity()).subtract(mzChargeDetail.getDecAmount() == null ? BigDecimal.ZERO : mzChargeDetail.getDecAmount()).intValue();
                        //皮试药特别逻辑
                        if (Constants.XYF.equals(mzChargeDetail.getBillItemCode())) {
                            BigDecimal origPrice = mzChargeDetail.getOrigPrice();
                            origPrice = origPrice == null ? BigDecimal.ZERO : origPrice;
                            BigDecimal unitPrice = mzChargeDetail.getUnitPrice();
                            unitPrice = unitPrice == null ? BigDecimal.ZERO : unitPrice;
                            //如果原价大于单价，说明是皮试自备
                            if (origPrice.compareTo(unitPrice) == 1) {
                                if (Integer.valueOf(1).equals(syCount)) {
                                    syCount = 0;
                                }
                            }
                        }

                        if (syCount <= 0) {
                            continue;
                        }
                        ypMzFytj.setTimes(times);
                        ypMzFytj.setReceiptNo(ypMzFytj.getReceiptNo() + 1);
                        ypMzFytj.setQuantity(Double.valueOf(syCount));
                        ypMzFytj.setSerialNo(serialNo);
                        ypMzFytj.setConfirmFlag(ConfirmFlagEnum.CONFIRM.code);
                        ypMzFytj.setRealNo(serialNo);
                        ypMzFytj.setItemNo(itemNoMap.get(ypMzFytj.getChargeItemCode().trim()));
                        ypMzFytjMapper.insertYpMzFytj(ypMzFytj);
                    }
                }
            }
        }
    }

    @Override
    public List<MzChargeDetail> queryFyJl(String patientId, Integer times) {
        return mzChargeDetailMapper.selectFyJl(patientId, times);
    }

    @Override
    public int modifyPrintFlag(String patientId, List<Integer> times) {
        return mzChargeDetailMapper.updatePrintFlag(patientId, times);
    }

    @Override
    public List<MzChargeDetail> queryChargeDetail(MzChargeDetail mzChargeDetail) {
        return mzChargeDetailMapper.selectMzChargeDetailByPatientId(mzChargeDetail.getPatientId(), mzChargeDetail.getTimes(), mzChargeDetail.getReceiptNo(), mzChargeDetail.getPayMark());
    }

    @Override
    public List<MzChargeDetail> getTempMzChargeDetailListForUnPaid(MzChargeDetail mzChargeDetail) throws MzException {
        MzVisitTable mzVisitTable = mzVisitTableMapper.selectByPatientIdAndTimes(mzChargeDetail.getPatientId(), mzChargeDetail.getTimes(), "mz_visit_table");
        if (mzVisitTable == null) {
            throw new MzException("当前病人就诊基础资料【MzVisitTable】不存在，请检查");
        }
        Integer receiptNo = mzVisitTable.getReceiptNo() + 1;
        List<MzChargeDetail> mzChargeDetails = getMzChargeDetails(mzChargeDetail, YesNoEnum.YES, receiptNo);
        if (mzChargeDetails == null || mzChargeDetails.size() == 0) {
            return null;
        }
        List<MzChargeDetail> returnList = getMzChargeDetails(mzChargeDetails, mzChargeDetail.getBillItemCode());
        return returnList;
    }

    @Override
    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 36000, rollbackFor = Exception.class)
    public int refundFee(String opId, MzDepositFileVo mzDepositFileVo) throws MzException {
        Windows windows = windowsMapper.selectLastWindowsByUserIdCode(opId, null);
        if (windows == null) {
            throw new MzException("当前操作人未设置窗口号，请先设置！");
        }
        List<MzChargeDetail> mzChargeDetails = getNewListForRefundFee(opId, mzDepositFileVo, YesNoEnum.YES);
        //是否全退
        boolean allRefund = mzChargeDetails == null || mzChargeDetails.size() == 0;
        MzChargeDetailYb mzChargeDetailYb = new MzChargeDetailYb();
        mzChargeDetailYb.setPatientId(mzDepositFileVo.getPatientId());
        mzChargeDetailYb.setTimes(mzDepositFileVo.getTimes());
        mzChargeDetailYb.setReceiptNo(mzDepositFileVo.getReceiptNo());
        int count = mzChargeDetailYbMapper.selectTmCount(mzChargeDetailYb);
        if (count > 0 && !allRefund) {
            throw new MzException("退费失败，特门收费必须全退！");
        }
        List<String> chargeItemCodeList = mzChargeDetails.stream().filter(u -> StringUtils.isNotBlank(u.getChargeItemCode())).map(u -> u.getChargeItemCode()).collect(Collectors.toList());
        List<MzChargeDetail> oriMzChargeDetails = mzChargeDetailMapper.selectMzChargeDetailByPatientId(mzDepositFileVo.getPatientId(), mzDepositFileVo.getTimes(), mzDepositFileVo.getReceiptNo(), PayMarkEnum.CHARGED.code);
        Date now = new Date();
        List<MzChargeDetail> tcMzChargeDetails = new ArrayList<>();
        List<MzChargeDetail> removeMzChargeDetails = new ArrayList<>();
        //需要重新入库的原记录的退费记录
        List<MzChargeDetail> refundOriMzChargeDetails = new ArrayList<>();
        fromatRefundDetail(opId, refundOriMzChargeDetails, chargeItemCodeList, oriMzChargeDetails, now, tcMzChargeDetails, removeMzChargeDetails);
        getMzChargeDetailService().saveMzChargeDetail(mzChargeDetails);
        getMzChargeDetailService().saveMzChargeDetail(refundOriMzChargeDetails);
        MzChargeDetail updateMzChargeDetail = new MzChargeDetail(mzDepositFileVo.getPatientId(), mzDepositFileVo.getTimes());
        updateMzChargeDetail.setReceiptNo(mzDepositFileVo.getReceiptNo());
        updateMzChargeDetail.setConfirmFlag(ConfirmFlagEnum.CANCEL.code);
        mzChargeDetailMapper.updateMzChargeDetailFull(updateMzChargeDetail);
        List<MzReceiptSerial> mzReceiptSerials = mzReceiptSerialMapper.selectSerialForThisTime(mzDepositFileVo.getPatientId(), mzDepositFileVo.getTimes(), mzDepositFileVo.getReceiptNo());
        if (mzReceiptSerials != null && mzReceiptSerials.size() > 0) {
            List<MzReceiptSerial> newReceiptSerials = formatRefundReceiptSerial(mzReceiptSerials, opId);
            mzReceiptSerialMapper.batchInsertMzReceiptSerial(newReceiptSerials);
        }
        MzReceiptSerial updateMzReceiptSerial = new MzReceiptSerial(mzDepositFileVo.getPatientId(), mzDepositFileVo.getTimes());
        //updateMzReceiptSerial.setPayMark(PayMarkEnum.RETURN_PREMIUM.code);
        updateMzReceiptSerial.setTfFlag(YesNoEnum.YES.code);
        mzReceiptSerialMapper.updateMzReceiptSerial(updateMzReceiptSerial);
        //包含退费的付款方式
        List<MzDepositFile> fullNewMzDepositFiles = new ArrayList<>();
        int times = 0;
        int oriTimes = mzDepositFileVo.getTimes();
        if (allRefund) {
            getDeposFiles(opId, mzDepositFileVo, now, 0, 0, null, null, fullNewMzDepositFiles, allRefund, null);
            //新增收费方式记录
            mzDepositFileMapper.batchInsertMzDepositFile(fullNewMzDepositFiles);
            times = 0;
            if (count > 0) {
                //PayInfo result=
                tsmzService.retractFees(opId, mzChargeDetailYb.getPatientId(), mzChargeDetailYb.getTimes(), mzChargeDetailYb.getReceiptNo());
            }
            mzYpFydlMapper.deleteMzYpFydl(mzDepositFileVo.getPatientId(), mzDepositFileVo.getTimes(), mzDepositFileVo.getReceiptNo());
        } else {
            times = mzChargeDetails.get(0).getTimes();
            List<String> orderCodes = new ArrayList<>();
            Map<String, String> tcMap = new HashMap<>();
            for (MzChargeDetail mt : tcMzChargeDetails) {
                if (!tcMap.containsKey(mt.getChargeItemCode())) {
                    tcMap.put(mt.getChargeItemCode(), mt.getTcNo());
                }
            }
            //Map<String, String> tcMap = tcMzChargeDetails.stream().collect(Collectors.toMap(MzChargeDetail::getChargeItemCode, MzChargeDetail::getTcNo));
            for (MzChargeDetail md : removeMzChargeDetails) {
                String tcNo = tcMap.get(md.getTcNo());
                if (StringUtils.isNotBlank(tcNo) && !orderCodes.contains(tcNo)) {
                    orderCodes.add(tcNo);
                }
            }
            List<MzYjReq> mzYjReqs = mzYjReqService.queryNotRefundYjReq(mzDepositFileVo.getPatientId(), mzDepositFileVo.getTimes(), orderCodes);
            if (mzYjReqs != null && mzYjReqs.size() > 0) {
                for (MzYjReq yj : mzYjReqs) {
                    int newReqNo = mzYshConfigService.getReqNo();
                    mzChargeDetailMapper.updateReqNo(yj.getPatientId(), times, yj.getReqNo(), newReqNo);
                    yj.setReqNo(newReqNo);
                    yj.setTimes(times);
                    yj.setPayMark(PayMarkEnum.NO_CHARGE.code);
                    yj.setSerialNo(null);
                    yj.setCashId(null);
                    yj.setConfirmFlag(ConfirmFlagEnum.NOT_CONFIRM.code.toString());
                    yj.setConfirmTime(null);
                    yj.setConfirmId(null);
                    yj.setPrintFlagYj(null);
                    mzYjReqMapper.insertMzYjReq(yj);
                }
            }
            int serialNo = mzSerialNoService.getSerialNo();
//            Receipt receipt = receiptMapper.selectByUserIdCode(opId);
//            if (receipt == null || StringUtils.isBlank(receipt.getReceiptCurrent())) {
//                throw new MzException("用户id=" + opId + "没有可用的发票,请先维护发票。");
//            }
            //所有应收费用的明细 将所有费用按照类型归类
            Map<String, BigDecimal> feeMap = new HashMap<>();
            //实际应付金额
            BigDecimal totalPayable = getTotalPayable(mzChargeDetails, feeMap, false);
            MzReceiptSerial mzReceiptSerial = new MzReceiptSerial();
            ReceiptSerialFee receiptSerialFee = new ReceiptSerialFee();
            //退费后新的收款方式
            List<MzDepositFile> newMzDepositFiles = new ArrayList<>();
            String payWay = Constants.CASH;
            payWay = getDeposFiles(opId, mzDepositFileVo, now, times, serialNo, totalPayable, payWay, fullNewMzDepositFiles, allRefund, newMzDepositFiles);
            //setMzReceiptSerial(opId, mzDepositFileVo.getPatientId(), times, windows, mzChargeDetails.get(0).getResponceType(), feeMap, now, serialNo, mzReceiptSerial, payWay, totalPayable, 1);
            MzPatientMi mzPatientMi = mzPatientMiService.queryByPatientId(mzDepositFileVo.getPatientId());
            mzDepositFileVo.setMzDepositFiles(newMzDepositFiles);
            Integer refundTimes = mzDepositFileVo.getTimes();
            mzDepositFileVo.setTimes(times);
            getHadPayable(opId, mzDepositFileVo, windows, mzPatientMi, feeMap, now, serialNo, mzReceiptSerial, 1, receiptSerialFee);
            getMzChargeDetailService().updateChargeFlag(opId, mzDepositFileVo.getPatientId(), times, mzChargeDetails.get(0).getName(), mzChargeDetails, now, serialNo, payWay, refundTimes);
            getMzChargeDetailService().afterChargeFee(mzDepositFileVo.getPatientId(), times, fullNewMzDepositFiles, now, serialNo, mzReceiptSerial, totalPayable, receiptSerialFee);
            MzPatientMi updateMzPatientMi = new MzPatientMi();
            updateMzPatientMi.setPatientId(mzDepositFileVo.getPatientId());
            updateMzPatientMi.setTimes(times);
            updateMzPatientMi.setLvDate(now);
            mzPatientMiMapper.updateMzPatientMi(updateMzPatientMi);
        }
        MzYjReq updateMzYjReq = new MzYjReq(mzDepositFileVo.getPatientId(), oriTimes);
        updateMzYjReq.setPayMark(PayMarkEnum.RETURN_PREMIUM.code);
        mzYjReqService.modifyMzYjReq(updateMzYjReq);
        return times;
    }

    private List<MzReceiptSerial> formatRefundReceiptSerial(List<MzReceiptSerial> mzReceiptSerials, String opId) {
        Set<String> tempSet = new HashSet<>();
        List<MzReceiptSerial> newReceiptSerials = new ArrayList<>();
        for (MzReceiptSerial mz : mzReceiptSerials) {
            //退过费的发票表记录
            if (mz.getSerialNo() < 0 && mz.getReceiptNo() < 0) {
                Integer tempSerialNo = -mz.getSerialNo();
                tempSet.add(mz.getChequeType() + "_" + tempSerialNo);
                continue;
            }
            if (tempSet.contains(mz.getChequeType() + "_" + mz.getSerialNo())) {
                continue;
            }
            mz.setOperatorId(opId);
            mz.setReceiptNo(-mz.getReceiptNo());
            mz.setPayId(opId);
            mz.setSerialNo(-mz.getSerialNo());
            mz.setPayMark(PayMarkEnum.RETURN_PREMIUM.code);
            mz.setTotalCharge(BigDecimal.ZERO.subtract(mz.getTotalCharge()));
            mz.setReceiptSn(-mz.getReceiptSn());
            mz.setSerialYb(null);
            mz.setDeptNo(null);
            mz.setCharge1(BigDecimal.ZERO.subtract(mz.getCharge1()));
            mz.setCharge2(BigDecimal.ZERO.subtract(mz.getCharge2()));
            mz.setCharge3(BigDecimal.ZERO.subtract(mz.getCharge3()));
            mz.setCharge4(BigDecimal.ZERO.subtract(mz.getCharge4()));
            mz.setCharge5(BigDecimal.ZERO.subtract(mz.getCharge5()));
            mz.setCharge6(BigDecimal.ZERO.subtract(mz.getCharge6()));
            mz.setCharge7(BigDecimal.ZERO.subtract(mz.getCharge7()));
            mz.setCharge8(BigDecimal.ZERO.subtract(mz.getCharge8()));
            mz.setCharge9(BigDecimal.ZERO.subtract(mz.getCharge9()));
            mz.setCharge10(BigDecimal.ZERO.subtract(mz.getCharge10()));
            mz.setCharge11(BigDecimal.ZERO.subtract(mz.getCharge11()));
            mz.setCharge12(BigDecimal.ZERO.subtract(mz.getCharge12()));
            mz.setCharge13(BigDecimal.ZERO.subtract(mz.getCharge13()));
            mz.setCharge14(BigDecimal.ZERO.subtract(mz.getCharge14()));
            mz.setCharge15(BigDecimal.ZERO.subtract(mz.getCharge15()));
            mz.setCharge16(BigDecimal.ZERO.subtract(mz.getCharge16()));
            mz.setCharge17(BigDecimal.ZERO.subtract(mz.getCharge17()));
            mz.setCharge18(BigDecimal.ZERO.subtract(mz.getCharge18()));
            mz.setCharge19(BigDecimal.ZERO.subtract(mz.getCharge19()));
            mz.setCharge20(BigDecimal.ZERO.subtract(mz.getCharge20()));
            if (Constants.BYJZ.equals(mz.getChequeType())) {
                mz.setChequeType(Constants.BYJZ);
            } else if (Constants.YBJZ.equals(mz.getChequeType())) {
                mz.setChequeType(Constants.YBJZ);
            } else {
                mz.setChequeType(Constants.CASH);
            }
            mz.setDcountNo(YesNoEnum.NO.code);
            mz.setDcountDate(null);
            mz.setChargeDcountDate(null);
            mz.setChargeDcountNo(YesNoEnum.NO.code);
            mz.setFpFlag(null);
            newReceiptSerials.add(mz);
        }
        return newReceiptSerials;
    }

    private void fromatRefundDetail(String opId, List<MzChargeDetail> mzChargeDetails, List<String> chargeItemCodeList, List<MzChargeDetail> oriMzChargeDetails, Date now, List<MzChargeDetail> tcMzChargeDetails, List<MzChargeDetail> removeMzChargeDetails) {
        for (MzChargeDetail md : oriMzChargeDetails) {
            md.setReceiptNo(-md.getReceiptNo());
            md.setQuantity(-md.getQuantity());
            md.setSerialNo(-md.getSerialNo());
            md.setConfirmTime(null);
            md.setInputId(opId);
            md.setInputDate(now);
            md.setRealNo(-md.getRealNo());
            md.setJzFlag(null);
            md.setInjectTimes(null);
            md.setOrderType(null);
            md.setSupplyNo(null);
            md.setOrderDays(null);
            md.setPaySelf(null);
            md.setTryFlag(null);
            md.setReqYj(null);
            md.setReqNo(null);
            md.setOrderBill(null);
            md.setBackSerial(null);
            md.setSupplyAmount(null);
            md.setGlPercentFt(null);
            md.setOrigPrice(null);
            md.setSupplyExec(null);
            md.setPayMark(PayMarkEnum.RETURN_PREMIUM.code);
            mzChargeDetails.add(md);
            if (Constants.TC.equals(md.getBillItemCode())) {
                tcMzChargeDetails.add(md);
            } else if (!chargeItemCodeList.contains(md.getChargeItemCode())) {
                removeMzChargeDetails.add(md);
            }
        }
    }

    /**
     * 构造退款后新需要入库的收款方式列表
     *
     * @param opId
     * @param mzDepositFileVo
     * @param now
     * @param times
     * @param serialNo
     * @param totalPayable
     * @param payWay
     * @param fullNewMzDepositFiles
     * @param newMzDepositFiles
     * @return
     */
    private String getDeposFiles(String opId, MzDepositFileVo mzDepositFileVo, Date now, int times, int serialNo, BigDecimal totalPayable, String payWay, List<MzDepositFile> fullNewMzDepositFiles, boolean allRefund, List<MzDepositFile> newMzDepositFiles) {
        List<MzDepositFile> mzDepositFiles = mzDepositFileMapper.selectMzDepositFileByTimes(mzDepositFileVo.getPatientId(), mzDepositFileVo.getTimes(), mzDepositFileVo.getReceiptNo(), "mz_deposit_file");
        if (mzDepositFiles == null || mzDepositFiles.size() == 0) {
            return payWay;
        }
        //本院记账总额
        BigDecimal byjzAmount = BigDecimal.ZERO;
        //非本院记账总额
        BigDecimal notByjzAmount = BigDecimal.ZERO;
        MzDepositFile temp = CloneUtil.clone(mzDepositFiles.get(0));
        temp.setReceiptNo(-temp.getReceiptNo());
        temp.setAmount(BigDecimal.ZERO.subtract(temp.getAmount()));
        temp.setReceiptSn(-temp.getReceiptSn());
        temp.setSerialNo(-temp.getSerialNo());
        temp.setDeptNo(null);
        temp.setChargeDate(now);
        temp.setPayMark(PayMarkEnum.RETURN_PREMIUM.code);
        temp.setOpId(opId);
        //当前退费发起人是手机自助，且退费的记录的缴费人也是手机自助发起的缴费记录退费方式
        if(Constants.BRZZJF_CODE.equals(opId) && Constants.BRZZJF_CODE.equals(temp.getOpId())){
            payWay=temp.getChequeType();
        }else {
            payWay=Constants.CASH;
            temp.setChequeType(payWay);
        }
        temp.setDcountNo(YesNoEnum.NO.code);
        temp.setDcountDate(null);
        temp.setPsordnum(null);
        temp.setAgtordnum(null);
        temp.setHisrefundnum(null);
        for (MzDepositFile ms : mzDepositFiles) {
            if (ms == null) {
                continue;
            }
            if (Constants.BYJZ.equals(ms.getChequeType())) {
                byjzAmount = byjzAmount.add(ms.getAmount());
            } else {
                notByjzAmount = notByjzAmount.add(ms.getAmount());
            }
        }
        temp.setAmount(BigDecimal.ZERO.subtract(notByjzAmount));
        //复制一个本院记账的退款记录
        MzDepositFile byjzTemp = CloneUtil.clone(temp);
        byjzTemp.setChequeType(Constants.BYJZ);
        byjzTemp.setAmount(BigDecimal.ZERO.subtract(byjzAmount));
        //如果有本院记账的退款金额，本院记账记录保持入库
        if (byjzAmount.compareTo(BigDecimal.ZERO) == 1) {
            fullNewMzDepositFiles.add(byjzTemp);
        }
        //如果有非本院记账的退款金额，非本院记账记录保持入库
        if (notByjzAmount.compareTo(BigDecimal.ZERO) == 1) {
            fullNewMzDepositFiles.add(temp);
        }
        if (!allRefund) {
            MzDepositFile m = mzDepositFiles.get(0);
            m.setTimes(times);
            m.setReceiptNo(1);
            m.setPayMark(PayMarkEnum.CHARGED.code);
            m.setChargeDate(now);
            m.setDcountNo(YesNoEnum.NO.code);
            m.setDcountDate(null);
            m.setOpId(opId);
            m.setReceiptSn(serialNo);
            m.setSerialNo(serialNo);
            m.setPsordnum(null);
            m.setAgtordnum(null);
            m.setHisrefundnum(null);
            //应付小于等于实际已经支付的非记账总额
            if (totalPayable.compareTo(notByjzAmount) <= 0) {
                m.setAmount(totalPayable);
                m.setChequeType(Constants.CASH);
                fullNewMzDepositFiles.add(m);
                //应付大于实际已经支付的非记账总额，需要用记账收一部分
                payWay = Constants.CASH;
                newMzDepositFiles.add(m);
            } else if (totalPayable.compareTo(notByjzAmount) == 1) {
                m.setAmount(notByjzAmount);
                m.setChequeType(Constants.CASH);
                fullNewMzDepositFiles.add(m);
                //复制一个本院记账的收款记录
                MzDepositFile byjzNeedPayTemp = CloneUtil.clone(m);
                byjzNeedPayTemp.setChequeType(Constants.BYJZ);
                byjzNeedPayTemp.setAmount(totalPayable.subtract(notByjzAmount).setScale(1, BigDecimal.ROUND_HALF_UP));
                fullNewMzDepositFiles.add(byjzNeedPayTemp);
                newMzDepositFiles.add(m);
                newMzDepositFiles.add(byjzNeedPayTemp);
                payWay = Constants.BYJZ;
            }
        }
        return payWay;
    }

    /**
     * 获取退费后新产生的缴费明细记录
     *
     * @param opId
     * @param mzDepositFileVo
     * @param yesNo           是否入库，入库，需要产生新的times
     * @return
     * @throws MzException
     */
    @Override
    public List<MzChargeDetail> getNewListForRefundFee(String opId, MzDepositFileVo mzDepositFileVo, YesNoEnum yesNo) throws MzException {
        //借用字段传参，实际是收费编码
        String chargeItemCodes = mzDepositFileVo.getChargeItemCodes();
        if (StringUtils.isBlank(chargeItemCodes)) {
            throw new MzException("没有选择需要退费的收费明细，无法退费");
        }
        List<String> chargeItemCodeList = Arrays.asList(chargeItemCodes.split(","));
        if (chargeItemCodeList == null || chargeItemCodeList.size() == 0) {
            throw new MzException("没有选择需要退费的收费明细，无法退费");
        }
        List<MzChargeDetail> mzChargeDetails = mzChargeDetailMapper.selectMzChargeDetailByPatientId(mzDepositFileVo.getPatientId(), mzDepositFileVo.getTimes(), mzDepositFileVo.getReceiptNo(), PayMarkEnum.CHARGED.code);
        if (mzChargeDetails == null || mzChargeDetails.size() == 0) {
            throw new MzException("当前病人无可退费用，无法退费");
        }
        if (ConfirmFlagEnum.CANCEL.code.equals(mzChargeDetails.get(0).getConfirmFlag())) {
            throw new MzException("当前病人已成功退费，请不要重复退费");
        }
        Date now = new Date();
        int times = mzDepositFileVo.getTimes();
        MzVisitTable lastMzVisitTable = mzVisitTableService.queryLastMzVisitTableByPatientId(mzDepositFileVo.getPatientId());
        if (lastMzVisitTable != null && lastMzVisitTable.getTimes() != null && lastMzVisitTable.getTimes() > times) {
            times = lastMzVisitTable.getTimes();
        }
        MzPatientMi mzPatientMi = mzPatientMiMapper.selectByPatientId(mzDepositFileVo.getPatientId());
        if (mzPatientMi == null) {
            throw new MzException("当前病人信息不存在，请先保存病人信息！");
        }
        if (mzPatientMi.getTimes() != null && mzPatientMi.getTimes() > times) {
            times = mzPatientMi.getTimes();
        }
        times++;
        if (YesNoEnum.YES.equals(yesNo)) {
            MzVisitTable newMzVisitTable = getMzVisitTable(opId, mzChargeDetails, times, now);
            mzVisitTableMapper.insertMzVisitTable(newMzVisitTable);
        }
        List<MzChargeDetail> newMzChargeDetailList = new ArrayList<>();
        Integer itemNo = 100;
        List<String> billItemCodeList = Arrays.asList(Constants.SSWRF);
        Set<String> tcNos = new HashSet<>();
        int receiptNo = 1;
        for (MzChargeDetail md : mzChargeDetails) {
            MzChargeDetail temp = null;
            if (chargeItemCodeList.contains(md.getOrderNo() + "_" + md.getItemNo() + "_" + md.getChargeItemCode())) {
                if (Constants.XYF.equals(md.getBillItemCode()) || Constants.ZCYF.equals(md.getBillItemCode())) {
                    if (ConfirmFlagEnum.DONE.code.equals(md.getConfirmFlag()) && md.getDecAmount() != null && md.getDecAmount().compareTo(BigDecimal.ZERO) == 1) {
                        Double oriQuantity = md.getQuantity();
                        BigDecimal surplus = BigDecimal.valueOf(md.getQuantity()).subtract(md.getDecAmount());
                        if (surplus.compareTo(BigDecimal.ZERO) == 1) {
                            temp = CloneUtil.clone(md);
                            temp.setQuantity(surplus.doubleValue());
                            //BigDecimal proportion = BigDecimal.valueOf(md.getQuantity()).divide(BigDecimal.valueOf(md.getSupplyAmount()),2,RoundingMode.HALF_UP);
                            //temp.setSupplyAmount(BigDecimal.valueOf(md.getQuantity()).divide(proportion).intValue());
                            BigDecimal origPrice = temp.getOrigPrice();
                            origPrice = origPrice == null ? BigDecimal.ZERO : origPrice;
                            BigDecimal unitPrice = temp.getUnitPrice();
                            unitPrice = unitPrice == null ? BigDecimal.ZERO : unitPrice;
                            //如果原价大于单价，说明是皮试自备
                            if (origPrice.compareTo(unitPrice) == 1) {
                                //如果只剩一直，单价为0
                                if (surplus.compareTo(BigDecimal.ONE) == 0) {
                                    temp.setUnitPrice(BigDecimal.ZERO);
                                } else {
                                    temp.setUnitPrice(BigDecimal.valueOf(oriQuantity).multiply(md.getUnitPrice()).subtract(md.getDecAmount().multiply(md.getOrigPrice())).divide(surplus));
                                }
                            }
                        }
                    }
                } else if (Constants.CYF.equals(md.getBillItemCode())) {
                    //中药和诊疗需要整退
                    tcNos.add(md.getTcNo());
                }
            } else {
                if (!billItemCodeList.contains(md.getBillItemCode()) && !tcNos.contains(md.getTcNo())) {
                    //当前项目不退，需要新增到新的收费记录中 四舍五入的必须退掉，因为需要重新计算，如果没有选中四舍五入，则默认去除  医技项目是按照套餐开的，如果退了某个套餐的明细，整个套餐全部退掉
                    temp = CloneUtil.clone(md);
                }
            }
            if (temp != null) {
//                if (receiptNo == 1) {
//                    receiptNo = temp.getReceiptNo() + 1;
//                }
                temp.setTimes(times);
                temp.setReceiptNo(receiptNo);
                temp.setItemNo(itemNo++);
                temp.setSerialNo(null);
                temp.setPayMark(PayMarkEnum.NO_CHARGE.code);
                temp.setChargeDate(null);
                temp.setConfirmTime(null);
                temp.setConfirmId(null);
                temp.setInputDate(now);
                temp.setPriceTime(now);
                temp.setPrintFlag(YesNoEnum.NO.code.toString());
                temp.setConfirmFlag(ConfirmFlagEnum.NOT_CONFIRM.code.equals(temp.getConfirmFlag()) ? ConfirmFlagEnum.NOT_CONFIRM.code : ConfirmFlagEnum.CONFIRM.code);
                temp.setCashId(null);
                temp.setRealNo(null);
                temp.setDecAmount(BigDecimal.ZERO);
                temp.setBackSerial(null);
                temp.setPrintFlagYj(null);
                temp.setConfirmFlagQx(null);
                newMzChargeDetailList.add(temp);
            }
        }
        List<MzChargeDetail> supplyFeeMzChargeDetails = new ArrayList<>();
        //重新计算给药方式费用
        //   itemNo = formatSupplyFee(supplyFeeMzChargeDetails, newMzChargeDetailList, itemNo);
        formatPriceRoundDetail(new MzChargeDetail(mzDepositFileVo.getPatientId(), times), supplyFeeMzChargeDetails, mzPatientMi, newMzChargeDetailList, 127, itemNo, receiptNo, false);
//        List<String> supplyList = supplyFeeMzChargeDetails.stream().filter(u -> StringUtils.isNotBlank(u.getChargeItemCode())).map-util.js(u -> u.getChargeItemCode()).collect(Collectors.toList());
//        List<MzChargeDetail> removeList = new ArrayList<>();
//        for (MzChargeDetail md : newMzChargeDetailList) {
//            if (supplyList.contains(md.getChargeItemCode())) {
//                removeList.add(md);
//                continue;
//            }
//            md.setConfirmFlag(ConfirmFlagEnum.NOT_CONFIRM.code);
//        }
//        newMzChargeDetailList.removeAll(removeList);
//        newMzChargeDetailList.addAll(supplyFeeMzChargeDetails);
        removeOnlyTcItem(newMzChargeDetailList);
        return newMzChargeDetailList;
    }

    /**
     * 将仅剩套餐本身，无明细的套餐删除
     *
     * @param newMzChargeDetailList
     */
    private void removeOnlyTcItem(List<MzChargeDetail> newMzChargeDetailList) {
        if (newMzChargeDetailList.size() > 0) {
            Map<String, MzChargeDetail> chargeItemMap = new HashMap<>();
            Map<String, Integer> chargeItemCountMap = new HashMap<>();
            for (MzChargeDetail md : newMzChargeDetailList) {
                if (Constants.TC.equals(md.getBillItemCode())) {
                    chargeItemMap.put(md.getChargeItemCode(), md);
                } else if (StringUtils.isNotBlank(md.getTcNo())) {
                    Integer count = chargeItemCountMap.get(md.getTcNo());
                    if (count == null) {
                        count = 0;
                    }
                    count++;
                    chargeItemCountMap.put(md.getTcNo(), count);
                }
            }
            if (chargeItemMap.size() > 0) {
                for (String key : chargeItemMap.keySet()) {
                    Integer count = chargeItemCountMap.get(key);
                    if (count == null || count == 0) {
                        newMzChargeDetailList.remove(chargeItemMap.get(key));
                    }
                }
            }
        }
    }

    @Override
    public List<MzChargeDetail> getTempMzChargeDetailListForNewListForRefundFee(String opId, MzDepositFileVo mzDepositFileVo, YesNoEnum yesNo) throws MzException {
        List<MzChargeDetail> mzChargeDetails = getNewListForRefundFee(opId, mzDepositFileVo, YesNoEnum.NO);
        if (mzChargeDetails == null || mzChargeDetails.size() == 0) {
            return null;
        }
        List<MzChargeDetail> returnList = getMzChargeDetails(mzChargeDetails, mzDepositFileVo.getBillItemCode());
        return returnList;
    }

    @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.DEFAULT, timeout = 36000, rollbackFor = Exception.class)
    @Override
    public void saveMzChargeDetail(List<MzChargeDetail> mzChargeDetails) {
        if (mzChargeDetails.size() == 0) {
            return;
        }
        if (mzChargeDetails.size() <= 20) {
            mzChargeDetailMapper.batchInsertMzChargeDetail(mzChargeDetails);
        } else {
            List<MzChargeDetail> tempList = new ArrayList<>();
            for (MzChargeDetail md : mzChargeDetails) {
                tempList.add(md);
                if (tempList.size() == 20) {
                    mzChargeDetailMapper.batchInsertMzChargeDetail(tempList);
                    tempList.clear();
                }
            }
            if (tempList.size() > 0) {
                mzChargeDetailMapper.batchInsertMzChargeDetail(tempList);
            }
        }
    }

    private List<MzChargeDetail> getMzChargeDetails(List<MzChargeDetail> mzChargeDetails, String billItemCode) {
        List<MzChargeDetail> returnList = new ArrayList<>();
        List<String> xcyTypes = Arrays.asList("010", "011");
        String zcyType = "012";
        List<String> otherTypes = Arrays.asList("010", "011", "012", "020", "TC");
        for (MzChargeDetail md : mzChargeDetails) {
            if ("0".equals(billItemCode)) {
                if (xcyTypes.contains(md.getBillItemCode())) {
                    returnList.add(md);
                }
            } else if ("1".equals(billItemCode)) {
                if (zcyType.equals(md.getBillItemCode())) {
                    returnList.add(md);
                }
            } else if ("2".equals(billItemCode)) {
                if (!otherTypes.contains(md.getBillItemCode())) {
                    returnList.add(md);
                }
                //手机自助缴费的查看全部
            } else if ("100".equals(billItemCode)) {
                returnList.add(md);
            }
        }
        return returnList;
    }

    /**
     * 获取就诊记录信息
     *
     * @param opId
     * @param mzChargeDetails
     * @param times
     * @param now
     * @return
     */
    private MzVisitTable getMzVisitTable(String opId, List<MzChargeDetail> mzChargeDetails, int times, Date now) {
        MzChargeDetail tempMzChargeDetail = mzChargeDetails.get(0);
        MzVisitTable newMzVisitTable = new MzVisitTable();
        newMzVisitTable.setPatientId(tempMzChargeDetail.getPatientId());
        newMzVisitTable.setTimes(times);
        newMzVisitTable.setVisitDeptCode(tempMzChargeDetail.getWarnDept());
        newMzVisitTable.setDoctorCode(tempMzChargeDetail.getDoctorCode());
        newMzVisitTable.setVisitDate(now);
        newMzVisitTable.setOpId(opId);
        newMzVisitTable.setOpDay(now);
        newMzVisitTable.setFirstOrNot(times == 1 ? YesNoEnum.NO.code : YesNoEnum.YES.code);
        newMzVisitTable.setReceiveFlag(YesNoEnum.NO.code);
        newMzVisitTable.setResponceType(tempMzChargeDetail.getResponceType());
        return newMzVisitTable;
    }

    /**
     * 获取就诊记录信息
     *
     * @param mzPrescriptionVo
     * @param times
     * @param now
     * @return
     */
    private MzVisitTable getMzVisitTable(MzPrescriptionVo mzPrescriptionVo, int times, Date now, String responseType) {
        MzVisitTable newMzVisitTable = new MzVisitTable();
        newMzVisitTable.setPatientId(mzPrescriptionVo.getPatientId());
        newMzVisitTable.setTimes(times);
        newMzVisitTable.setVisitDeptCode(mzPrescriptionVo.getVisitDeptCode());
        newMzVisitTable.setDoctorCode(mzPrescriptionVo.getDoctorCode());
        newMzVisitTable.setVisitDate(now);
        newMzVisitTable.setOpId(mzPrescriptionVo.getDoctorCode());
        newMzVisitTable.setOpDay(now);
        newMzVisitTable.setFirstOrNot(times == 1 ? YesNoEnum.NO.code : YesNoEnum.YES.code);
        newMzVisitTable.setReceiveFlag(YesNoEnum.NO.code);
        newMzVisitTable.setResponceType(responseType);
        newMzVisitTable.setIcdCode(mzPrescriptionVo.getIcdCode());
        newMzVisitTable.setIcdText(mzPrescriptionVo.getIcdText());
        return newMzVisitTable;
    }


    /**
     * 设置药房参数
     *
     * @param mzDrugWinMap
     * @param yffyNoMap
     * @param orderNoMap
     * @param m
     * @throws MzException
     */
    private void setChargeDetail(Map<String, MzDrugWin> mzDrugWinMap, Map<String, Integer> yffyNoMap, Map<String, Integer> orderNoMap, MzChargeDetail m) throws MzException {
        if (StringUtils.isNotBlank(m.getGroupNo()) && !Constants.YJ_GROUP_NO.equals(m.getGroupNo())) {
            MzDrugWin mzDrugWin = mzDrugWinMap.get(m.getGroupNo());
            if (mzDrugWin == null) {
                mzDrugWin = mzDrugWinService.queryMinMzDrugWin(m.getGroupNo());
                if (mzDrugWin != null) {
                    mzDrugWinMap.put(m.getGroupNo(), mzDrugWin);
                }
            }
            if (mzDrugWin != null) {
                m.setWindowsNoYf(mzDrugWin.getWinNo());
            }
            Integer yffyNo = yffyNoMap.get(m.getGroupNo());
            if (yffyNo == null) {
                yffyNo = ypConfigService.getYfFyNo();
                if (yffyNo != null) {
                    yffyNoMap.put(m.getGroupNo(), yffyNo);
                }
            }
            if (yffyNo != null) {
                m.setBackSerial(yffyNo);
            }
            Integer orderNo = orderNoMap.get(m.getGroupNo());
            if (orderNo == null) {
                orderNoMap.put(m.getGroupNo(), m.getOrderNo());
            }
        }
    }

    /**
     * 构造发药队列
     *
     * @param patientId
     * @param times
     * @param name
     * @param now
     * @param serialNo
     * @param mzDrugWinMap
     * @param orderNoMap
     * @param key
     * @param yffyNo
     * @return
     */
    private MzYpFydl getMzYpFydl(String patientId, Integer times, String name, Date now, int serialNo, Map<String, MzDrugWin> mzDrugWinMap, Map<String, Integer> orderNoMap, String key, Integer yffyNo) {
        MzYpFydl mzYpFydl = new MzYpFydl();
        mzYpFydl.setPatientId(patientId);
        mzYpFydl.setTimes(times);
        mzYpFydl.setReceiptNo(1);
        mzYpFydl.setOrderNo(orderNoMap.get(key));
        mzYpFydl.setGroupNo(key);
        MzDrugWin mzDrugWin = mzDrugWinMap.get(key);
        if (mzDrugWin != null) {
            mzYpFydl.setWindowsNoYf(mzDrugWin.getWinNo());
        }
        mzYpFydl.setName(name);
        mzYpFydl.setOrderTime(now);
        mzYpFydl.setSerialNo(serialNo);
        mzYpFydl.setStatusFlag("3");
        mzYpFydl.setYfNo(yffyNo);
        return mzYpFydl;
    }

    /**
     * 设置收款方式的其他字段，并计算此时收款的总金额
     *
     * @param opId
     * @param mzDepositFileVo
     * @param windows
     * @param mzPatientMi
     * @param feeMap
     * @param now
     * @param serialNo
     * @param mzReceiptSerial
     * @return
     */
    private BigDecimal getHadPayable(String opId, MzDepositFileVo mzDepositFileVo, Windows windows, MzPatientMi mzPatientMi, Map<String, BigDecimal> feeMap, Date now, int serialNo, MzReceiptSerial mzReceiptSerial, Integer receiptNo, ReceiptSerialFee receiptSerialFee) {
        String chequeType = null;
        //总收款金额
        BigDecimal hadPayable = BigDecimal.ZERO;
        //排除记账的金额
        BigDecimal excludeByjzPay = BigDecimal.ZERO;
        //本院记账的金额
        BigDecimal byjzje = BigDecimal.ZERO;
        //医保记账的金额
        BigDecimal ybjzje = BigDecimal.ZERO;
        for (MzDepositFile m : mzDepositFileVo.getMzDepositFiles()) {
            if (m.getPatientId() == null) {
                //此时是直接收费，需要设置相关参数
                m.setPatientId(mzDepositFileVo.getPatientId());
                m.setTimes(mzDepositFileVo.getTimes());
                m.setReceiptNo(receiptNo);
                m.setPayMark(PayMarkEnum.CHARGED.code);
                m.setChargeDate(now);
                m.setDcountNo(YesNoEnum.NO.code);
                m.setOpId(opId);
                m.setReceiptSn(serialNo);
                m.setSerialNo(serialNo);
                m.setResponceType(mzPatientMi == null ? "" : mzPatientMi.getResponseType());
                m.setDeptNo(windows.getDeptNo());
            }
            hadPayable = hadPayable.add(m.getAmount());
            if (Constants.BYJZ.equals(m.getChequeType())) {
                if (chequeType == null) {
                    chequeType = Constants.BYJZ;
                }
                byjzje = byjzje.add(m.getAmount());
            } else if (Constants.YBJZ.equals(m.getChequeType())) {
                if (chequeType == null) {
                    chequeType = Constants.YBJZ;
                }
                ybjzje = ybjzje.add(m.getAmount());
            } else {
                excludeByjzPay = excludeByjzPay.add(m.getAmount());
                chequeType = m.getChequeType();
            }
        }
        receiptSerialFee.setZfTotalPayable(excludeByjzPay.setScale(2, BigDecimal.ROUND_FLOOR));
        receiptSerialFee.setByjzje(byjzje.setScale(2, BigDecimal.ROUND_FLOOR));
        receiptSerialFee.setYbjzje(ybjzje.setScale(2, BigDecimal.ROUND_FLOOR));
        hadPayable.setScale(2, BigDecimal.ROUND_FLOOR);
        setMzReceiptSerial(opId, mzDepositFileVo.getPatientId(), mzDepositFileVo.getTimes(), windows, mzPatientMi.getResponseType(), feeMap, now, serialNo, mzReceiptSerial, chequeType, receiptSerialFee, receiptNo);
        return hadPayable;
    }

    /**
     * 设置发票记录实体对象
     *
     * @param opId
     * @param patientId
     * @param times
     * @param windows
     * @param responseType
     * @param feeMap
     * @param now
     * @param serialNo
     * @param mzReceiptSerial
     * @param chequeType
     * @param receiptSerialFee
     */
    private void setMzReceiptSerial(String opId, String patientId, Integer times, Windows windows, String responseType, Map<String, BigDecimal> feeMap, Date now, int serialNo, MzReceiptSerial mzReceiptSerial, String chequeType, ReceiptSerialFee receiptSerialFee, Integer receiptNo) {
        mzReceiptSerial.setPatientId(patientId);
        mzReceiptSerial.setTimes(times);
        mzReceiptSerial.setReceiptNo(receiptNo);
        mzReceiptSerial.setSerialNo(serialNo);
        mzReceiptSerial.setOperatorId(opId);
        mzReceiptSerial.setPayId(opId);
        mzReceiptSerial.setCharge1(feeMap.get(Constants.GHF) == null ? BigDecimal.ZERO : feeMap.get(Constants.GHF).setScale(2, BigDecimal.ROUND_HALF_UP));
        mzReceiptSerial.setCharge2(feeMap.get(Constants.CWF) == null ? BigDecimal.ZERO : feeMap.get(Constants.CWF).setScale(2, BigDecimal.ROUND_HALF_UP));
        mzReceiptSerial.setCharge3(feeMap.get(Constants.ZCF) == null ? BigDecimal.ZERO : feeMap.get(Constants.ZCF).setScale(2, BigDecimal.ROUND_HALF_UP));
        mzReceiptSerial.setCharge4(feeMap.get(Constants.JCF) == null ? BigDecimal.ZERO : feeMap.get(Constants.JCF).setScale(2, BigDecimal.ROUND_HALF_UP));
        mzReceiptSerial.setCharge5(feeMap.get(Constants.ZLF) == null ? BigDecimal.ZERO : feeMap.get(Constants.ZLF).setScale(2, BigDecimal.ROUND_HALF_UP));
        mzReceiptSerial.setCharge6(feeMap.get(Constants.HLF) == null ? BigDecimal.ZERO : feeMap.get(Constants.HLF).setScale(2, BigDecimal.ROUND_HALF_UP));
        mzReceiptSerial.setCharge7(feeMap.get(Constants.SSF) == null ? BigDecimal.ZERO : feeMap.get(Constants.SSF).setScale(2, BigDecimal.ROUND_HALF_UP));
        mzReceiptSerial.setCharge8(feeMap.get(Constants.HYF) == null ? BigDecimal.ZERO : feeMap.get(Constants.HYF).setScale(2, BigDecimal.ROUND_HALF_UP));
        mzReceiptSerial.setCharge9(feeMap.get(Constants.QTF) == null ? BigDecimal.ZERO : feeMap.get(Constants.QTF).setScale(2, BigDecimal.ROUND_HALF_UP));
        mzReceiptSerial.setCharge10(feeMap.get(Constants.XYF) == null ? BigDecimal.ZERO : feeMap.get(Constants.XYF).setScale(2, BigDecimal.ROUND_HALF_UP));
        mzReceiptSerial.setCharge11(feeMap.get(Constants.ZCYF) == null ? BigDecimal.ZERO : feeMap.get(Constants.ZCYF).setScale(2, BigDecimal.ROUND_HALF_UP));
        mzReceiptSerial.setCharge12(feeMap.get(Constants.CYF) == null ? BigDecimal.ZERO : feeMap.get(Constants.CYF).setScale(2, BigDecimal.ROUND_HALF_UP));
        mzReceiptSerial.setCharge13(feeMap.get(Constants.TSCLF) == null ? BigDecimal.ZERO : feeMap.get(Constants.TSCLF).setScale(2, BigDecimal.ROUND_HALF_UP));
        mzReceiptSerial.setCharge14(feeMap.get(Constants.SXF) == null ? BigDecimal.ZERO : feeMap.get(Constants.SXF).setScale(2, BigDecimal.ROUND_HALF_UP));
        mzReceiptSerial.setCharge15(feeMap.get(Constants.JDF) == null ? BigDecimal.ZERO : feeMap.get(Constants.JDF).setScale(2, BigDecimal.ROUND_HALF_UP));
        mzReceiptSerial.setCharge16(feeMap.get(Constants.XDF) == null ? BigDecimal.ZERO : feeMap.get(Constants.XDF).setScale(2, BigDecimal.ROUND_HALF_UP));
        mzReceiptSerial.setCharge17(feeMap.get(Constants.SSQXSSF) == null ? BigDecimal.ZERO : feeMap.get(Constants.SSQXSSF).setScale(2, BigDecimal.ROUND_HALF_UP));
        mzReceiptSerial.setCharge18(feeMap.get(Constants.CLF) == null ? BigDecimal.ZERO : feeMap.get(Constants.CLF).setScale(2, BigDecimal.ROUND_HALF_UP));
        mzReceiptSerial.setCharge19(feeMap.get(Constants.MZF) == null ? BigDecimal.ZERO : feeMap.get(Constants.MZF).setScale(2, BigDecimal.ROUND_HALF_UP));
        mzReceiptSerial.setCharge20(feeMap.get(Constants.SSWRF) == null ? BigDecimal.ZERO : feeMap.get(Constants.SSWRF).setScale(2, BigDecimal.ROUND_HALF_UP));
        mzReceiptSerial.setPayMark(PayMarkEnum.CHARGED.code);
        mzReceiptSerial.setTotalCharge(receiptSerialFee.getZfTotalPayable());
        mzReceiptSerial.setChargeDate(now);
        mzReceiptSerial.setChequeType(chequeType);
        mzReceiptSerial.setReceiptSn(serialNo);
        mzReceiptSerial.setReceiptBill("");
        mzReceiptSerial.setWindowsNo(windows.getWindowsNo().toString());
        mzReceiptSerial.setDcountNo(YesNoEnum.NO.code);
        mzReceiptSerial.setChargeDcountNo(YesNoEnum.NO.code);
        mzReceiptSerial.setResponceType(responseType);
        mzReceiptSerial.setTfFlag(YesNoEnum.NO.code);
        mzReceiptSerial.setDeptNo(windows.getDeptNo());
    }

    /**
     * 将所有的欠费时间转成集合形式的参数
     *
     * @param mzDepositFileVo
     * @return
     */
    private List<Integer> getTimes(MzDepositFileVo mzDepositFileVo) {
        List<String> arr = Arrays.asList(mzDepositFileVo.getChargeItemCodes().split(","));
        List<Integer> times = new ArrayList<>();
        if (arr != null && arr.size() > 0) {
            CollectionUtils.collect(arr, new Transformer() {
                @Override
                public Object transform(Object o) {
                    return Integer.valueOf(o.toString());
                }
            }, times);
        }
        return times;
    }

    /**
     * 根据已经存在本院记账记录产生新的退款记录和重收记录
     *
     * @param opId
     * @param mzDepositFileVo
     * @param now
     * @param serialNo
     * @return
     */
    private List<MzReceiptSerial> getMzReceiptSerials(String opId, MzDepositFileVo mzDepositFileVo, Date now, int serialNo) {
        List<MzReceiptSerial> newList = new ArrayList<>();
        List<MzReceiptSerial> mzReceiptSerials = mzReceiptSerialMapper.selectReceiptDetails(mzDepositFileVo.getPatientId(), mzDepositFileVo.getTimes(), mzDepositFileVo.getReceiptNo(), "mz_receipt_serial");
        if (mzReceiptSerials != null && mzReceiptSerials.size() > 0) {
            mzReceiptSerials.stream().forEach(j -> {
                if (Constants.BYJZ.equals(j.getChequeType())) {
                    MzReceiptSerial newMzReceiptSerial = CloneUtil.clone(j);
                    if (newMzReceiptSerial != null) {
                        newMzReceiptSerial.setReceiptNo(newMzReceiptSerial.getReceiptNo() + 1);
                        newMzReceiptSerial.setDcountNo(YesNoEnum.NO.code);
                        newMzReceiptSerial.setDcountDate(null);
                        newMzReceiptSerial.setChargeDcountNo(YesNoEnum.NO.code);
                        newMzReceiptSerial.setChargeDcountDate(null);
                        newMzReceiptSerial.setChargeDate(now);
                        newMzReceiptSerial.setSerialNo(serialNo);
                        newMzReceiptSerial.setOperatorId(opId);
                        newMzReceiptSerial.setPayId(opId);
                        newMzReceiptSerial.setReceiptSn(serialNo);
                        newMzReceiptSerial.setReceiptBill("");
                        //本院记账被实际收费后设置
                        newMzReceiptSerial.setFpFlag(Constants.BYJZ);
                        newMzReceiptSerial.setChequeType(mzDepositFileVo.getMzDepositFiles().get(0).getChequeType());
                        newList.add(newMzReceiptSerial);
                    }
                    j.setReceiptNo(0 - j.getReceiptNo());
                    j.setCharge1(BigDecimal.ZERO.subtract(j.getCharge1()));
                    j.setCharge2(BigDecimal.ZERO.subtract(j.getCharge2()));
                    j.setCharge3(BigDecimal.ZERO.subtract(j.getCharge3()));
                    j.setCharge4(BigDecimal.ZERO.subtract(j.getCharge4()));
                    j.setCharge5(BigDecimal.ZERO.subtract(j.getCharge5()));
                    j.setCharge6(BigDecimal.ZERO.subtract(j.getCharge6()));
                    j.setCharge7(BigDecimal.ZERO.subtract(j.getCharge7()));
                    j.setCharge8(BigDecimal.ZERO.subtract(j.getCharge8()));
                    j.setCharge9(BigDecimal.ZERO.subtract(j.getCharge9()));
                    j.setCharge10(BigDecimal.ZERO.subtract(j.getCharge10()));
                    j.setCharge11(BigDecimal.ZERO.subtract(j.getCharge11()));
                    j.setCharge12(BigDecimal.ZERO.subtract(j.getCharge12()));
                    j.setCharge13(BigDecimal.ZERO.subtract(j.getCharge13()));
                    j.setCharge14(BigDecimal.ZERO.subtract(j.getCharge14()));
                    j.setCharge15(BigDecimal.ZERO.subtract(j.getCharge15()));
                    j.setCharge16(BigDecimal.ZERO.subtract(j.getCharge16()));
                    j.setCharge17(BigDecimal.ZERO.subtract(j.getCharge17()));
                    j.setCharge18(BigDecimal.ZERO.subtract(j.getCharge18()));
                    j.setCharge19(BigDecimal.ZERO.subtract(j.getCharge19()));
                    j.setCharge20(BigDecimal.ZERO.subtract(j.getCharge20()));
                    j.setTotalCharge(BigDecimal.ZERO.subtract(j.getTotalCharge()));
                    j.setReceiptSn(0 - j.getReceiptSn());
                    j.setSerialNo(0 - j.getSerialNo());
                    j.setPayMark(PayMarkEnum.RETURN_PREMIUM.code);
                    j.setChargeDate(now);
                    j.setTfFlag(YesNoEnum.YES.code);
                    j.setDcountNo(YesNoEnum.NO.code);
                    j.setDcountDate(null);
                    j.setChargeDcountNo(YesNoEnum.NO.code);
                    j.setChargeDcountDate(null);
                    j.setOperatorId(opId);
                    j.setPayId(opId);
                    newList.add(j);
                }
            });
        }
        return newList;
    }

    /**
     * 根据已经存在本院记账记录产生新的退款记录和重收记录
     *
     * @param mzDepositFileVo
     * @param now
     * @param serialNo
     * @return
     */
    private List<MzDepositFile> getMzDepositFiles(MzDepositFileVo mzDepositFileVo, Date now, int serialNo, String opId) {
        List<MzDepositFile> newList = new ArrayList<>();
        List<MzDepositFile> mzDepositFiles = mzDepositFileMapper.selectMzDepositFileByTimes(mzDepositFileVo.getPatientId(), mzDepositFileVo.getTimes(), mzDepositFileVo.getReceiptNo(), "mz_deposit_file");
        if (mzDepositFiles == null || mzDepositFiles.size() == 0) {
            mzDepositFiles = mzDepositFileMapper.selectMzDepositFileByTimesInHisData(mzDepositFileVo.getPatientId(), mzDepositFileVo.getTimes(), mzDepositFileVo.getReceiptNo());
        }
        if (mzDepositFiles != null && mzDepositFiles.size() > 0) {
            mzDepositFiles.stream().forEach(j -> {
                if (Constants.BYJZ.equals(j.getChequeType())) {
                    MzDepositFile newMzDepositFile = CloneUtil.clone(j);
                    if (newMzDepositFile != null) {
                        newMzDepositFile.setReceiptNo(newMzDepositFile.getReceiptNo() + 1);
                        newMzDepositFile.setDcountNo(YesNoEnum.NO.code);
                        newMzDepositFile.setDcountDate(null);
                        newMzDepositFile.setChargeDate(now);
                        newMzDepositFile.setSerialNo(serialNo);
                        newMzDepositFile.setReceiptSn(serialNo);
                        newMzDepositFile.setChequeType(mzDepositFileVo.getMzDepositFiles().get(0).getChequeType());
                        newMzDepositFile.setOpId(opId);
                        newList.add(newMzDepositFile);
                    }
                    j.setReceiptNo(0 - j.getReceiptNo());
                    j.setAmount(BigDecimal.ZERO.subtract(j.getAmount()));
                    j.setReceiptSn(0 - j.getReceiptSn());
                    j.setSerialNo(0 - j.getSerialNo());
                    j.setPayMark(PayMarkEnum.RETURN_PREMIUM.code);
                    j.setChargeDate(now);
                    j.setOpId(opId);
                    j.setDcountDate(null);
                    j.setDcountNo(YesNoEnum.NO.code);
                    newList.add(j);
                }
            });
        }
        return newList;
    }

    /**
     * 根据已经存在本院记账记录产生新的退款记录和重收记录
     *
     * @param opId
     * @param mzDepositFileVo
     * @param now
     * @param serialNo
     * @return
     */
    private List<MzChargeDetail> getMzChargeDetails(String opId, MzDepositFileVo mzDepositFileVo, Date now, int serialNo) {
        List<MzChargeDetail> newList = new ArrayList<>();
        List<MzChargeDetail> jiZhangDetails = mzChargeDetailMapper.selectJiZhangDetails(mzDepositFileVo.getPatientId(), mzDepositFileVo.getTimes(), mzDepositFileVo.getReceiptNo());
        if (jiZhangDetails != null && jiZhangDetails.size() > 0) {
            jiZhangDetails.stream().forEach(j -> {
                MzChargeDetail newMzChargeDetail = CloneUtil.clone(j);
                if (newMzChargeDetail != null) {
                    newMzChargeDetail.setReceiptNo(newMzChargeDetail.getReceiptNo() + 1);
                    newMzChargeDetail.setChargeDate(now);
                    newMzChargeDetail.setSerialNo(serialNo);
                    newMzChargeDetail.setRealNo(serialNo);
                    newMzChargeDetail.setCashId(opId);
                    newMzChargeDetail.setChequType(null);
                    newList.add(newMzChargeDetail);
                }
                j.setReceiptNo(0 - j.getReceiptNo());
                j.setQuantity(0 - j.getQuantity());
                j.setSerialNo(0 - j.getSerialNo());
                j.setRealNo(0 - j.getRealNo());
                j.setPayMark(PayMarkEnum.RETURN_PREMIUM.code);
                j.setInputDate(now);
            });
            newList.addAll(jiZhangDetails);
        }
        return newList;
    }


    /**
     * 获取实际应付金额，并将费用按照类型分类
     *
     * @param mzChargeDetailList
     * @param feeMap
     * @param needDiscount       是否需要做优惠计算
     * @return
     */
    private BigDecimal getTotalPayable(List<MzChargeDetail> mzChargeDetailList, Map<String, BigDecimal> feeMap, boolean needDiscount) {
        BigDecimal totalPayable = BigDecimal.ZERO;
        if (mzChargeDetailList != null && mzChargeDetailList.size() > 0) {
            for (MzChargeDetail mzChargeDetail : mzChargeDetailList) {
                String billItemCode = mzChargeDetail.getBillItemCode();
                if (Constants.TC.equals(billItemCode)) {
                    continue;
                }
                BigDecimal unitPrice = mzChargeDetail.getUnitPrice() == null ? BigDecimal.ZERO : mzChargeDetail.getUnitPrice().setScale(2, BigDecimal.ROUND_HALF_UP);
                if (!Constants.TC.equals(mzChargeDetail.getBillItemCode()) && BigDecimal.ZERO.compareTo(unitPrice) == 0) {
                    unitPrice = BigDecimal.valueOf(0.01D);
                    log.error("有为空的单价项目，费用明细具体如下{}", mzChargeDetail.toString());
                    mzChargeDetail.setUnitPrice(unitPrice);
                }
                //进行营销折扣计算并写入库 优先申请科室的折扣率  医生系统做完移走开始
                if (needDiscount) {
                    mzChargeDetail.setOrigPrice(unitPrice);
                    Discount discount = null;
                    if (StringUtils.isNotBlank(mzChargeDetail.getWarnDept())) {
                        discount = discountService.getDiscountRate(YesNoEnum.NO.code, mzChargeDetail.getWarnDept(), mzChargeDetail.getChargeItemCode());
                    }
                    if (discount == null && StringUtils.isNotBlank(mzChargeDetail.getExecDept())) {
                        discount = discountService.getDiscountRate(YesNoEnum.NO.code, mzChargeDetail.getExecDept(), mzChargeDetail.getChargeItemCode());
                    }
                    if (discount != null) {
                        if (YesNoEnum.YES.code.equals(discount.getDiscountType())) {
                            unitPrice = discount.getDiscountRate().multiply(mzChargeDetail.getUnitPrice()).setScale(2, BigDecimal.ROUND_HALF_UP);
                        } else {
                            unitPrice = discount.getDiscountPrice();
                        }
                        mzChargeDetail.setUnitPrice(unitPrice);
                    }
                }
                //医生系统做完移走 结尾
                BigDecimal tempFee = unitPrice.multiply(BigDecimal.valueOf(mzChargeDetail.getQuantity()).multiply(BigDecimal.valueOf(mzChargeDetail.getDrugWin())));
                totalPayable = totalPayable.add(tempFee);
                if (StringUtils.isBlank(billItemCode)) {
                    billItemCode = Constants.QTF;
                }
                BigDecimal temp = feeMap.get(billItemCode);
                if (temp == null) {
                    temp = tempFee;
                } else {
                    temp = temp.add(tempFee);
                }
                feeMap.put(billItemCode, temp);
            }
        }
        return totalPayable.setScale(2, BigDecimal.ROUND_FLOOR);
    }

    /**
     * 将总金额的零头转做四舍五入的收费明细记录
     *
     * @param mzChargeDetail
     * @param mzChargeDetails
     * @param mzPatientMi
     * @param mzChargeDetailList
     * @param maxOrderNo
     * @param itemNo
     * @param needDiscount       是否需要做优惠计算
     */
    private void formatPriceRoundDetail(MzChargeDetail mzChargeDetail, List<MzChargeDetail> mzChargeDetails, MzPatientMi mzPatientMi, List<MzChargeDetail> mzChargeDetailList, Integer maxOrderNo, Integer itemNo, Integer receiptNo, boolean needDiscount) {
        List<MzChargeDetail> temp = new ArrayList<>();
        temp.addAll(mzChargeDetailList);
        temp.addAll(mzChargeDetails);
        if (temp != null && temp.size() > 0) {
            BigDecimal totalFee = BigDecimal.ZERO;
            //所有应收费用的明细 将所有费用按照类型归类
            Map<String, BigDecimal> feeMap = new HashMap<>();
            //实际应付金额
            getTotalPayable(temp, feeMap, needDiscount);
            for (String key : feeMap.keySet()) {
                BigDecimal amount = feeMap.get(key).setScale(2, BigDecimal.ROUND_HALF_UP);
                totalFee = totalFee.add(amount);
            }
            totalFee = totalFee.setScale(2, BigDecimal.ROUND_HALF_UP);
            BigDecimal realTotal = totalFee.setScale(1, BigDecimal.ROUND_HALF_UP);
            BigDecimal sZero = realTotal.subtract(totalFee);
            if (sZero.compareTo(BigDecimal.ZERO) != 0) {
                MzChargeDetail newMzChargeDetail = new MzChargeDetail();
                newMzChargeDetail.setPatientId(mzChargeDetail.getPatientId());
                newMzChargeDetail.setTimes(mzChargeDetail.getTimes());
                newMzChargeDetail.setReceiptNo(receiptNo);
                newMzChargeDetail.setOrderNo(maxOrderNo);
                newMzChargeDetail.setItemNo(itemNo++);
                newMzChargeDetail.setChargeItemCode(Constants.SSWR_CHARGE_ITEM_CODE);
                newMzChargeDetail.setBillItemCode(Constants.SSWRF);
                newMzChargeDetail.setQuantity(1D);
                newMzChargeDetail.setUnitPrice(sZero);
                newMzChargeDetail.setPayMark(PayMarkEnum.NO_CHARGE.code);
                newMzChargeDetail.setSerial(Constants.YJ_GROUP_NO);
                newMzChargeDetail.setSerialNo(0);
                newMzChargeDetail.setName(mzPatientMi.getName());
                newMzChargeDetail.setGroupNo(Constants.YJ_GROUP_NO);
                newMzChargeDetail.setDrugWin(1);
                newMzChargeDetail.setPriceId(temp.get(0).getPriceId());
                newMzChargeDetail.setPriceTime(temp.get(0).getPriceTime());
                newMzChargeDetail.setExecDept(temp.get(0).getExecDept());
                newMzChargeDetail.setPrintFlag(YesNoEnum.NO.code.toString());
                newMzChargeDetail.setConfirmFlag(ConfirmFlagEnum.NOT_CONFIRM.code);
                newMzChargeDetail.setWarnDept(temp.get(0).getWarnDept());
                newMzChargeDetail.setJzFlag(temp.get(0).getJzFlag());
                newMzChargeDetail.setDoctorCode(temp.get(0).getDoctorCode());
                newMzChargeDetail.setDoctorFlag(YesNoEnum.YES.code.toString());
                newMzChargeDetail.setInjectRes(Double.valueOf(YesNoEnum.YES.code));
                newMzChargeDetail.setRealNo(0);
                newMzChargeDetail.setYbbxFlag(YesNoEnum.NO.code.toString());
                newMzChargeDetail.setDetailFlag(YesNoEnum.NO.code.toString());
                newMzChargeDetail.setOrderType(YesNoEnum.YES.code.toString());
                newMzChargeDetail.setSupplyNo("Y");
                newMzChargeDetail.setReqNo(0);
                newMzChargeDetail.setGroupType(GroupTypeEnum.DIAGNOSIS.code);
                newMzChargeDetail.setOrderBill(0);
                newMzChargeDetail.setChargeBillCode(Constants.SSWR_BILL_ITEM_CODE);
                newMzChargeDetail.setSelfFlag(YesNoEnum.NO.code.toString());
                newMzChargeDetail.setResponceType(mzPatientMi != null ? mzPatientMi.getResponseType() : ResponceTypeEnum.SELF_PAYING.code);
                newMzChargeDetail.setGlPercentFt(BigDecimal.ONE);
                newMzChargeDetail.setOrigPrice(newMzChargeDetail.getUnitPrice());
                newMzChargeDetail.setTcName("四舍五入");
                newMzChargeDetail.setReqYj(YesNoEnum.YES.code.toString());
                mzChargeDetails.add(newMzChargeDetail);
            }
        }
    }

    /**
     * 将抽血费用转成收费明细记录
     *
     * @param mzChargeDetail
     * @param mzChargeDetails
     * @param mzPatientMi
     * @param maxOrderNo
     * @param itemNo
     * @param mzYjReqMap
     * @param jianYans
     * @return
     */
    private Integer formatCxFeeItem(MzChargeDetail mzChargeDetail, List<MzChargeDetail> mzChargeDetails, MzPatientMi mzPatientMi, Integer maxOrderNo, Integer itemNo, Map<String, MzYjReq> mzYjReqMap, List<String> jianYans, Map<String, MzChargeDetail> tcNoMap, String priceId, Date priceTime, Integer receiptNo) throws MzException {
        List<JyZdItem> jyZdItems = jyZdItemService.queryCxTimesByCodeList(jianYans);
        MzYjReq mzYjReq = mzYjReqMap.get(jianYans.get(0));
        if (jyZdItems != null && jyZdItems.size() > 0) {
            Set<String> vesselSets = new HashSet<>();
            for (JyZdItem jyZdItem : jyZdItems) {
                if (jyZdItem != null) {
                    if (StringUtils.isNotBlank(jyZdItem.getVessel()) && !vesselSets.contains(jyZdItem.getVessel())) {
                        itemNo = formatVesselFee(mzChargeDetail, mzChargeDetails, mzPatientMi, maxOrderNo, itemNo, mzYjReq, vesselSets, jyZdItem, tcNoMap, priceId, priceTime, receiptNo);
                    }
                }
            }
            ZdChargeItem zdChargeItem = zdChargeItemService.queryZdChargeItemByCode(Constants.JM_CAI_XUE_CODE);
            if (zdChargeItem == null) {
                //  throw new MzException("【收费编码：008910】不存在,请联系物价科确认！");
                return itemNo;
            }
            if (YesNoEnum.YES.code.equals(zdChargeItem.getDelFlag())) {
                throw new MzException("收费项目【" + zdChargeItem.getName() + "(编码" + zdChargeItem.getCode() + ")】被停用,请联系物价科确认！");
            }
            MzChargeDetail newMzChargeDetail = new MzChargeDetail();
            newMzChargeDetail.setPatientId(mzChargeDetail.getPatientId());
            newMzChargeDetail.setTimes(mzChargeDetail.getTimes());
            newMzChargeDetail.setReceiptNo(receiptNo);
            if (mzYjReq.getOrderNo() != null && mzYjReq.getOrderNo() > 0) {
                newMzChargeDetail.setOrderNo(mzYjReq.getOrderNo());
            } else {
                newMzChargeDetail.setOrderNo(maxOrderNo);
            }
            newMzChargeDetail.setItemNo(itemNo++);
            newMzChargeDetail.setChargeItemCode(Constants.JM_CAI_XUE_CODE);
            if (zdChargeItem.getChargeAmount() == null || zdChargeItem.getPercentag1() == null) {
                newMzChargeDetail.setUnitPrice(BigDecimal.ZERO);
                newMzChargeDetail.setOrigPrice(BigDecimal.ZERO);
            } else {
                newMzChargeDetail.setUnitPrice(zdChargeItem.getChargeAmount().multiply(zdChargeItem.getPercentag1()));
                newMzChargeDetail.setBillItemCode(zdChargeItem.getBillItemMz());
                newMzChargeDetail.setOrigPrice(zdChargeItem.getChargeAmount());
            }
            newMzChargeDetail.setQuantity(1D);
            newMzChargeDetail.setPayMark(PayMarkEnum.NO_CHARGE.code);
            newMzChargeDetail.setSerial("");
            newMzChargeDetail.setSerialNo(0);
            newMzChargeDetail.setName(mzYjReq.getPatientName());
            newMzChargeDetail.setGroupNo(Constants.YJ_GROUP_NO);
            newMzChargeDetail.setDrugWin(1);
            newMzChargeDetail.setPriceId(priceId == null ? mzYjReq.getReqDoctor() : priceId);
            newMzChargeDetail.setPriceTime(priceTime == null ? mzYjReq.getReqDate() : priceTime);
            newMzChargeDetail.setExecDept(mzYjReq.getExecDept());
            newMzChargeDetail.setPrintFlag(YesNoEnum.NO.code.toString());
            newMzChargeDetail.setConfirmFlag(ConfirmFlagEnum.NOT_CONFIRM.code);
            newMzChargeDetail.setWarnDept(mzYjReq.getReqWard());
            newMzChargeDetail.setJzFlag(mzYjReq.getJzFlag() == null ? YesNoEnum.NO.code.toString() : mzYjReq.getJzFlag());
            newMzChargeDetail.setDoctorCode(mzYjReq.getReqDoctor());
            newMzChargeDetail.setDoctorFlag(YesNoEnum.YES.code.toString());
            newMzChargeDetail.setInjectRes(Double.valueOf(YesNoEnum.YES.code));
            newMzChargeDetail.setRealNo(0);
            newMzChargeDetail.setYbbxFlag(YesNoEnum.NO.code.toString());
            newMzChargeDetail.setTcNo(tcNoMap.get(jianYans.get(0)).getChargeItemCode());
            newMzChargeDetail.setTcName(Constants.JM_CAI_XUE_NAME);
            newMzChargeDetail.setDetailFlag(YesNoEnum.NO.code.toString());
            newMzChargeDetail.setOrderType(YesNoEnum.YES.code.toString());
            newMzChargeDetail.setSupplyNo("Y");
            newMzChargeDetail.setReqNo(StringUtils.isNotBlank(mzYjReq.getOrderCode()) ? Integer.valueOf(mzYjReq.getOrderCode()) : null);
            newMzChargeDetail.setGroupType(GroupTypeEnum.DIAGNOSIS.code);
            newMzChargeDetail.setOrderBill(0);
            String chargeBillCode = Constants.BILL_ITEM_CODE_prev + zdChargeItem.getBillItemMz().substring(1);
            newMzChargeDetail.setChargeBillCode(chargeBillCode);
            newMzChargeDetail.setSelfFlag(YesNoEnum.NO.code.toString());
            newMzChargeDetail.setResponceType(mzPatientMi != null ? mzPatientMi.getResponseType() : ResponceTypeEnum.SELF_PAYING.code);
            newMzChargeDetail.setGlPercentFt(BigDecimal.ONE);
            newMzChargeDetail.setReqYj(YesNoEnum.YES.code.toString());
            mzChargeDetails.add(newMzChargeDetail);
        }
        return itemNo;
    }

    /**
     * 将容器费用转成收费明细记录
     *
     * @param mzChargeDetail
     * @param mzChargeDetails
     * @param mzPatientMi
     * @param maxOrderNo
     * @param itemNo
     * @param mzYjReq
     * @param vesselSets
     * @param jyZdItem
     * @return
     */
    private Integer formatVesselFee(MzChargeDetail mzChargeDetail, List<MzChargeDetail> mzChargeDetails, MzPatientMi mzPatientMi, Integer maxOrderNo, Integer itemNo, MzYjReq mzYjReq, Set<String> vesselSets, JyZdItem jyZdItem, Map<String, MzChargeDetail> tcNoMap, String priceId, Date priceTime, Integer receiptNo) throws MzException {
        JyZdTubeCharge jyZdTubeCharge = jyZdTubeChargeService.queryJyZdTubeChargeByCode(jyZdItem.getVessel());
        if (jyZdTubeCharge != null) {
            ZdChargeItem zdChargeItem = zdChargeItemService.queryZdChargeItemByCode(jyZdTubeCharge.getChargeCode());
            if (zdChargeItem == null) {
                //throw new MzException("【收费编码：" + jyZdTubeCharge.getChargeCode() + "】不存在,请联系物价科确认！");
                return itemNo;
            }
            if (YesNoEnum.YES.code.equals(zdChargeItem.getDelFlag())) {
                throw new MzException("收费项目【" + zdChargeItem.getName() + "(编码" + zdChargeItem.getCode() + ")】被停用,请联系物价科确认！");
            }
            MzChargeDetail newMzChargeDetail = new MzChargeDetail();
            newMzChargeDetail.setPatientId(mzChargeDetail.getPatientId());
            newMzChargeDetail.setTimes(mzChargeDetail.getTimes());
            newMzChargeDetail.setReceiptNo(receiptNo);
            if (mzYjReq.getOrderNo() != null && mzYjReq.getOrderNo() > 0) {
                newMzChargeDetail.setOrderNo(mzYjReq.getOrderNo());
            } else {
                newMzChargeDetail.setOrderNo(maxOrderNo);
            }
            newMzChargeDetail.setItemNo(itemNo++);
            newMzChargeDetail.setChargeItemCode(jyZdTubeCharge.getChargeCode());
            if (zdChargeItem.getChargeAmount() == null || zdChargeItem.getPercentag1() == null) {
                newMzChargeDetail.setUnitPrice(BigDecimal.ZERO);
                newMzChargeDetail.setOrigPrice(BigDecimal.ZERO);
            } else {
                newMzChargeDetail.setUnitPrice(zdChargeItem.getChargeAmount().multiply(zdChargeItem.getPercentag1()));
                newMzChargeDetail.setBillItemCode(zdChargeItem.getBillItemMz());
                newMzChargeDetail.setOrigPrice(zdChargeItem.getChargeAmount());
            }
            newMzChargeDetail.setQuantity(1D);
            newMzChargeDetail.setPayMark(PayMarkEnum.NO_CHARGE.code);
            newMzChargeDetail.setSerial("");
            newMzChargeDetail.setSerialNo(0);
            newMzChargeDetail.setName(mzYjReq.getPatientName());
            newMzChargeDetail.setGroupNo(Constants.YJ_GROUP_NO);
            newMzChargeDetail.setDrugWin(1);
            newMzChargeDetail.setPriceId(priceId == null ? mzYjReq.getReqDoctor() : priceId);
            newMzChargeDetail.setPriceTime(priceTime == null ? mzYjReq.getReqDate() : priceTime);
            newMzChargeDetail.setExecDept(mzYjReq.getExecDept());
            newMzChargeDetail.setPrintFlag(YesNoEnum.NO.code.toString());
            newMzChargeDetail.setConfirmFlag(ConfirmFlagEnum.NOT_CONFIRM.code);
            newMzChargeDetail.setWarnDept(mzYjReq.getReqWard());
            newMzChargeDetail.setJzFlag(mzYjReq.getJzFlag() == null ? YesNoEnum.NO.code.toString() : mzYjReq.getJzFlag());
            newMzChargeDetail.setDoctorCode(mzYjReq.getReqDoctor());
            newMzChargeDetail.setDoctorFlag(YesNoEnum.YES.code.toString());
            newMzChargeDetail.setInjectRes(Double.valueOf(YesNoEnum.YES.code));
            newMzChargeDetail.setRealNo(0);
            newMzChargeDetail.setYbbxFlag(YesNoEnum.NO.code.toString());
            newMzChargeDetail.setTcNo(tcNoMap.get(jyZdItem.getCode()).getTcNo());
            newMzChargeDetail.setTcName(tcNoMap.get(jyZdItem.getCode()).getTcName());
            newMzChargeDetail.setDetailFlag(YesNoEnum.NO.code.toString());
            newMzChargeDetail.setOrderType(YesNoEnum.YES.code.toString());
            newMzChargeDetail.setSupplyNo("Y");
            newMzChargeDetail.setReqNo(StringUtils.isNotBlank(mzYjReq.getOrderCode()) ? Integer.valueOf(mzYjReq.getOrderCode()) : null);
            newMzChargeDetail.setGroupType(GroupTypeEnum.DIAGNOSIS.code);
            newMzChargeDetail.setOrderBill(0);
            String chargeBillCode = Constants.BILL_ITEM_CODE_prev + zdChargeItem.getBillItemMz().substring(1);
            newMzChargeDetail.setChargeBillCode(chargeBillCode);
            newMzChargeDetail.setSelfFlag(YesNoEnum.NO.code.toString());
            newMzChargeDetail.setResponceType(mzPatientMi != null ? mzPatientMi.getResponseType() : ResponceTypeEnum.SELF_PAYING.code);
            newMzChargeDetail.setGlPercentFt(BigDecimal.ONE);
            newMzChargeDetail.setReqYj(YesNoEnum.YES.code.toString());
            mzChargeDetails.add(newMzChargeDetail);
            vesselSets.add(jyZdItem.getVessel());
        }
        return itemNo;
    }

    /**
     * 将药品给药方式转成收费表的记录
     *
     * @param mzChargeDetails
     * @param mzChargeDetailList
     * @param itemNo
     * @return
     * @throws Exception
     */
    private Integer formatSupplyFee(List<MzChargeDetail> mzChargeDetails, List<MzChargeDetail> mzChargeDetailList, Integer itemNo, Integer receiptNo) throws MzException {
        for (MzChargeDetail mcd : mzChargeDetailList) {
            YpZdDict ypZdDict = ypZdDictService.queryYpZdDictByCodeAndSerial(mcd.getChargeItemCode(), mcd.getSerial());
            if (ypZdDict != null && ypZdDict.getMzRestrict() != null) {
                //当前处方购药量
                BigDecimal thisQuantity = BigDecimal.valueOf(mcd.getQuantity()).multiply(BigDecimal.valueOf(mcd.getDrugWin()));
                //本月已经购买量
                Integer quantityDb = mzChargeDetailMapper.selectTotalQuantityForMonth(mcd.getPatientId(), mcd.getChargeItemCode(), mcd.getSerial(), DateUtil.getFirstSecondForMonth(new Date()));
                quantityDb = quantityDb == null ? 0 : quantityDb;
                BigDecimal totalQuantity = thisQuantity.add(BigDecimal.valueOf(quantityDb));
                if (totalQuantity.compareTo(BigDecimal.valueOf(ypZdDict.getMzRestrict())) == 1) {
                    //当前还可以购药量，小于0时为0
                    BigDecimal tempCount = BigDecimal.valueOf(ypZdDict.getMzRestrict()).subtract(BigDecimal.valueOf(quantityDb));
                    if (tempCount.compareTo(BigDecimal.ZERO) == -1) {
                        tempCount = BigDecimal.ZERO;
                    }
                    throw new MzException("药品【" + ypZdDict.getName() + "】编码【" + ypZdDict.getCode() + "】的药品超过限购量，最大购买量为【" + ypZdDict.getMzRestrict() + "】,本月已购买量为【" + quantityDb + "】,本次最大可购量为【" + tempCount + "】,当前处方购药数量【" + thisQuantity + "】请联系医生修改处方限制购药品种的数量");
                }
            }
            //非口服用药方式，需要写入收费记录
            if (StringUtils.isNotBlank(mcd.getSupplyCode()) && !Constants.KOU_FU_SUPPLY_CODE.equals(mcd.getSupplyCode())) {
                List<MzZdSupplyCharge> mzZdSupplyChargeList = mzZdSupplyChargeService.queryMzZdSupplyChargeByCode(mcd.getSupplyCode());
                List<String> chargeCodes = mzZdSupplyChargeList.stream().map(u -> u.getChargeCode()).collect(Collectors.toList());
                if (chargeCodes != null && chargeCodes.size() > 0) {
                    List<ZdChargeItem> zdChargeItemList = zdChargeItemService.queryZdChargeItemByCodeList(chargeCodes);
                    if (zdChargeItemList != null && zdChargeItemList.size() > 0) {
                        for (ZdChargeItem zdChargeItem : zdChargeItemList) {
                            MzChargeDetail newMzChargeDetail = CloneUtil.clone(mcd);
                            newMzChargeDetail.setItemNo(itemNo++);
                            newMzChargeDetail.setChargeItemCode(zdChargeItem.getCode());
                            newMzChargeDetail.setBillItemCode(zdChargeItem.getBillItemMz());
                            if (zdChargeItem.getChargeAmount() == null || zdChargeItem.getPercentag1() == null) {
                                newMzChargeDetail.setUnitPrice(BigDecimal.ZERO);
                            } else {
                                newMzChargeDetail.setUnitPrice(zdChargeItem.getChargeAmount().multiply(zdChargeItem.getPercentag1()));
                            }
                            newMzChargeDetail.setReceiptNo(receiptNo);
                            newMzChargeDetail.setSerial("");
                            newMzChargeDetail.setPayMark(PayMarkEnum.NO_CHARGE.code);
                            newMzChargeDetail.setGroupNo(Constants.YJ_GROUP_NO);
                            newMzChargeDetail.setSupplyCode(null);
                            newMzChargeDetail.setFrequency(null);
                            newMzChargeDetail.setDrugQuan(null);
                            newMzChargeDetail.setDrugUnit("");
                            newMzChargeDetail.setDetailFlag(YesNoEnum.YES.code.toString());
                            newMzChargeDetail.setOrderDays(null);
                            newMzChargeDetail.setPaySelf(null);
                            newMzChargeDetail.setTryFlag(null);
                            newMzChargeDetail.setReqYj(YesNoEnum.YES.code.toString());
                            newMzChargeDetail.setOrigPrice(zdChargeItem.getChargeAmount());
                            String temp = newMzChargeDetail.getOrderNo().toString();
                            Integer itemNoTemp = itemNo - 100;
                            newMzChargeDetail.setTcNo(temp + itemNoTemp);
                            if (zdChargeItem.getName().length() > 14) {
                                zdChargeItem.setName(zdChargeItem.getName().substring(0, 14));
                            }
                            newMzChargeDetail.setTcName(zdChargeItem.getName());
                            newMzChargeDetail.setBillItemCode(Constants.ZLF);
                            //给药方式执行次数如果为空，默认为1次
                            newMzChargeDetail.setQuantity(Double.valueOf(newMzChargeDetail.getSupplyAmount() == null ? 1 : newMzChargeDetail.getSupplyAmount()));
                            newMzChargeDetail.setSupplyAmount(null);
                            mzChargeDetails.add(newMzChargeDetail);
                        }
                    }
                }
            }
        }
        return itemNo;
    }


    /**
     * 将医技申请的套餐转成收费表的记录
     *
     * @param mzChargeDetail
     * @param mzChargeDetails
     * @param maxOrderNo
     * @param mzPatientMi
     * @param itemNo
     * @param jianYans
     * @param jianChas
     * @param mzYjReq
     * @param tcNo
     * @return
     */
    private Integer formatYjChargeDetail(MzChargeDetail mzChargeDetail, List<MzChargeDetail> mzChargeDetails, Integer maxOrderNo, MzPatientMi mzPatientMi, Integer itemNo, List<String> jianYans, List<String> jianChas, MzYjReq mzYjReq, String tcNo, String priceId, Date priceTime, Map<String, MzChargeDetail> tcNoMap, Integer receiptNo) {
        MzChargeDetail newMzChargeDetail = new MzChargeDetail();
        newMzChargeDetail.setPatientId(mzChargeDetail.getPatientId());
        newMzChargeDetail.setTimes(mzChargeDetail.getTimes());
        newMzChargeDetail.setReceiptNo(receiptNo);
        if (mzYjReq.getOrderNo() != null && mzYjReq.getOrderNo() > 0) {
            newMzChargeDetail.setOrderNo(mzYjReq.getOrderNo());
        } else {
            newMzChargeDetail.setOrderNo(maxOrderNo);
        }
        newMzChargeDetail.setItemNo(itemNo++);
        newMzChargeDetail.setChargeItemCode(tcNo);
        newMzChargeDetail.setBillItemCode(Constants.TC);
        newMzChargeDetail.setQuantity(mzYjReq.getPercentFt() == null ? 1D : mzYjReq.getPercentFt().doubleValue());
        newMzChargeDetail.setUnitPrice(BigDecimal.ZERO);
        newMzChargeDetail.setPayMark(PayMarkEnum.NO_CHARGE.code);
        newMzChargeDetail.setSerial("");
        newMzChargeDetail.setSerialNo(0);
        newMzChargeDetail.setName(mzYjReq.getPatientName());
        newMzChargeDetail.setGroupNo(Constants.YJ_GROUP_NO);
        newMzChargeDetail.setDrugWin(1);
        newMzChargeDetail.setPriceId(priceId == null ? mzYjReq.getReqDoctor() : priceId);
        newMzChargeDetail.setPriceTime(priceTime == null ? mzYjReq.getReqDate() : priceTime);
        newMzChargeDetail.setExecDept(mzYjReq.getExecDept());
        newMzChargeDetail.setPrintFlag(YesNoEnum.NO.code.toString());
        newMzChargeDetail.setConfirmFlag(ConfirmFlagEnum.NOT_CONFIRM.code);
        newMzChargeDetail.setWarnDept(mzYjReq.getReqWard());
        newMzChargeDetail.setJzFlag(mzYjReq.getJzFlag() == null ? YesNoEnum.NO.code.toString() : mzYjReq.getJzFlag());
        newMzChargeDetail.setDoctorCode(mzYjReq.getReqDoctor());
        newMzChargeDetail.setDoctorFlag(YesNoEnum.YES.code.toString());
        newMzChargeDetail.setInjectRes(Double.valueOf(YesNoEnum.YES.code));
        newMzChargeDetail.setRealNo(0);
        newMzChargeDetail.setYbbxFlag(YesNoEnum.NO.code.toString());
        newMzChargeDetail.setTcNo(mzYjReq.getOrderCode());
        if (mzYjReq.getGroupName().length() > 14) {
            newMzChargeDetail.setTcName(mzYjReq.getGroupName().substring(0, 14));
        } else {
            newMzChargeDetail.setTcName(mzYjReq.getGroupName());
        }

        newMzChargeDetail.setDetailFlag(YesNoEnum.NO.code.toString());
        newMzChargeDetail.setOrderType(YesNoEnum.YES.code.toString());
        newMzChargeDetail.setSupplyNo("Y");
        newMzChargeDetail.setReqNo(StringUtils.isNotBlank(mzYjReq.getOrderCode()) ? Integer.valueOf(mzYjReq.getOrderCode()) : null);
        newMzChargeDetail.setGroupType(GroupTypeEnum.DIAGNOSIS.code);
        newMzChargeDetail.setOrderBill(0);
        newMzChargeDetail.setChargeBillCode(newMzChargeDetail.getChargeItemCode());
        newMzChargeDetail.setSelfFlag(YesNoEnum.NO.code.toString());
        newMzChargeDetail.setResponceType(mzPatientMi != null ? mzPatientMi.getResponseType() : ResponceTypeEnum.SELF_PAYING.code);
        newMzChargeDetail.setGlPercentFt(BigDecimal.ONE);
        newMzChargeDetail.setOrigPrice(BigDecimal.ZERO);
        newMzChargeDetail.setReqYj(YesNoEnum.YES.code.toString());
        mzChargeDetails.add(newMzChargeDetail);
        if (ReqTypeEnum.JIAN_YAN.code.equals(mzYjReq.getReqType())) {
            jianYans.add(mzYjReq.getOrderCode());
        } else if (ReqTypeEnum.JIAN_CHA.code.equals(mzYjReq.getReqType())) {
            jianChas.add(mzYjReq.getOrderCode());
        }
        tcNoMap.put(mzYjReq.getOrderCode(), newMzChargeDetail);
        return itemNo;
    }

    /**
     * 将医技对应的检查检验项目明细转成收费记录明细
     *
     * @param mzChargeDetail
     * @param mzChargeDetails
     * @param maxOrderNo
     * @param mzPatientMi
     * @param itemNo
     * @param mzYjReqMap
     * @param jcJyItemCharge
     * @return
     */
    private Integer formatYjDetailChargeDetail(MzChargeDetail mzChargeDetail, List<MzChargeDetail> mzChargeDetails, Integer maxOrderNo, MzPatientMi mzPatientMi, Integer itemNo, Map<String, MzYjReq> mzYjReqMap, JcJyItemCharge jcJyItemCharge, Map<String, MzChargeDetail> tcNoMap, String priceId, Date priceTime, Integer receiptNo) throws MzException {
        MzYjReq mzYjReq = mzYjReqMap.get(jcJyItemCharge.getCode());
        ZdChargeItem zdChargeItem = zdChargeItemService.queryZdChargeItemByCode(jcJyItemCharge.getChargeCode());
        if (zdChargeItem == null) {
            // throw new MzException("【收费编码：" + jcJyItemCharge.getChargeCode() + "】不存在,请联系物价科确认！");
            return itemNo;
        }
        if (YesNoEnum.YES.code.equals(zdChargeItem.getDelFlag())) {
            throw new MzException("收费项目【" + zdChargeItem.getName() + "(编码" + zdChargeItem.getCode() + ")】被停用,请联系物价科确认！");
        }
        MzChargeDetail newMzChargeDetail = new MzChargeDetail();
        newMzChargeDetail.setPatientId(mzChargeDetail.getPatientId());
        newMzChargeDetail.setTimes(mzChargeDetail.getTimes());
        newMzChargeDetail.setReceiptNo(receiptNo);
        if (mzYjReq.getOrderNo() != null && mzYjReq.getOrderNo() > 0) {
            newMzChargeDetail.setOrderNo(mzYjReq.getOrderNo());
        } else {
            newMzChargeDetail.setOrderNo(maxOrderNo);
        }
        newMzChargeDetail.setItemNo(itemNo++);
        newMzChargeDetail.setChargeItemCode(jcJyItemCharge.getChargeCode());

        newMzChargeDetail.setBillItemCode(zdChargeItem == null ? "" : zdChargeItem.getBillItemMz());
        BigDecimal quantity = jcJyItemCharge.getAmount() == null ? BigDecimal.ONE : jcJyItemCharge.getAmount();
        quantity = quantity.multiply(mzYjReq.getPercentFt() == null ? BigDecimal.ONE : mzYjReq.getPercentFt());
        newMzChargeDetail.setQuantity(quantity.doubleValue());
        if (zdChargeItem.getChargeAmount() == null || zdChargeItem.getPercentag1() == null) {
            newMzChargeDetail.setUnitPrice(BigDecimal.ZERO);
        } else {
            newMzChargeDetail.setUnitPrice(zdChargeItem.getChargeAmount().multiply(zdChargeItem.getPercentag1()));
        }
        newMzChargeDetail.setPayMark(PayMarkEnum.NO_CHARGE.code);
        newMzChargeDetail.setSerial("");
        newMzChargeDetail.setSerialNo(0);
        newMzChargeDetail.setName(mzPatientMi.getName());
        newMzChargeDetail.setGroupNo(Constants.YJ_GROUP_NO);
        newMzChargeDetail.setDrugWin(1);
        newMzChargeDetail.setPriceId(priceId == null ? mzYjReq.getReqDoctor() : priceId);
        newMzChargeDetail.setPriceTime(priceTime == null ? mzYjReq.getReqDate() : priceTime);
        newMzChargeDetail.setExecDept(mzYjReq.getExecDept());
        newMzChargeDetail.setPrintFlag(YesNoEnum.NO.code.toString());
        newMzChargeDetail.setConfirmFlag(ConfirmFlagEnum.NOT_CONFIRM.code);
        newMzChargeDetail.setWarnDept(mzYjReq.getReqWard());
        newMzChargeDetail.setJzFlag(mzYjReq.getJzFlag() == null ? YesNoEnum.NO.code.toString() : mzYjReq.getJzFlag());
        newMzChargeDetail.setDoctorCode(mzYjReq.getReqDoctor());
        newMzChargeDetail.setDoctorFlag(YesNoEnum.YES.code.toString());
        newMzChargeDetail.setInjectRes(Double.valueOf(YesNoEnum.YES.code));
        newMzChargeDetail.setRealNo(0);
        newMzChargeDetail.setYbbxFlag(YesNoEnum.NO.code.toString());
        newMzChargeDetail.setTcNo(tcNoMap.get(jcJyItemCharge.getCode()).getChargeItemCode());
        newMzChargeDetail.setTcName(tcNoMap.get(jcJyItemCharge.getCode()).getTcName());
        newMzChargeDetail.setDetailFlag(YesNoEnum.NO.code.toString());
        newMzChargeDetail.setOrderType(YesNoEnum.YES.code.toString());
        newMzChargeDetail.setSupplyNo("Y");
        newMzChargeDetail.setReqNo(mzYjReq.getReqNo());
        newMzChargeDetail.setGroupType(GroupTypeEnum.DIAGNOSIS.code);
        newMzChargeDetail.setOrderBill(0);
        String chargeBillCode = Constants.BILL_ITEM_CODE_prev + zdChargeItem.getBillItemMz().substring(1);
        newMzChargeDetail.setChargeBillCode(chargeBillCode);
        newMzChargeDetail.setSelfFlag(YesNoEnum.NO.code.toString());
        newMzChargeDetail.setResponceType(mzPatientMi != null ? mzPatientMi.getResponseType() : ResponceTypeEnum.SELF_PAYING.code);
        newMzChargeDetail.setGlPercentFt(BigDecimal.ONE);
        newMzChargeDetail.setOrigPrice(zdChargeItem.getChargeAmount());
        newMzChargeDetail.setReqYj(YesNoEnum.YES.code.toString());
        mzChargeDetails.add(newMzChargeDetail);
        return itemNo;
    }


    //解决事务失效
    private MzChargeDetailService getMzChargeDetailService() {
        return SpringUtil.getBean(this.getClass());
    }

}
