package com.iformall.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.iformall.common.ErrorCode;
import com.iformall.common.IdWorker;
import com.iformall.common.ResultData;
import com.iformall.domain.dto.WxMerchantDto;
import com.iformall.domain.po.*;
import com.iformall.domain.po.msg.MailMsg;
import com.iformall.domain.vo.*;
import com.iformall.enums.*;
import com.iformall.exception.MallinkException;
import com.iformall.mapper.*;
import com.iformall.mq.MqBaseProducer;
import com.iformall.service.*;
import com.iformall.utils.DateUtils;
import com.iformall.utils.JsonUtil;
import com.iformall.utils.PriceUtil;
import com.iformall.utils.WordUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.map.HashedMap;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @author gongbiao
 */
@Service
public class WxBillAllServiceImpl implements WxBillAllService {
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    WxBillAllMapper wxBillAllMapper;

    @Autowired
    WxBillDailyService wxBillDailyService;

    @Autowired
    WxBillDepositService wxBillDepositService;

    @Autowired
    WxBillPropertyDepositService wxBillPropertyDepositService;

    @Autowired
    WxBillPropertyService wxBillPropertyService;

    @Autowired
    WxBillRentService wxBillRentService;

    @Autowired
    WxBillOtherService wxBillOtherService;

    @Autowired
    WxBillOtherDepositService wxBillOtherDepositService;

    @Autowired
    WxBillDailyMapper wxBillDailyMapper;

    @Autowired
    WxBillDepositMapper wxBillDepositMapper;

    @Autowired
    WxBillPropertyDepositMapper wxBillPropertyDepositMapper;

    @Autowired
    WxBillPropertyMapper wxBillPropertyMapper;

    @Autowired
    WxBillRentMapper wxBillRentMapper;

    @Autowired
    WxBillOtherMapper wxBillOtherMapper;

    @Autowired
    WxBillOtherDepositMapper wxBillOtherDepositMapper;

    @Autowired
    ExcelService excelService;

    @Autowired
    MqBaseProducer mqBaseProducer;

    @Autowired
    WxBillActionService wxBillActionService;

    @Autowired
    WxMerchantBUserMapper wxMerchantBUserMapper;

    @Autowired
    WxMallMapper wxMallMapper;

    @Autowired
    WxMerchantMapper wxMerchantMapper;

    @Autowired
    private String fmUploadDir;

    @Autowired
    private WxBillSettleMapper wxBillSettleMapper;

    @Autowired
    private WxPayAccountBillMapper wxPayAccountBillMapper;

    @Autowired
    WxMerchantShopMapper wxMerchantShopMapper;

    @Autowired
    StringRedisTemplate stringRedisTemplate;

    @Autowired
    WxBillSettleRecordService wxBillSettleRecordService;

    @Autowired
    WxBillSettleService wxBillSettleService;

    @Autowired
    WxBillSettleRecordMapper wxBillSettleRecordMapper;
    @Autowired
    WxPayAccountBillService wxPayAccountBillService;

    @Override
    public Map<String, Object> listAsPage(WxBillAll record, Integer pageIndex, Integer pageSize) {
        //更新各账单状态
        //updateBillStatus(record);
        WxPayAccountBill wxPayAccountBill = wxPayAccountBillService.getByTenantId(record.getTenantId());

        if (StringUtils.isNotEmpty(record.getTypeStr())) {
            List<Integer> typeList = JSONArray.parseArray(record.getTypeStr(), Integer.class);
            record.setTypeList(typeList);
        }
        PageInfo<WxBillAllVo> pageInfo = PageHelper.startPage(pageIndex, pageSize).doSelectPageInfo(() -> wxBillAllMapper.list(record));

        //手续费 = 合同应收+手续费+滞纳金
        pageInfo.getList().stream().forEach(e -> {
            //手续费 = 合同应收+手续费+滞纳金
            cmputeTotalMoney(wxPayAccountBill, e);
        });

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

    public void cmputeTotalMoney(WxPayAccountBill wxPayAccountBill, WxBillAllVo e) {
        if (e.getReceivePay() != null) {
            if (e.getLatePayPrice() == null) e.setLatePayPrice(0L);
            BigDecimal servicePay;
            if (e.getServiceChargePay() != null) {
                servicePay = new BigDecimal(e.getServiceChargePay());
            } else {
                servicePay = new BigDecimal(e.getReceivePay()).multiply(new BigDecimal(wxPayAccountBill.getServiceChargeRate())).divide(new BigDecimal(10000), 2, BigDecimal.ROUND_HALF_UP);
            }
            Long realReceivePay = servicePay.longValue() + e.getLatePayPrice() + e.getReceivePay();
            e.setRealReceivePay(realReceivePay);
            e.setServiceChargePay(servicePay.intValue());
        }
    }

    @Override
    public List<Map<String, Object>> listBillOweAndWaitPay(WxBillAll wxBillAll) {
        //更新各账单状态
        //updateBillStatus(wxBillAll);
        ArrayList<Integer> statusList = new ArrayList<>();
        statusList.add(EnumBillRentStatus.NOT_PAID.getCode());
        statusList.add(EnumBillRentStatus.WAIT_PAY.getCode());
        wxBillAll.setStatusList(statusList);
        return wxBillAllMapper.listData(wxBillAll);
    }

    @Override
    public ResultData listBill(WxBillAll wxBillAll) {
        //更新各账单状态
        //updateBillStatus(wxBillAll);
        //账单类型
        if (wxBillAll.getBillTypeValue() != null) {
            if (wxBillAll.getBillTypeValue().equals(EnumBillType.RENT.getCode())) {
                wxBillAll.setBillTypeValue(EnumBillTypeParam.RENT.getCode());
            } else if (wxBillAll.getBillTypeValue().equals(EnumBillType.DEPOSIT.getCode())) {
                wxBillAll.setBillTypeValue(null);
                ArrayList typeList = new ArrayList();
                typeList.add(EnumBillTypeParam.RENT_DEPOSIT.getCode());
                typeList.add(EnumBillTypeParam.PROPERTY_DEPOSIT.getCode());
                typeList.add(EnumBillTypeParam.ATHER_DEPOSIT.getCode());
                wxBillAll.setTypeList(typeList);
            } else if (wxBillAll.getBillTypeValue().equals(EnumBillType.PROPERTY.getCode())) {
                wxBillAll.setBillTypeValue(EnumBillTypeParam.PROPERTY.getCode());
            } else if (wxBillAll.getBillTypeValue().equals(EnumBillType.WATER.getCode())) {
                wxBillAll.setBillTypeValue(EnumBillTypeParam.WATER.getCode());
            } else if (wxBillAll.getBillTypeValue().equals(EnumBillType.POWER.getCode())) {
                wxBillAll.setBillTypeValue(EnumBillTypeParam.POWER.getCode());
            } else if (wxBillAll.getBillTypeValue().equals(EnumBillType.ROUTINE.getCode())) {
                wxBillAll.setBillTypeValue(EnumBillTypeParam.ROUTINE.getCode());
            } else if (wxBillAll.getBillTypeValue().equals(EnumBillType.AIR_CONDITIONING.getCode())) {
                wxBillAll.setBillTypeValue(EnumBillTypeParam.AIR_CONDITIONING.getCode());
            } else if (wxBillAll.getBillTypeValue().equals(EnumBillType.SETTLE.getCode())) {
                wxBillAll.setBillTypeValue(EnumBillTypeParam.SETTLE.getCode());
            } else {
                logger.info("账单不存在");
                return new ResultData(ErrorCode.BILL_ROUTINE_IS_NOT_FOUND);
            }
        }
        if (wxBillAll.getPageIndex() != null && wxBillAll.getPageIndex() != null) {
            PageHelper.startPage(wxBillAll.getPageIndex(), wxBillAll.getPageSize());
            List<Map<String, Object>> maps = wxBillAllMapper.listData(wxBillAll);
            for (Map<String, Object> map : maps) {
                Integer billType = ((Long) map.get("billTypeValue")).intValue();
                if (EnumBillType.SETTLE.getCode().equals(billType)) {
                    Long id = (Long) map.get("id");
                    WxBillSettle settle = wxBillSettleService.getById(id, EnumFilterSettle.YES.getCode());
                    map.put("owe", settle.getBalance());
                    settle = wxBillSettleService.getById(id, EnumFilterSettle.NO.getCode());
                    map.put("receivePay", settle.getBalance());
                }
            }
            PageInfo<Map<String, Object>> pageInfo = new PageInfo<>(maps);
            return new ResultData(pageInfo);
        }
        List<Map<String, Object>> maps = wxBillAllMapper.listData(wxBillAll);
        for (Map<String, Object> map : maps) {
            Integer billType = ((Long) map.get("billTypeValue")).intValue();
            if (EnumBillType.SETTLE.getCode().equals(billType)) {
                Long id = (Long) map.get("id");
                WxBillSettle settle = wxBillSettleService.getById(id, EnumFilterSettle.YES.getCode());
                map.put("owe", settle.getBalance());
                settle = wxBillSettleService.getById(id, EnumFilterSettle.NO.getCode());
                map.put("receivePay", settle.getBalance());
            }
        }
        return new ResultData(maps);
    }

    @Override
    public void updateBill(Map<String, Object> bill) {
        int billTypeValue = ((Long) bill.get("billTypeValue")).intValue();
        logger.info(">>>>>>>>>>>>>>>>>>>>账单回调修改数据:" + JSONObject.toJSONString(bill));
        if (billTypeValue == EnumBillTypeParam.RENT.getCode().intValue()) {
            logger.info("更新租金账单");
            WxBillRent billRent = wxBillRentMapper.selectById((Long) bill.get("id"));
            if (billRent != null && !billRent.getStatus().equals(EnumBillRentStatus.PAID.getCode())) {
                updateBillRent(bill);
            }
        } else if (billTypeValue == EnumBillTypeParam.RENT_DEPOSIT.getCode().intValue()) {
            logger.info("更新租金押金账单");
            WxBillDeposit billDeposit = wxBillDepositMapper.selectById((Long) bill.get("id"));
            if (billDeposit != null && !billDeposit.getStatus().equals(EnumBillRentStatus.PAID.getCode())) {
                updateBillRentDeposit(bill);
            }
        } else if (billTypeValue == EnumBillTypeParam.PROPERTY.getCode().intValue()) {
            logger.info("更新物业账单");
            WxBillProperty property = wxBillPropertyMapper.selectById((Long) bill.get("id"));
            if (property != null && !property.getStatus().equals(EnumBillRentStatus.PAID.getCode())) {
                updateBillProperty(bill);
            }
        } else if (billTypeValue == EnumBillTypeParam.PROPERTY_DEPOSIT.getCode().intValue()) {
            logger.info("更新物业押金账单");
            WxBillPropertyDeposit wxBillPropertyDeposit = wxBillPropertyDepositMapper.selectById((Long) bill.get("id"));
            if (wxBillPropertyDeposit != null && !wxBillPropertyDeposit.getStatus().equals(EnumBillRentStatus.PAID.getCode())) {
                updateBillPropertyDeposit(bill);
            }
        } else if (billTypeValue == EnumBillTypeParam.WATER.getCode().intValue()) {
            logger.info("更新水费账单");
            WxBillDaily wxBillDaily = wxBillDailyMapper.selectById((Long) bill.get("id"));
            if (wxBillDaily != null && !wxBillDaily.getStatus().equals(EnumBillRentStatus.PAID.getCode())) {
                updateBillDaily(bill);
            }
        } else if (billTypeValue == EnumBillTypeParam.POWER.getCode().intValue()) {
            logger.info("更新电费账单");
            WxBillDaily wxBillDaily = wxBillDailyMapper.selectById((Long) bill.get("id"));
            if (wxBillDaily != null && !wxBillDaily.getStatus().equals(EnumBillRentStatus.PAID.getCode())) {
                updateBillDaily(bill);
            }
        } else if (billTypeValue == EnumBillTypeParam.AIR_CONDITIONING.getCode().intValue()) {
            logger.info("更新空调费账单");
            WxBillDaily wxBillDaily = wxBillDailyMapper.selectById((Long) bill.get("id"));
            if (wxBillDaily != null && !wxBillDaily.getStatus().equals(EnumBillRentStatus.PAID.getCode())) {
                updateBillDaily(bill);
            }
        } else if (billTypeValue == EnumBillTypeParam.ROUTINE.getCode().intValue()) {
            logger.info("更新其他账单");
            WxBillOther wxBillOther = wxBillOtherMapper.selectById((Long) bill.get("id"));
            if (wxBillOther != null && !wxBillOther.getStatus().equals(EnumBillRentStatus.PAID.getCode())) {
                updateBillOther(bill);
            }
        } else if (billTypeValue == EnumBillTypeParam.ATHER_DEPOSIT.getCode().intValue()) {
            logger.info("更新其他押金账单");
            WxBillOtherDeposit wxBillOtherDeposit = wxBillOtherDepositMapper.selectById((Long) bill.get("id"));
            if (wxBillOtherDeposit != null && !wxBillOtherDeposit.getStatus().equals(EnumBillRentStatus.PAID.getCode())) {
                updateBillOtherDeposit(bill);
            }
        } else if (billTypeValue == EnumBillTypeParam.SETTLE.getCode().intValue()) {
            try {
                logger.info("更新结算单id:{}", JsonUtil.obj2Json(bill));

                WxBillSettle wxBillSettle = wxBillSettleService.getById((Long) bill.get("id"), EnumFilterSettle.YES.getCode());

                WxBillSettleRecord settleRecord = new WxBillSettleRecord();
                settleRecord.setSettleId((Long) bill.get("id"));
                settleRecord.setSettleMoney(wxBillSettle.getBalance());
                settleRecord.setSettleTime(new Date());
                settleRecord.setSettleWay(EnumSettleRecordWay.WEBCAT.getCode());
                settleRecord.setTenantId(wxBillSettle.getTenantId());

                BigDecimal money = new BigDecimal(settleRecord.getSettleMoney()).divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP);
                settleRecord.setDetail(EnumSettleRecordWay.getEnum(settleRecord.getSettleWay()).getMessage() + "收款" + money.toString() + "元");
                wxBillSettleRecordService.saveOrUpdate(settleRecord, null, (Long) bill.get("userId"));

                wxBillSettle.setUpdatetime(new Date());
                wxBillSettle.setStatus(EnumSettleStatus.FINISH.getCode());
                wxBillSettleMapper.updateById(wxBillSettle);

                logger.info("更新结算单success");
            } catch (Exception e) {
                logger.error("结算单error", e);
                e.printStackTrace();
            }

        } else {
            logger.info("账单类型不存在");
        }
    }

    @Override
    public void exportBill(HttpServletRequest request, HttpServletResponse response, WxBillAll wxBillAll) {

        Map<Long, List<WxBillAllVo>> collect = wxBillAllMapper.list(wxBillAll)
                .stream().filter(b -> null != b.getMerchantId())
                .collect(Collectors.groupingBy(WxBillAllVo::getMerchantId));
        Set<Map.Entry<Long, List<WxBillAllVo>>> entries = collect.entrySet();
        List<WxBillAllVo> datalist = new ArrayList<>();
        for (Map.Entry<Long, List<WxBillAllVo>> entry : entries) {
            List<WxBillAllVo> list = entry.getValue();
            for (WxBillAllVo wxBillAllVo : list) {
                String shopNumber = wxBillAllVo.getShopNumber();
                if (StringUtils.isEmpty(shopNumber)) {
                    String shopInfo = wxBillAllVo.getShopInfo();
                    if (StringUtils.isNotEmpty(shopInfo) && !shopInfo.equals("[]")) {
                        JSONObject jsonObject = JSONObject.parseObject(shopInfo);
                        StringBuffer sb = new StringBuffer();
                        Set<Map.Entry<String, Object>> sets = jsonObject.entrySet();
                        sets.forEach(x -> sb.append(x.getKey()).append(","));
                        wxBillAllVo.setShopNumber(sb.deleteCharAt(sb.length() - 1).toString());
                    }
                }
                wxBillAllVo.setPayDateStr(DateUtils.format(wxBillAllVo.getPayDate()));
                wxBillAllVo.setRentStartTime(DateUtils.format(wxBillAllVo.getStarttime()));
                wxBillAllVo.setRentEndTime(DateUtils.format(wxBillAllVo.getEndtime()));

                //status不是欠缴，都展示0，与前端保持一致
                if (!EnumBillRentStatus.NOT_PAID.getCode().equals(wxBillAllVo.getStatus())) {
                    wxBillAllVo.setOwe(0l);
                    wxBillAllVo.setOweStr("0");
                }
                datalist.add(wxBillAllVo);
            }
        }
        excelService.exportExcel(datalist, null, "账单数据", WxBillAllVo.class, "账单数据.xlsx", response, false);
    }

    private int updateBillOtherDeposit(Map<String, Object> bill) {
        logger.info("updateBillOtherDeposit params:" + bill.toString());
        Object id = bill.get("id");
        WxBillOtherDeposit wxBillOtherDeposit = wxBillOtherDepositMapper.selectById((Long) id);
        if (wxBillOtherDeposit == null) {
            return 0;
        }
        Date date = new Date();
        wxBillOtherDeposit.setPayDate(date);
        Long owe = (Long) bill.get("owe");
        wxBillOtherDeposit.setPay(wxBillOtherDeposit.getPay() + owe);
        wxBillOtherDeposit.setOwe(0L);
        wxBillOtherDeposit.setStatus(EnumBillDailyStatus.PAID.getCode());
        wxBillOtherDeposit.setPayDate(date);
        wxBillOtherDeposit.setUpdatetime(date);
        wxBillOtherDeposit.setPayWay(EnumBillPayWay.WECHAT_PAY.getCode());
        int count = 0;
        try {
            count = wxBillOtherDepositMapper.updateById(wxBillOtherDeposit);
        } catch (Exception e) {
            logger.error("更新其他押金账单失败,e:" + e.getMessage());
            throw new MallinkException(ErrorCode.DB_FAIL.getCode(), "DB FAILD " + e.getMessage());
        }
        //日志
        WxMerchantBUser wxMerchantBUser = wxMerchantBUserMapper.selectById((Long) bill.get("userId"));
        WxBillAction wxBillAction = new WxBillAction();
        wxBillAction.setBillId(wxBillOtherDeposit.getId());
        String price = new BigDecimal(owe).divide(new BigDecimal(100)).toPlainString();
        wxBillAction.setDetails("线上缴费" + price + "元");
        wxBillAction.setAction(EnumBillAction.SELF_SERVICE_PAY.getCode());
        wxBillAction.setUserId(wxMerchantBUser.getId());
        wxBillAction.setUserName(wxMerchantBUser.getName());
        wxBillAction.setPhone(wxMerchantBUser.getPhone());
        wxBillAction.setTenantId(wxMerchantBUser.getTenantId());
        wxBillAction.setPayDate(date);
        try {
            wxBillActionService.save(wxBillAction);
        } catch (Exception e) {
            logger.error("添加其他押金账单行为日志,e:" + e.getMessage());
            throw new MallinkException(ErrorCode.DB_FAIL.getCode(), "DB FAILD " + e.getMessage());
        }
        return count;
    }

    private int updateBillOther(Map<String, Object> bill) {
        logger.info("updateBillOther params:" + bill.toString());
        Object id = bill.get("id");
        WxBillOther wxBillOther = wxBillOtherMapper.selectById((Long) id);
        if (wxBillOther == null) {
            return 0;
        }
        Date date = new Date();
        wxBillOther.setPayDate(date);
        Long owe = (Long) bill.get("owe");
        wxBillOther.setPay(wxBillOther.getPay() + owe);
        wxBillOther.setOwe(0L);
        wxBillOther.setStatus(EnumBillDailyStatus.PAID.getCode());
        wxBillOther.setPayDate(date);
        wxBillOther.setUpdatetime(date);
        wxBillOther.setPayWay(EnumBillPayWay.WECHAT_PAY.getCode());
        int count = 0;
        try {
            count = wxBillOtherMapper.updateById(wxBillOther);
        } catch (Exception e) {
            logger.error("更新其他账单失败,e:" + e.getMessage());
            throw new MallinkException(ErrorCode.DB_FAIL.getCode(), "DB FAILD " + e.getMessage());
        }
        //日志
        WxMerchantBUser wxMerchantBUser = wxMerchantBUserMapper.selectById((Long) bill.get("userId"));
        WxBillAction wxBillAction = new WxBillAction();
        wxBillAction.setBillId(wxBillOther.getId());
        String price = new BigDecimal(owe).divide(new BigDecimal(100)).toPlainString();
        wxBillAction.setDetails("线上缴费" + price + "元");
        wxBillAction.setAction(EnumBillAction.SELF_SERVICE_PAY.getCode());
        wxBillAction.setUserId(wxMerchantBUser.getId());
        wxBillAction.setUserName(wxMerchantBUser.getName());
        wxBillAction.setPhone(wxMerchantBUser.getPhone());
        wxBillAction.setTenantId(wxMerchantBUser.getTenantId());
        wxBillAction.setPayDate(date);
        try {
            wxBillActionService.save(wxBillAction);
        } catch (Exception e) {
            logger.error("添加其他账单行为日志,e:" + e.getMessage());
            throw new MallinkException(ErrorCode.DB_FAIL.getCode(), "DB FAILD " + e.getMessage());
        }
        return count;
    }

    private int updateBillDaily(Map<String, Object> bill) {
        logger.info("updateBillDaily params:" + bill.toString());
        Object id = bill.get("id");
        WxBillDaily wxBillDaily = wxBillDailyMapper.selectById((Long) id);
        if (wxBillDaily == null) {
            return 0;
        }
        Date date = new Date();
        wxBillDaily.setPayDate(date);
        Long owe = (Long) bill.get("owe");
        wxBillDaily.setPay(wxBillDaily.getPay() + owe);
        wxBillDaily.setOwe(0L);
        wxBillDaily.setStatus(EnumBillDailyStatus.PAID.getCode());
        wxBillDaily.setPayDate(date);
        wxBillDaily.setUpdatetime(date);
        wxBillDaily.setPayWay(EnumBillPayWay.WECHAT_PAY.getCode());

        int count = 0;
        try {
            count = wxBillDailyMapper.updateById(wxBillDaily);
        } catch (Exception e) {
            logger.error("更新日常账单失败,e:" + e.getMessage());
            throw new MallinkException(ErrorCode.DB_FAIL.getCode(), "DB FAILD " + e.getMessage());
        }
        //日志
        WxMerchantBUser wxMerchantBUser = wxMerchantBUserMapper.selectById((Long) bill.get("userId"));
        WxBillAction wxBillAction = new WxBillAction();
        wxBillAction.setBillId(wxBillDaily.getId());
        String price = new BigDecimal(owe).divide(new BigDecimal(100)).toPlainString();
        wxBillAction.setDetails("线上缴费" + price + "元");
        wxBillAction.setAction(EnumBillAction.SELF_SERVICE_PAY.getCode());
        wxBillAction.setUserId(wxMerchantBUser.getId());
        wxBillAction.setUserName(wxMerchantBUser.getName());
        wxBillAction.setPhone(wxMerchantBUser.getPhone());
        wxBillAction.setTenantId(wxMerchantBUser.getTenantId());
        wxBillAction.setPayDate(date);
        try {
            wxBillActionService.save(wxBillAction);
        } catch (Exception e) {
            logger.error("添加日常账单行为日志,e:" + e.getMessage());
            throw new MallinkException(ErrorCode.DB_FAIL.getCode(), "DB FAILD " + e.getMessage());
        }
        return count;
    }

    private int updateBillPropertyDeposit(Map<String, Object> bill) {
        logger.info("updateBillPropertyDeposit params:" + bill.toString());
        Object id = bill.get("id");
        WxBillPropertyDeposit wxBillPropertyDeposit = wxBillPropertyDepositMapper.selectById((Long) id);
        if (wxBillPropertyDeposit == null) {
            return 0;
        }
        Date date = new Date();
        wxBillPropertyDeposit.setPayDate(date);
        Long owe = (Long) bill.get("owe");
        wxBillPropertyDeposit.setPay(wxBillPropertyDeposit.getPay() + owe);
        wxBillPropertyDeposit.setOwe(0L);
        wxBillPropertyDeposit.setStatus(EnumBillDailyStatus.PAID.getCode());
        wxBillPropertyDeposit.setPayDate(date);
        wxBillPropertyDeposit.setUpdatetime(date);
        wxBillPropertyDeposit.setPayWay(EnumBillPayWay.WECHAT_PAY.getCode());

        int count = 0;
        try {
            count = wxBillPropertyDepositMapper.updateById(wxBillPropertyDeposit);
        } catch (Exception e) {
            logger.error("更新物业押金账单失败,e:" + e.getMessage());
            throw new MallinkException(ErrorCode.DB_FAIL.getCode(), "DB FAILD " + e.getMessage());
        }
        //日志
        WxMerchantBUser wxMerchantBUser = wxMerchantBUserMapper.selectById((Long) bill.get("userId"));
        WxBillAction wxBillAction = new WxBillAction();
        wxBillAction.setBillId(wxBillPropertyDeposit.getId());
        String price = new BigDecimal(owe).divide(new BigDecimal(100)).toPlainString();
        wxBillAction.setDetails("线上缴费" + price + "元");
        wxBillAction.setAction(EnumBillAction.SELF_SERVICE_PAY.getCode());
        wxBillAction.setUserId(wxMerchantBUser.getId());
        wxBillAction.setUserName(wxMerchantBUser.getName());
        wxBillAction.setPhone(wxMerchantBUser.getPhone());
        wxBillAction.setTenantId(wxMerchantBUser.getTenantId());
        wxBillAction.setPayDate(date);
        try {
            wxBillActionService.save(wxBillAction);
        } catch (Exception e) {
            logger.error("添加物业押金账单行为日志,e:" + e.getMessage());
            throw new MallinkException(ErrorCode.DB_FAIL.getCode(), "DB FAILD " + e.getMessage());
        }
        return count;
    }

    private int updateBillProperty(Map<String, Object> bill) {
        logger.info("updateBillProperty params:" + bill.toString());
        Object id = bill.get("id");
        WxBillProperty property = wxBillPropertyMapper.selectById((Long) id);
        if (property == null) {
            return 0;
        }
        Date date = new Date();
        property.setPayDate(date);
        Long owe = (Long) bill.get("owe");
        property.setPay(property.getPay() + owe);
        property.setOwe(0L);
        property.setStatus(EnumBillDailyStatus.PAID.getCode());
        property.setPayDate(date);
        property.setUpdatetime(date);
        property.setPayWay(EnumBillPayWay.WECHAT_PAY.getCode());

        int count = 0;
        try {
            count = wxBillPropertyMapper.updateById(property);
        } catch (Exception e) {
            logger.error("更新物业账单失败,e:" + e.getMessage());
            throw new MallinkException(ErrorCode.DB_FAIL.getCode(), "DB FAILD " + e.getMessage());
        }
        //日志
        WxMerchantBUser wxMerchantBUser = wxMerchantBUserMapper.selectById((Long) bill.get("userId"));
        WxBillAction wxBillAction = new WxBillAction();
        wxBillAction.setBillId(property.getId());
        String price = new BigDecimal(owe).divide(new BigDecimal(100)).toPlainString();
        wxBillAction.setDetails("线上缴费" + price + "元");
        wxBillAction.setAction(EnumBillAction.SELF_SERVICE_PAY.getCode());
        wxBillAction.setUserId(wxMerchantBUser.getId());
        wxBillAction.setUserName(wxMerchantBUser.getName());
        wxBillAction.setPhone(wxMerchantBUser.getPhone());
        wxBillAction.setTenantId(wxMerchantBUser.getTenantId());
        wxBillAction.setPayDate(date);
        try {
            wxBillActionService.save(wxBillAction);
        } catch (Exception e) {
            logger.error("添加物业账单行为日志,e:" + e.getMessage());
            throw new MallinkException(ErrorCode.DB_FAIL.getCode(), "DB FAILD " + e.getMessage());
        }
        return count;
    }

    private int updateBillRentDeposit(Map<String, Object> bill) {
        logger.info("updateBillRentDeposit params:" + bill.toString());
        Object id = bill.get("id");
        WxBillDeposit wxBillDeposit = wxBillDepositMapper.selectById((Long) id);
        if (wxBillDeposit == null) {
            return 0;
        }
        Date date = new Date();
        wxBillDeposit.setPayDate(date);
        Long owe = (Long) bill.get("owe");
        wxBillDeposit.setPay(wxBillDeposit.getPay() + owe);
        wxBillDeposit.setOwe(0L);
        wxBillDeposit.setStatus(EnumBillDailyStatus.PAID.getCode());
        wxBillDeposit.setPayDate(date);
        wxBillDeposit.setUpdatetime(date);
        wxBillDeposit.setPayWay(EnumBillPayWay.WECHAT_PAY.getCode());

        int count = 0;
        try {
            count = wxBillDepositMapper.updateById(wxBillDeposit);
        } catch (Exception e) {
            logger.error("更新租赁押金账单失败,e:" + e.getMessage());
            throw new MallinkException(ErrorCode.DB_FAIL.getCode(), "DB FAILD " + e.getMessage());
        }
        //日志
        WxMerchantBUser wxMerchantBUser = wxMerchantBUserMapper.selectById((Long) bill.get("userId"));
        WxBillAction wxBillAction = new WxBillAction();
        wxBillAction.setBillId(wxBillDeposit.getId());
        String price = new BigDecimal(owe).divide(new BigDecimal(100)).toPlainString();
        wxBillAction.setDetails("线上缴费" + price + "元");
        wxBillAction.setAction(EnumBillAction.SELF_SERVICE_PAY.getCode());
        wxBillAction.setUserId(wxMerchantBUser.getId());
        wxBillAction.setUserName(wxMerchantBUser.getName());
        wxBillAction.setPhone(wxMerchantBUser.getPhone());
        wxBillAction.setTenantId(wxMerchantBUser.getTenantId());
        wxBillAction.setPayDate(date);
        try {
            wxBillActionService.save(wxBillAction);
        } catch (Exception e) {
            logger.error("添加其他押金账单行为日志,e:" + e.getMessage());
            throw new MallinkException(ErrorCode.DB_FAIL.getCode(), "DB FAILD " + e.getMessage());
        }
        return count;
    }

    private int updateBillRent(Map<String, Object> bill) {
        logger.info("updateBillRentDeposit params:" + bill.toString());
        Object id = bill.get("id");
        WxBillRent wxBillRent = wxBillRentMapper.selectById((Long) id);
        if (wxBillRent == null) {
            return 0;
        }
        Date date = new Date();
        wxBillRent.setPayDate(date);
        Long owe = (Long) bill.get("owe");
        wxBillRent.setPay(wxBillRent.getPay() + owe);
        wxBillRent.setOwe(0L);
        wxBillRent.setStatus(EnumBillDailyStatus.PAID.getCode());
        wxBillRent.setPayDate(date);
        wxBillRent.setUpdatetime(date);
        wxBillRent.setPayWay(EnumBillPayWay.WECHAT_PAY.getCode());

        int count = 0;
        try {
            count = wxBillRentMapper.updateById(wxBillRent);
        } catch (Exception e) {
            logger.error("更新租金账单失败,e:" + e.getMessage());
            throw new MallinkException(ErrorCode.DB_FAIL.getCode(), "DB FAILD " + e.getMessage());
        }
        //日志
        WxMerchantBUser wxMerchantBUser = wxMerchantBUserMapper.selectById((Long) bill.get("userId"));
        WxBillAction wxBillAction = new WxBillAction();
        wxBillAction.setBillId(wxBillRent.getId());
        String price = new BigDecimal(owe).divide(new BigDecimal(100)).toPlainString();
        wxBillAction.setDetails("线上缴费" + price + "元");
        wxBillAction.setAction(EnumBillAction.SELF_SERVICE_PAY.getCode());
        wxBillAction.setUserId(wxMerchantBUser.getId());
        wxBillAction.setUserName(wxMerchantBUser.getName());
        wxBillAction.setPhone(wxMerchantBUser.getPhone());
        wxBillAction.setTenantId(wxMerchantBUser.getTenantId());
        wxBillAction.setPayDate(date);
        try {
            wxBillActionService.save(wxBillAction);
        } catch (Exception e) {
            logger.error("添加其他押金账单行为日志,e:" + e.getMessage());
            throw new MallinkException(ErrorCode.DB_FAIL.getCode(), "DB FAILD " + e.getMessage());
        }
        return count;
    }

    @Override
    public void updateBillStatus(WxBillAll record) {
        logger.info("更新各账单状态开始");
        //更新其他押金账单
        //WxBillOtherDeposit wxBillOtherDeposit = new WxBillOtherDeposit();
        //wxBillOtherDeposit.setTenantId(record.getTenantId());
        //wxBillOtherDepositService.updateBillStatus(wxBillOtherDeposit);
        //更新其他账单
        WxBillOther wxBillOther = new WxBillOther();
        wxBillOther.setTenantId(record.getTenantId());
        wxBillOtherService.updateBillStatus(wxBillOther);
        //更新日常账单状态
        WxBillDaily wxBillDaily = new WxBillDaily();
        wxBillDaily.setTenantId(record.getTenantId());
        wxBillDailyService.updateBillStatus(wxBillDaily);
        //更新租赁押金账单状态
        //WxBillDeposit wxBillDeposit = new WxBillDeposit();
        //wxBillDeposit.setTenantId(record.getTenantId());
        //wxBillDepositService.updateBillStatus(wxBillDeposit);
        //更新物业押金账单状态
        //WxBillPropertyDeposit wxBillPropertyDeposit = new WxBillPropertyDeposit();
        //wxBillPropertyDeposit.setTenantId(record.getTenantId());
        //wxBillPropertyDepositService.updateBillStatus(wxBillPropertyDeposit);
        //更新物业账单状态
        WxBillProperty wxBillProperty = new WxBillProperty();
        wxBillProperty.setTenantId(record.getTenantId());
        wxBillPropertyService.updateBillStatus(wxBillProperty);
        //更新租赁账单状态
        WxBillRent wxBillRent = new WxBillRent();
        wxBillRent.setTenantId(record.getTenantId());
        wxBillRentService.updateBillStatus(wxBillRent);
        logger.info("更新各账单状态结束");
    }

    @Override
    public void exportOweBill(WxBillAll wxBillAll, HttpServletRequest request, HttpServletResponse response) {
        //商场名称
        WxMall wxMall = wxMallMapper.getByTenantId(wxBillAll.getTenantId());
        //映射结果
        Map<String, Object> result = new HashMap<>();
        result.put("mall", wxMall.getName());

        //付款方式
        WxPayAccountBill wxPayAccountBill = new WxPayAccountBill();
        wxPayAccountBill.setTenantId(wxBillAll.getTenantId());
        WxPayAccountBill payAccountBill = wxPayAccountBillMapper.selectOne(new QueryWrapper(wxPayAccountBill));
        if (payAccountBill != null) {
            String bankCardId = payAccountBill.getBankCardId();
            String bankAccountName = payAccountBill.getBankAccountName();
            result.put("accountNumber", StringUtils.isNotEmpty(bankCardId) ? bankCardId : " ");
            result.put("accountName", StringUtils.isNotEmpty(bankAccountName) ? bankAccountName : " ");
        } else {
            result.put("accountNumber", " ");
            result.put("accountName", " ");
        }

        //编号
        String number = "JF" + DateUtils.getSystemTime("yyyyMMddHHmmss");
        result.put("number", number);
        //数据
        Integer status = wxBillAll.getStatus();
        if (status == null) {
            List<Integer> statusList = new ArrayList<>();
            statusList.add(EnumBillRentStatus.NOT_PAID.getCode());
            statusList.add(EnumBillRentStatus.WAIT_PAY.getCode());
            statusList.add(EnumBillRentStatus.NOT_EXPIRED.getCode());
            wxBillAll.setStatusList(statusList);
            //账单时间段
            result.put("starttime", wxBillAll.getStarttime());
            result.put("endtime", wxBillAll.getEndtime().substring(0, 10));
        } else {
            result.put("starttime", " ");
            result.put("endtime", " ");
        }
        Integer filterHasPay = wxBillAll.getFilterHasPay();
        List<WxBillAllVo> list = wxBillAllMapper.list(wxBillAll);
        if (!list.isEmpty()) {
            //租金总额
            Long rentSum = list.stream().filter(b -> b.getBillTypeValue().equals(EnumBillTypeParam.RENT.getCode()))
                    .collect(Collectors.summingLong(b -> status == null && filterHasPay == null ? b.getReceivePay() : b.getOwe()));
            //物业总额
            Long propertySum = list.parallelStream().filter(b -> b.getBillTypeValue().equals(EnumBillTypeParam.PROPERTY.getCode()))
                    .collect(Collectors.summingLong(b -> status == null && filterHasPay == null ? b.getReceivePay() : b.getOwe()));
            //押金总额
            Long depositSum = list.stream().filter(b -> b.getBillTypeValue().equals(EnumBillTypeParam.RENT_DEPOSIT.getCode()) ||
                    b.getBillTypeValue().equals(EnumBillTypeParam.PROPERTY_DEPOSIT.getCode()) || b.getBillTypeValue().equals(EnumBillTypeParam.ATHER_DEPOSIT.getCode()))
                    .collect(Collectors.summingLong(b -> status == null && filterHasPay == null ? b.getReceivePay() : b.getOwe()));
            //水费
            Long waterSum = list.stream().filter(b -> b.getBillTypeValue().equals(EnumBillTypeParam.WATER.getCode()))
                    .collect(Collectors.summingLong(b -> status == null && filterHasPay == null ? b.getReceivePay() : b.getOwe()));
            //电费
            Long powerSum = list.stream().filter(b -> b.getBillTypeValue().equals(EnumBillTypeParam.POWER.getCode()))
                    .collect(Collectors.summingLong(b -> status == null && filterHasPay == null ? b.getReceivePay() : b.getOwe()));
            //空调费
            Long airConditioningSum = list.stream().filter(b -> b.getBillTypeValue().equals(EnumBillTypeParam.AIR_CONDITIONING.getCode()))
                    .collect(Collectors.summingLong(b -> status == null && filterHasPay == null ? b.getReceivePay() : b.getOwe()));
            //其他费用
            Long otherSum = list.stream().filter(b -> b.getBillTypeValue().equals(EnumBillTypeParam.ROUTINE.getCode()))
                    .collect(Collectors.summingLong(b -> status == null && filterHasPay == null ? b.getReceivePay() : b.getOwe()));
            //押金明细
            StringBuffer depositDetail = new StringBuffer();
            list.stream().filter(b -> b.getBillTypeValue().equals(EnumBillTypeParam.RENT_DEPOSIT.getCode()) ||
                    b.getBillTypeValue().equals(EnumBillTypeParam.PROPERTY_DEPOSIT.getCode()) || b.getBillTypeValue().equals(EnumBillTypeParam.ATHER_DEPOSIT.getCode()))
                    .forEach(b -> {
                        BigDecimal owe = new BigDecimal(status == null && filterHasPay == null ? b.getReceivePay() : b.getOwe()).divide(new BigDecimal(100)).setScale(2, RoundingMode.HALF_EVEN);
                        depositDetail.append(b.getName()).append(":[").append(owe.toPlainString()).append("] ");
                    });

            //其他费用明细
            StringBuffer otherDetail = new StringBuffer();
            list.stream().filter(b -> b.getBillTypeValue().equals(EnumBillTypeParam.ROUTINE.getCode()))
                    .forEach(b -> {
                        BigDecimal owe = new BigDecimal(status == null && filterHasPay == null ? b.getReceivePay() : b.getOwe()).divide(new BigDecimal(100)).setScale(2, RoundingMode.HALF_EVEN);
                        otherDetail.append(b.getName()).append(":[").append(owe.toPlainString()).append("] ");
                    });
            //总计
            Long summarySum = rentSum + propertySum + depositSum + waterSum + powerSum + airConditioningSum + otherSum;
            BigDecimal rent = new BigDecimal(rentSum).divide(new BigDecimal(100)).setScale(2, RoundingMode.HALF_EVEN);
            BigDecimal property = new BigDecimal(propertySum).divide(new BigDecimal(100)).setScale(2, RoundingMode.HALF_EVEN);
            BigDecimal deposit = new BigDecimal(depositSum).divide(new BigDecimal(100)).setScale(2, RoundingMode.HALF_EVEN);
            BigDecimal water = new BigDecimal(waterSum).divide(new BigDecimal(100)).setScale(2, RoundingMode.HALF_EVEN);
            BigDecimal power = new BigDecimal(powerSum).divide(new BigDecimal(100)).setScale(2, RoundingMode.HALF_EVEN);
            BigDecimal airConditioning = new BigDecimal(airConditioningSum).divide(new BigDecimal(100)).setScale(2, RoundingMode.HALF_EVEN);
            BigDecimal other = new BigDecimal(otherSum).divide(new BigDecimal(100)).setScale(2, RoundingMode.HALF_EVEN);
            BigDecimal summary = new BigDecimal(summarySum).divide(new BigDecimal(100)).setScale(2, RoundingMode.HALF_EVEN);
            String summaryUpper = PriceUtil.number2CNMontrayUnit(summary);

            result.put("rent", rent.toPlainString());
            result.put("property", property.toPlainString());
            result.put("deposit", deposit.toPlainString());
            result.put("water", water.toPlainString());
            result.put("power", power.toPlainString());
            result.put("airConditioning", airConditioning.toPlainString());
            result.put("other", other.toPlainString());
            result.put("summary", summary.toPlainString());
            result.put("summaryUpper", summaryUpper);

            result.put("depositDetail", StringUtils.isNotEmpty(depositDetail.toString()) ? depositDetail.toString() : " ");
            result.put("otherDetail", StringUtils.isNotEmpty(otherDetail.toString()) ? otherDetail.toString() : " ");

            WxMerchantDto wxMerchantDto = new WxMerchantDto();
            wxMerchantDto.setId(wxBillAll.getMerchantId());
            List<WxMerchantVo> listCVo = wxMerchantMapper.findListCVo(wxMerchantDto);
            WxMerchantVo wxMerchantVo = listCVo.get(0);
            result.put("merchant", wxMerchantVo.getMerchantName());
            WxShopVo wxShopVo = wxMerchantVo.getShopVoList().stream()
                    .filter(s -> StringUtils.isNotEmpty(s.getLinkPhone()) || StringUtils.isNotEmpty(s.getLinkPerson())).findFirst().orElse(null);
            if (wxShopVo != null) {
                String linkPerson = wxShopVo.getLinkPerson();
                String linkPhone = wxShopVo.getLinkPhone();
                result.put("linkPerson", StringUtils.isNotEmpty(linkPerson) ? linkPerson : " ");
                result.put("linkPhone", StringUtils.isNotEmpty(linkPhone) ? linkPhone : " ");
            } else {
                result.put("linkPerson", " ");
                result.put("linkPhone", " ");
            }

        } else {
            result.put("merchant", " ");
            result.put("rent", " ");
            result.put("property", " ");
            result.put("deposit", " ");
            result.put("water", " ");
            result.put("power", " ");
            result.put("airConditioning", " ");
            result.put("other", " ");
            result.put("summary", " ");
            result.put("summaryUpper", " ");

            result.put("depositDetail", " ");
            result.put("otherDetail", " ");

            result.put("linkPerson", " ");
            result.put("linkPhone", " ");
        }

        String createtime = DateUtils.getSystemTime("yyyy-MM-dd");
        result.put("createtime", createtime);

        String templatePath = "contract-word-template/bill_owe.docx";
        String filepath = fmUploadDir;
        String filename = UUID.randomUUID() + ".docx";
        String exportFileName = "催缴单.docx";
        WordUtil.exportWord(templatePath, filepath, filename, exportFileName, result, request, response, null);
    }

    @Override
    public void exportSettleBill(WxBillSettle wxBillSettle, HttpServletRequest request, HttpServletResponse response) {
        wxBillSettle = wxBillSettleService.getById(wxBillSettle.getId(), EnumFilterSettle.NO.getCode());
        if (wxBillSettle.getReceiveBillIds() == null) {
            wxBillSettle.setReceiveBillIds(new ArrayList<>());
        }
        if (wxBillSettle.getPayBillIds() == null) {
            wxBillSettle.setPayBillIds(new ArrayList<>());
        }

        //映射结果
        Map<String, Object> result = new HashMap<>();

        WxMall wxMall = wxMallMapper.getByTenantId(wxBillSettle.getTenantId());
        result.put("mall", wxMall.getName());
        result.put("merchant", wxMerchantMapper.selectById(wxBillSettle.getMerchantId()).getName());
        result.put("num", wxBillSettle.getSettleNumber());
        result.put("cdate", DateUtils.format(wxBillSettle.getCreatetime()));

        BigDecimal receiveM = (new BigDecimal(wxBillSettle.getReceiveMoney()).divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP));
        BigDecimal payM = (new BigDecimal(wxBillSettle.getPayMoney()).divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP));
        BigDecimal bM = (new BigDecimal(wxBillSettle.getBalance()).divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP));
        result.put("receiveM", receiveM.toString() + "元");
        result.put("payM", payM.toString() + "元");
        result.put("bM", bM.toString() + "元");
        result.put("receiveMU", PriceUtil.digitUppercase(receiveM.doubleValue()));
        result.put("payMU", PriceUtil.digitUppercase(payM.doubleValue()));
        result.put("bMU", PriceUtil.digitUppercase(bM.doubleValue()));

        WordDocTableVo wordDocTableVo = new WordDocTableVo();
        List<List<String>> rowsParams = new ArrayList<>();
        int size = wxBillSettle.getReceiveBillIds().size() > wxBillSettle.getPayBillIds().size() ? wxBillSettle.getReceiveBillIds().size() : wxBillSettle.getPayBillIds().size();
        int count = 1;
        for (int i = 0; i < size; i++) {
            WxBillSettleBill bill = i > wxBillSettle.getReceiveBillIds().size() - 1 ? null : wxBillSettle.getReceiveBillIds().get(i);
            List<String> cellList = new ArrayList<>();
            cellList.add(count + "");

            if (bill != null) {
                cellList.add(bill.getBillName());
                cellList.add(new BigDecimal(bill.getReceivePay()).divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP).toString());
            } else {
                cellList.add("");
                cellList.add("");
            }
            cellList.add(count + "");
            WxBillSettleBill payBill = i > wxBillSettle.getPayBillIds().size() - 1 ? null : wxBillSettle.getPayBillIds().get(i);
            if (payBill != null) {
                cellList.add(payBill.getBillName());
                cellList.add(new BigDecimal(payBill.getReceivePay()).divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP).toString());
            } else {
                cellList.add("");
                cellList.add("");
            }
            rowsParams.add(cellList);
            count++;
        }
        wordDocTableVo.setParams(rowsParams);
        wordDocTableVo.setTableIndex(0);
        wordDocTableVo.setRowIndex(2);

        String templatePath = "contract-word-template/settle.docx";
        String filepath = fmUploadDir;
        String filename = UUID.randomUUID() + ".docx";
        String exportFileName = "结算单.docx";
        WordUtil.exportWord(templatePath, filepath, filename, exportFileName, result, request, response, wordDocTableVo);

    }

    @Override
    public ResultData updateReceivePay(WxBillAll wxBillAll, MallUserInfo user) {
        Integer billType = wxBillAll.getBillTypeValue();
        Long oldPrice = wxBillAll.getOldPrice();
        Long newPrice = wxBillAll.getNewPrice();
        Long oldLatePrice = wxBillAll.getOldLatePrice();
        Long newLatePrice = wxBillAll.getNewLatePrice();
        Long id = wxBillAll.getId();
        Date updateDate = new Date();
        if (billType.equals(EnumBillTypeParam.RENT.getCode())) {
            WxBillRent dbBill = wxBillRentMapper.selectById(id);
            WxBillRent wxBillRent = new WxBillRent();
            wxBillRent.setId(id);
            wxBillRent.setUpdatetime(updateDate);
            if (oldLatePrice != null) {
                wxBillRent.setLatePayPrice(newLatePrice);
                wxBillRentMapper.updateById(wxBillRent);
                addBillAction(EnumBillAction.UPDATE_LATE_PAY_MONEY, id, oldLatePrice, newLatePrice, user);
            } else {
                //租赁账单更新
                wxBillRent.setReceivePay(newPrice);
                wxBillRent.setOwe(newPrice - dbBill.getPay());
                if (newPrice.equals(dbBill.getPay())) {
                    wxBillRent.setStatus(EnumBillRentStatus.PAID.getCode());
                }
                wxBillRentMapper.updateById(wxBillRent);
                //账单日志
                addBillAction(EnumBillAction.UPDATE_BILL, id, oldPrice, newPrice, user);
            }
        } else if (billType.equals(EnumBillTypeParam.RENT_DEPOSIT.getCode())) {
            WxBillDeposit dbBill = wxBillDepositMapper.selectById(id);
            if (dbBill != null) {
                //租赁押金账单更新
                WxBillDeposit wxBillDeposit = new WxBillDeposit();
                wxBillDeposit.setId(id);
                wxBillDeposit.setReceivePay(newPrice);
                wxBillDeposit.setOwe(newPrice - dbBill.getPay());
                if (newPrice.equals(dbBill.getPay())) {
                    wxBillDeposit.setStatus(EnumBillRentStatus.PAID.getCode());
                }
                wxBillDeposit.setUpdatetime(updateDate);
                wxBillDepositMapper.updateById(wxBillDeposit);
                //账单日志
                addBillAction(EnumBillAction.UPDATE_BILL, id, oldPrice, newPrice, user);
            }

            WxBillPropertyDeposit propertyDeposit = wxBillPropertyDepositMapper.selectById(id);
            if (propertyDeposit != null) {
                //物业押金账单更新
                WxBillPropertyDeposit wxBillPropertyDeposit = new WxBillPropertyDeposit();
                wxBillPropertyDeposit.setId(id);
                wxBillPropertyDeposit.setReceivePay(newPrice);
                wxBillPropertyDeposit.setOwe(newPrice - propertyDeposit.getPay());
                if (newPrice.equals(propertyDeposit.getPay())) {
                    wxBillPropertyDeposit.setStatus(EnumBillRentStatus.PAID.getCode());
                }
                wxBillPropertyDeposit.setUpdatetime(updateDate);
                wxBillPropertyDepositMapper.updateById(wxBillPropertyDeposit);
                //账单日志
                addBillAction(EnumBillAction.UPDATE_BILL, id, oldPrice, newPrice, user);
            }
        } else if (billType.equals(EnumBillTypeParam.PROPERTY.getCode())) {
            WxBillProperty dbBill = wxBillPropertyMapper.selectById(id);
            //物业账单更新
            WxBillProperty wxBillProperty = new WxBillProperty();
            wxBillProperty.setId(id);
            wxBillProperty.setUpdatetime(updateDate);
            if (oldLatePrice != null) {
                wxBillProperty.setLatePayPrice(newLatePrice);
                wxBillPropertyMapper.updateById(wxBillProperty);
                addBillAction(EnumBillAction.UPDATE_LATE_PAY_MONEY, id, oldLatePrice, newLatePrice, user);
            } else {
                wxBillProperty.setReceivePay(newPrice);
                wxBillProperty.setOwe(newPrice - dbBill.getPay());
                if (newPrice.equals(dbBill.getPay())) {
                    wxBillProperty.setStatus(EnumBillRentStatus.PAID.getCode());
                }
                wxBillPropertyMapper.updateById(wxBillProperty);
                //账单日志
                addBillAction(EnumBillAction.UPDATE_BILL, id, oldPrice, newPrice, user);
            }
        } else if (billType.equals(EnumBillTypeParam.PROPERTY_DEPOSIT.getCode())) {
            WxBillPropertyDeposit dbBill = wxBillPropertyDepositMapper.selectById(id);
            //物业押金账单更新
            WxBillPropertyDeposit wxBillPropertyDeposit = new WxBillPropertyDeposit();
            wxBillPropertyDeposit.setId(id);
            wxBillPropertyDeposit.setReceivePay(newPrice);
            wxBillPropertyDeposit.setOwe(newPrice - dbBill.getPay());
            if (newPrice.equals(dbBill.getPay())) {
                wxBillPropertyDeposit.setStatus(EnumBillRentStatus.PAID.getCode());
            }
            wxBillPropertyDeposit.setUpdatetime(updateDate);
            wxBillPropertyDepositMapper.updateById(wxBillPropertyDeposit);
            //账单日志
            addBillAction(EnumBillAction.UPDATE_BILL, id, oldPrice, newPrice, user);
        } else if (billType.equals(EnumBillTypeParam.WATER.getCode())) {
            //水费账单更新
            updateDailyBill(id, newPrice, updateDate);
            //账单日志
            addBillAction(EnumBillAction.UPDATE_BILL, id, oldPrice, newPrice, user);
        } else if (billType.equals(EnumBillTypeParam.POWER.getCode())) {
            //电费账单更新
            updateDailyBill(id, newPrice, updateDate);
            //账单日志
            addBillAction(EnumBillAction.UPDATE_BILL, id, oldPrice, newPrice, user);
        } else if (billType.equals(EnumBillTypeParam.AIR_CONDITIONING.getCode())) {
            //空调费账单更新
            updateDailyBill(id, newPrice, updateDate);
            //账单日志
            addBillAction(EnumBillAction.UPDATE_BILL, id, oldPrice, newPrice, user);
        } else if (billType.equals(EnumBillTypeParam.ROUTINE.getCode())) {
            WxBillOther dbBill = wxBillOtherMapper.selectById(id);
            //其他费用账单更新
            WxBillOther wxBillOther = new WxBillOther();
            wxBillOther.setId(id);
            wxBillOther.setReceivePay(newPrice);
            wxBillOther.setOwe(newPrice - dbBill.getPay());
            if (newPrice.equals(dbBill.getPay())) {
                wxBillOther.setStatus(EnumBillRentStatus.PAID.getCode());
            }
            wxBillOther.setUpdatetime(updateDate);
            wxBillOtherMapper.updateById(wxBillOther);
            //账单日志
            addBillAction(EnumBillAction.UPDATE_BILL, id, oldPrice, newPrice, user);
        } else if (billType.equals(EnumBillTypeParam.ATHER_DEPOSIT.getCode())) {
            WxBillOtherDeposit dbBill = wxBillOtherDepositMapper.selectById(id);
            //其他押金账单更新
            WxBillOtherDeposit wxBillOtherDeposit = new WxBillOtherDeposit();
            wxBillOtherDeposit.setId(id);
            wxBillOtherDeposit.setReceivePay(newPrice);
            wxBillOtherDeposit.setOwe(newPrice - dbBill.getPay());
            if (newPrice.equals(dbBill.getPay())) {
                wxBillOtherDeposit.setStatus(EnumBillRentStatus.PAID.getCode());
            }
            wxBillOtherDeposit.setUpdatetime(updateDate);
            wxBillOtherDepositMapper.updateById(wxBillOtherDeposit);
            //账单日志
            addBillAction(EnumBillAction.UPDATE_BILL, id, oldPrice, newPrice, user);
        } else {
            logger.info("未找到账单类型");
        }
        return new ResultData();
    }

    @Override
    public void addBillAction(EnumBillAction billAction, Long billId, Long oldPrice, Long newPrice, MallUserInfo mallUserInfo) {
        WxBillAction wxBillAction = new WxBillAction();
        wxBillAction.setBillId(billId);
        String oldPriceStr = new BigDecimal(oldPrice).divide(new BigDecimal(100)).toPlainString();
        String newPriceStr = new BigDecimal(newPrice).divide(new BigDecimal(100)).toPlainString();
        wxBillAction.setDetails(oldPriceStr + "元变更成" + newPriceStr + "元");
        wxBillAction.setAction(billAction.getCode());
        wxBillActionService.modifyBill(wxBillAction, mallUserInfo);
    }


    @Override
    public void exportTemplate(WxBillExcelTemplate WxBillExcelTemplate, HttpServletRequest request, HttpServletResponse response) {
        List<WxBillExcelTemplate> datalist = new ArrayList<>();
        List<WxBillExcelTemplateOther> otherDatalist = new ArrayList<>();

        Integer billType = WxBillExcelTemplate.getBillType();
        if (billType.equals(EnumBillExcelTemplate.DAILY.getCode())) {
            WxBillExcelTemplateOther one = new WxBillExcelTemplateOther();
            Date date = new Date();
            one.setMerchantName("商户1");
            one.setBillType(billType);
            one.setBillAttr("水费");
            one.setStarttime(date);
            one.setEndtime(date);
            one.setReceivePayStr("1000");
            one.setPayStr("1000");
            one.setPayDate(date);
            one.setReceiveDate(date);
            one.setPayWay("微信");
            otherDatalist.add(one);

            WxBillExcelTemplateOther two = new WxBillExcelTemplateOther();
            two.setMerchantName("商户2");
            two.setBillType(billType);
            two.setBillAttr("电费");
            two.setStarttime(date);
            two.setEndtime(date);
            two.setReceivePayStr("2000.50");
            two.setPayStr("2000.50");
            two.setPayDate(date);
            two.setReceiveDate(date);
            two.setPayWay("支付宝");
            otherDatalist.add(two);

            WxBillExcelTemplateOther three = new WxBillExcelTemplateOther();
            three.setMerchantName("商户3");
            three.setBillType(billType);
            three.setBillAttr("空调费");
            three.setStarttime(date);
            three.setEndtime(date);
            three.setReceivePayStr("3333");
            three.setPayStr("3333");
            three.setPayDate(date);
            three.setReceiveDate(date);
            three.setPayWay("其他");
            otherDatalist.add(three);
            excelService.exportExcel(otherDatalist, null, "账单模板", WxBillExcelTemplateOther.class, "账单模板.xlsx", response, true);
        } else if (billType.equals(EnumBillExcelTemplate.SHOP_RENT.getCode()) || billType.equals(EnumBillExcelTemplate.POINT_RENT.getCode())) {
            WxBillExcelTemplate one = new WxBillExcelTemplate();
            Date date = new Date();
            one.setMerchantName("商户");
            one.setBillType(billType);
            one.setBillAttr("租金");
            one.setStarttime(date);
            one.setEndtime(date);
            one.setPayStr("2000.50");
            one.setReceiveDate(date);
            one.setPayDate(date);
            one.setPayWay("微信");
            datalist.add(one);
            excelService.exportExcel(datalist, null, "账单模板", WxBillExcelTemplate.class, "账单模板.xlsx", response, true);
        } else if (billType.equals(EnumBillExcelTemplate.SHOP_PROPERTY.getCode()) || billType.equals(EnumBillExcelTemplate.POINT_PROPERTY.getCode())) {
            WxBillExcelTemplate one = new WxBillExcelTemplate();
            Date date = new Date();
            one.setMerchantName("商户");
            one.setBillType(billType);
            one.setBillAttr("物业费");
            one.setStarttime(date);
            one.setEndtime(date);
            one.setPayStr("2000.50");
            one.setReceiveDate(date);
            one.setPayDate(date);
            one.setPayWay("微信");
            datalist.add(one);
            excelService.exportExcel(datalist, null, "账单模板", WxBillExcelTemplate.class, "账单模板.xlsx", response, true);
        } else if (billType.equals(EnumBillExcelTemplate.OTHER.getCode())) {
            WxBillExcelTemplateOther one = new WxBillExcelTemplateOther();
            Date date = new Date();
            one.setMerchantName("商户");
            one.setBillType(billType);
            one.setBillAttr("其他费用");
            one.setStarttime(date);
            one.setEndtime(date);
            one.setReceivePayStr("2000.50");
            one.setPayStr("2000.50");
            one.setReceiveDate(date);
            one.setPayDate(date);
            one.setPayWay("微信");
            otherDatalist.add(one);
            excelService.exportExcel(otherDatalist, null, "账单模板", WxBillExcelTemplateOther.class, "账单模板.xlsx", response, true);
        } else {
            WxBillExcelTemplateOther one = new WxBillExcelTemplateOther();
            Date date = new Date();
            one.setMerchantName("商户");
            one.setBillType(billType);
            one.setBillAttr("其他押金");
            one.setStarttime(date);
            one.setEndtime(date);
            one.setReceivePayStr("2000.50");
            one.setPayStr("2000.50");
            one.setReceiveDate(date);
            one.setPayDate(date);
            one.setPayWay("微信");
            otherDatalist.add(one);
            excelService.exportExcel(otherDatalist, null, "账单模板", WxBillExcelTemplateOther.class, "账单模板.xlsx", response, true);
        }
    }

    @Override
    public void importBillOther(String tenantId, String importKey, WxBillExcelTemplateOther bill, MallUserInfo user) {
        Integer billType = bill.getBillType();
        long receivePay = new BigDecimal(bill.getReceivePayStr()).multiply(new BigDecimal(100)).longValueExact();
        long pay = new BigDecimal(bill.getPayStr()).multiply(new BigDecimal(100)).longValueExact();
        if (billType.equals(EnumBillExcelTemplate.DAILY.getCode())) {
            WxBillDaily dailyQuery = new WxBillDaily();
            String billAttrStr = StringUtils.trim(bill.getBillAttr());
            if (billAttrStr.equals(EnumBillExcelTemplateDaily.WATER.getMessage())) {
                dailyQuery.setType(EnumBillDailyType.WATER.getCode());
            }
            if (billAttrStr.equals(EnumBillExcelTemplateDaily.POWER.getMessage())) {
                dailyQuery.setType(EnumBillDailyType.POWER.getCode());
            }
            if (billAttrStr.equals(EnumBillExcelTemplateDaily.AIR_CONDITIONING.getMessage())) {
                dailyQuery.setType(EnumBillDailyType.AIR_CONDITIONING.getCode());
            }
            dailyQuery.setTenantId(tenantId);
            dailyQuery.setMerchantId(bill.getMerchantId());
            dailyQuery.setReceiveDate(bill.getReceiveDate());
            dailyQuery.setIsDel(EnumDelStatus.NOT_DEL.getCode());
            WxBillDaily daily = wxBillDailyMapper.selectOne(new QueryWrapper(dailyQuery));
            if (daily != null && pay > 0) {
                if (!daily.getStatus().equals(EnumBillRentStatus.PAID.getCode())) {
                    long allPay = new BigDecimal(daily.getPay()).add(new BigDecimal(pay)).longValueExact();
                    WxBillRent expiredDayAndStatus = getExpiredDayAndStatus(bill.getReceiveDate(), bill.getPayDate(), receivePay, allPay, false);
                    daily.setExpiredDay(expiredDayAndStatus.getExpiredDay());
                    daily.setStatus(expiredDayAndStatus.getStatus());
                    daily.setReceivePay(receivePay);
                    daily.setPay(allPay);
                    daily.setOwe(0L);
                    long owe = daily.getReceivePay() - daily.getPay();
                    if (owe > 0) {
                        daily.setOwe(owe);
                    }
                    daily.setPayDate(bill.getPayDate());
                    daily.setReceiveDate(bill.getReceiveDate());
                    wxBillDailyMapper.updateById(daily);
                    addActionImport(daily.getId(), bill.getPayWay(), bill.getPayDate(), user, bill.getPayStr());
                }
            } else {
                WxMerchantShop wxMerchantShop = new WxMerchantShop();
                wxMerchantShop.setTenantId(tenantId);
                wxMerchantShop.setMerchantId(bill.getMerchantId());
                wxMerchantShop.setIsDel(EnumDelStatus.NOT_DEL.getCode());
                List<WxMerchantShop> select = wxMerchantShopMapper.selectList(new QueryWrapper<>(wxMerchantShop));
                if (!select.isEmpty()) {
                    daily = new WxBillDaily();
                    final IdWorker idWorker = IdWorker.get();
                    daily.setId(idWorker.nextId());
                    daily.setReceivePay(receivePay);
                    daily.setReceiveDate(bill.getReceiveDate());
                    daily.setPay(pay);
                    daily.setType(dailyQuery.getType());
                    daily.setTenantId(tenantId);
                    daily.setMerchantId(bill.getMerchantId());
                    daily.setShopId(select.get(0).getShopId());
                    daily.setRentShopType(bill.getMerchantType());
                    daily.setPayDate(bill.getPayDate());
                    Date date = new Date();
                    daily.setCreatetime(date);
                    daily.setUpdatetime(date);
                    daily.setOwe(receivePay - pay);
                    daily.setIsDel(EnumDelStatus.NOT_DEL.getCode());
                    daily.setStarttime(bill.getStarttime());
                    daily.setEndtime(bill.getEndtime());
                    WxBillRent expiredDayAndStatus = getExpiredDayAndStatus(bill.getReceiveDate(), bill.getPayDate(), receivePay, pay, false);
                    daily.setExpiredDay(expiredDayAndStatus.getExpiredDay());
                    daily.setStatus(expiredDayAndStatus.getStatus());
                    daily.setBuildWay(EnumBillDailyBuildWay.IMPORT.getCode());
                    wxBillDailyMapper.insert(daily);
                    if (pay > 0) {
                        addActionImport(daily.getId(), bill.getPayWay(), bill.getPayDate(), user, bill.getPayStr());
                    }
                }
            }
        } else if (billType.equals(EnumBillExcelTemplate.OTHER.getCode())) {
            WxBillOther otherQuery = new WxBillOther();
            otherQuery.setTenantId(tenantId);
            otherQuery.setMerchantId(bill.getMerchantId());
            otherQuery.setReceiveDate(bill.getReceiveDate());
            otherQuery.setName(bill.getBillAttr());
            otherQuery.setIsDel(EnumDelStatus.NOT_DEL.getCode());
            WxBillOther other = wxBillOtherMapper.selectOne(new QueryWrapper(otherQuery));
            if (other != null && pay > 0) {
                if (!other.getStatus().equals(EnumBillRentStatus.PAID.getCode())) {
                    long allPay = new BigDecimal(other.getPay()).add(new BigDecimal(pay)).longValueExact();
                    WxBillRent expiredDayAndStatus = getExpiredDayAndStatus(bill.getReceiveDate(), bill.getPayDate(), receivePay, allPay, false);
                    other.setExpiredDay(expiredDayAndStatus.getExpiredDay());
                    other.setStatus(expiredDayAndStatus.getStatus());
                    other.setReceivePay(receivePay);
                    other.setName(bill.getBillAttr());
                    other.setComments(bill.getBillAttr());
                    other.setPay(allPay);
                    other.setOwe(0L);
                    long owe = other.getReceivePay() - other.getPay();
                    if (owe > 0) {
                        other.setOwe(owe);
                    }
                    other.setPayDate(bill.getPayDate());
                    other.setReceiveDate(bill.getReceiveDate());
                    wxBillOtherMapper.updateById(other);
                    addActionImport(other.getId(), bill.getPayWay(), bill.getPayDate(), user, bill.getPayStr());
                }
            } else {
                WxMerchantShop wxMerchantShop = new WxMerchantShop();
                wxMerchantShop.setTenantId(tenantId);
                wxMerchantShop.setMerchantId(bill.getMerchantId());
                wxMerchantShop.setIsDel(EnumDelStatus.NOT_DEL.getCode());
                List<WxMerchantShop> select = wxMerchantShopMapper.selectList(new QueryWrapper(wxMerchantShop));
                if (!select.isEmpty()) {
                    other = new WxBillOther();
                    final IdWorker idWorker = IdWorker.get();
                    other.setId(idWorker.nextId());
                    other.setName(bill.getBillAttr());
                    other.setComments(bill.getBillAttr());
                    other.setReceivePay(receivePay);
                    other.setReceiveDate(bill.getReceiveDate());
                    other.setPay(pay);
                    other.setTenantId(tenantId);
                    other.setMerchantId(bill.getMerchantId());
                    other.setShopId(select.get(0).getShopId());
                    other.setRentShopType(bill.getMerchantType());
                    other.setPayDate(bill.getPayDate());
                    Date date = new Date();
                    other.setCreatetime(date);
                    other.setUpdatetime(date);
                    other.setOwe(receivePay - pay);
                    other.setIsDel(EnumDelStatus.NOT_DEL.getCode());
                    other.setStarttime(bill.getStarttime());
                    other.setEndtime(bill.getEndtime());
                    WxBillRent expiredDayAndStatus = getExpiredDayAndStatus(bill.getReceiveDate(), bill.getPayDate(), receivePay, pay, false);
                    other.setExpiredDay(expiredDayAndStatus.getExpiredDay());
                    other.setStatus(expiredDayAndStatus.getStatus());
                    wxBillOtherMapper.insert(other);
                    if (pay > 0) {
                        addActionImport(other.getId(), bill.getPayWay(), bill.getPayDate(), user, bill.getPayStr());
                    }
                }
            }
        } else if (billType.equals(EnumBillExcelTemplate.OTHER_DEPOSIT.getCode())) {
            WxBillOtherDeposit otherDepositQuery = new WxBillOtherDeposit();
            otherDepositQuery.setTenantId(tenantId);
            otherDepositQuery.setMerchantId(bill.getMerchantId());
            otherDepositQuery.setReceiveDate(bill.getReceiveDate());
            otherDepositQuery.setComments(bill.getBillAttr());
            otherDepositQuery.setIsDel(EnumDelStatus.NOT_DEL.getCode());
            WxBillOtherDeposit otherDeposit = wxBillOtherDepositMapper.selectOne(new QueryWrapper(otherDepositQuery));
            if (otherDeposit != null && pay > 0) {
                if (!otherDeposit.getStatus().equals(EnumBillRentStatus.PAID.getCode()) && !otherDeposit.getStatus().equals(EnumBillRentStatus.RETURN.getCode())) {
                    long allPay = new BigDecimal(otherDeposit.getPay()).add(new BigDecimal(pay)).longValueExact();
                    otherDeposit.setExpiredDay(0L);
                    if (allPay >= receivePay) {
                        otherDeposit.setStatus(EnumBillRentStatus.PAID.getCode());
                    } else {
                        otherDeposit.setStatus(EnumBillRentStatus.WAIT_PAY.getCode());
                    }
                    otherDeposit.setReceivePay(receivePay);
                    otherDeposit.setPay(allPay);
                    otherDeposit.setOwe(0L);
                    long owe = otherDeposit.getReceivePay() - otherDeposit.getPay();
                    if (owe > 0) {
                        otherDeposit.setOwe(owe);
                    }
                    otherDeposit.setPayDate(bill.getPayDate());
                    otherDeposit.setReceiveDate(bill.getReceiveDate());
                    wxBillOtherDepositMapper.updateById(otherDeposit);
                    addActionImport(otherDeposit.getId(), bill.getPayWay(), bill.getPayDate(), user, bill.getPayStr());
                }
            } else {
                WxMerchantShop wxMerchantShop = new WxMerchantShop();
                wxMerchantShop.setTenantId(tenantId);
                wxMerchantShop.setMerchantId(bill.getMerchantId());
                otherDepositQuery.setReceiveDate(bill.getReceiveDate());
                wxMerchantShop.setIsDel(EnumDelStatus.NOT_DEL.getCode());
                List<WxMerchantShop> select = wxMerchantShopMapper.selectList(new QueryWrapper(wxMerchantShop));
                if (!select.isEmpty()) {
                    otherDeposit = new WxBillOtherDeposit();
                    final IdWorker idWorker = IdWorker.get();
                    otherDeposit.setId(idWorker.nextId());
                    otherDeposit.setName(bill.getBillAttr());
                    otherDeposit.setComments(bill.getBillAttr());
                    otherDeposit.setReceivePay(receivePay);
                    otherDeposit.setReceiveDate(bill.getReceiveDate());
                    otherDeposit.setPay(pay);
                    otherDeposit.setTenantId(tenantId);
                    otherDeposit.setMerchantId(bill.getMerchantId());
                    otherDeposit.setShopId(select.get(0).getShopId());
                    otherDeposit.setRentShopType(bill.getMerchantType());
                    otherDeposit.setPayDate(bill.getPayDate());
                    Date date = new Date();
                    otherDeposit.setCreatetime(date);
                    otherDeposit.setUpdatetime(date);
                    otherDeposit.setExpiredDay(0L);
                    otherDeposit.setOwe(receivePay - pay);
                    otherDeposit.setIsDel(EnumDelStatus.NOT_DEL.getCode());
                    otherDeposit.setStarttime(bill.getStarttime());
                    otherDeposit.setEndtime(bill.getEndtime());
                    if (receivePay <= pay) {
                        otherDeposit.setStatus(EnumBillRentStatus.PAID.getCode());
                    } else {
                        otherDeposit.setStatus(EnumBillRentStatus.WAIT_PAY.getCode());
                    }
                    wxBillOtherDepositMapper.insert(otherDeposit);
                    if (pay > 0) {
                        addActionImport(otherDeposit.getId(), bill.getPayWay(), bill.getPayDate(), user, bill.getPayStr());
                    }
                }
            }
        } else {
            logger.error("账单导入失败");
        }
        //记数
        stringRedisTemplate.opsForHash().increment(importKey, "processCount", 1);
        stringRedisTemplate.expire(importKey, 10, TimeUnit.SECONDS);
    }

    public WxBillRent getExpiredDayAndStatus(Date startDate, Date endDate, Long owe, Long pay, boolean flag) {
        WxBillRent rent = new WxBillRent();
        rent.setExpiredDay(0L);
        if (owe <= pay) {
            rent.setStatus(EnumBillRentStatus.PAID.getCode());
            int expiredDay = DateUtils.daysBetween(startDate, endDate);
            int timePeriod = 0;
            if (expiredDay > timePeriod) {
                rent.setExpiredDay((long) expiredDay);
            }
            return rent;
        }
        Date now = new Date();
        int day = DateUtils.daysBetween(startDate, now);
        int timePeriod = 0;
        if (day > timePeriod) {
            rent.setStatus(EnumBillRentStatus.NOT_PAID.getCode());
            rent.setExpiredDay((long) day);
            return rent;
        }
        if (flag) {
            timePeriod = 30;
            long expiredDay = Long.valueOf(Math.abs(day));
            if (expiredDay > timePeriod) {
                rent.setStatus(EnumBillRentStatus.NOT_EXPIRED.getCode());
            } else {
                rent.setStatus(EnumBillRentStatus.WAIT_PAY.getCode());
            }
        } else {
            rent.setStatus(EnumBillRentStatus.WAIT_PAY.getCode());
        }
        return rent;
    }

    @Override
    public void importBill(String tenantId, String importKey, WxBillExcelTemplate bill, MallUserInfo user) {
        //租金
        Integer billType = bill.getBillType();
        if (billType.equals(EnumBillExcelTemplate.SHOP_RENT.getCode()) || billType.equals(EnumBillExcelTemplate.POINT_RENT.getCode())) {
            WxBillRent rentQuery = new WxBillRent();
            rentQuery.setTenantId(tenantId);
            rentQuery.setMerchantId(bill.getMerchantId());
            rentQuery.setStarttime(bill.getStarttime());
            rentQuery.setEndtime(bill.getEndtime());
            if (billType.equals(EnumBillExcelTemplate.SHOP_RENT.getCode())) {
                rentQuery.setRentShopType(EnumRentShopType.SHOP.getCode());
            } else {
                rentQuery.setRentShopType(EnumRentShopType.POINT.getCode());
            }
            rentQuery.setIsPreview(EnumIsPreview.NO.getCode());
            WxBillRent rent = wxBillRentMapper.selectBillOne(rentQuery);
            if (rent != null && !rent.getStatus().equals(EnumBillRentStatus.PAID.getCode())) {
                long pay = new BigDecimal(bill.getPayStr()).multiply(new BigDecimal(100)).longValueExact();
                WxBillRent expiredDayAndStatus = getExpiredDayAndStatus(bill.getReceiveDate(), bill.getPayDate(), rent.getOwe(), pay, true);
                rent.setExpiredDay(expiredDayAndStatus.getExpiredDay());
                rent.setStatus(expiredDayAndStatus.getStatus());
                rent.setPay(rent.getPay() + pay);
                rent.setOwe(rent.getOwe() - pay);
                rent.setPayDate(bill.getPayDate());
                rent.setReceiveDate(bill.getReceiveDate());
                wxBillRentMapper.updateById(rent);
                if (pay > 0) {
                    addActionImport(rent.getId(), bill.getPayWay(), bill.getPayDate(), user, bill.getPayStr());
                }
            }
        } else if (billType.equals(EnumBillExcelTemplate.SHOP_PROPERTY.getCode()) || billType.equals(EnumBillExcelTemplate.POINT_PROPERTY.getCode())) {
            WxBillProperty propertyQuery = new WxBillProperty();
            propertyQuery.setTenantId(tenantId);
            propertyQuery.setMerchantId(bill.getMerchantId());
            propertyQuery.setStarttime(bill.getStarttime());
            propertyQuery.setEndtime(bill.getEndtime());
            if (billType.equals(EnumBillExcelTemplate.SHOP_PROPERTY.getCode())) {
                propertyQuery.setRentShopType(EnumRentShopType.SHOP.getCode());
            } else {
                propertyQuery.setRentShopType(EnumRentShopType.POINT.getCode());
            }
            propertyQuery.setIsPreview(EnumIsPreview.NO.getCode());
            WxBillProperty property = wxBillPropertyMapper.selectBillOne(propertyQuery);
            if (property != null && !property.getStatus().equals(EnumBillRentStatus.PAID.getCode())) {
                long pay = new BigDecimal(bill.getPayStr()).multiply(new BigDecimal(100)).longValueExact();
                WxBillRent expiredDayAndStatus = getExpiredDayAndStatus(bill.getReceiveDate(), bill.getPayDate(), property.getOwe(), pay, true);
                property.setExpiredDay(expiredDayAndStatus.getExpiredDay());
                property.setStatus(expiredDayAndStatus.getStatus());
                property.setPay(property.getPay() + pay);
                property.setOwe(property.getOwe() - pay);
                property.setPayDate(bill.getPayDate());
                property.setReceiveDate(bill.getReceiveDate());
                wxBillPropertyMapper.updateById(property);
                if (pay > 0) {
                    addActionImport(property.getId(), bill.getPayWay(), bill.getPayDate(), user, bill.getPayStr());
                }
            }
        } else {
            logger.error("账单导入失败");
        }
        //记数
        stringRedisTemplate.opsForHash().increment(importKey, "processCount", 1);
        stringRedisTemplate.expire(importKey, 10, TimeUnit.SECONDS);
    }

    public void addActionImport(Long billId, String payWay, Date payDate, MallUserInfo user, String pay) {
        WxBillAction wxBillAction = new WxBillAction();
        wxBillAction.setBillId(billId);
        String details = StringUtils.isEmpty(payWay) ? "其他缴费" : payWay + "缴费";
        wxBillAction.setDetails(details + pay + "元");
        wxBillAction.setAction(EnumBillAction.IMPORT_PAY.getCode());
        wxBillAction.setPayDate(payDate);
        wxBillActionService.modifyBill(wxBillAction, user);
    }

    public void updateDailyBill(Long businessId, Long newPrice, Date updateDate) {
        WxBillDaily dbBill = wxBillDailyMapper.selectById(businessId);
        WxBillDaily wxBillDaily = new WxBillDaily();
        wxBillDaily.setId(businessId);
        wxBillDaily.setReceivePay(newPrice);
        wxBillDaily.setOwe(newPrice - dbBill.getPay());
        if (newPrice.equals(dbBill.getPay())) {
            wxBillDaily.setStatus(EnumBillRentStatus.PAID.getCode());
        }
        wxBillDaily.setUpdatetime(updateDate);
        wxBillDailyMapper.updateById(wxBillDaily);
    }

    @Override
    public Object getBillInfo(WxBillAll record) {

        record.setRentShopType(EnumRentShopType.SHOP.getCode());
        record.setStatus(EnumBillRentStatus.NOT_PAID.getCode());
        Map<String, Object> oweInfoForShop = wxBillAllMapper.queryOweInfo(record);
        record.setStatus(EnumBillRentStatus.PAID.getCode());
        Map<String, Object> paidInfoForShop = wxBillAllMapper.queryPaidInfo(record);

        record.setRentShopType(EnumRentShopType.POINT.getCode());
        record.setStatus(EnumBillRentStatus.NOT_PAID.getCode());
        Map<String, Object> oweInfoForPoint = wxBillAllMapper.queryOweInfo(record);
        record.setStatus(EnumBillRentStatus.PAID.getCode());
        Map<String, Object> paidInfoForPoint = wxBillAllMapper.queryPaidInfo(record);

        Map<String, Object> result = new HashMap<>(4);
        result.put("oweInfoForShop", oweInfoForShop);
        result.put("paidInfoForShop", paidInfoForShop);
        result.put("oweInfoForPoint", oweInfoForPoint);
        result.put("paidInfoForPoint", paidInfoForPoint);
        return result;
    }

    @Override
    public Long hasOweBill(Long contractId, Integer type) {
        if (type.intValue() == 1) {
            return wxBillRentMapper.oweBillCount(contractId);
        } else if (type.intValue() == 2) {
            return wxBillPropertyMapper.oweBillCount(contractId);
        }
        return 0L;
    }

    public Map<Long, List<Map<String, Object>>> toMap(List<Map<String, Object>> mapList) {
        Map<Long, List<Map<String, Object>>> result = new HashMap<>();
        for (Map<String, Object> bill : mapList) {
            Long merchantId = (Long) bill.get("merchantId");
            List<Map<String, Object>> currList = result.get(merchantId);
            if (currList == null) {
                currList = new ArrayList<>();
            }
            currList.add(bill);
            result.put(merchantId, currList);
        }
        return result;
    }

    @Override
    public void sendWaitPayBillEmail() {
        List<Map<String, Object>> waitBillListForEmail = wxBillAllMapper.getWaitPayBillForEmail();

        if (CollectionUtils.isNotEmpty(waitBillListForEmail)) {
            Map<Long, List<Map<String, Object>>> merchantMap = toMap(waitBillListForEmail);
            for (Long merchantId : merchantMap.keySet()) {
                List<Map<String, Object>> mapList = merchantMap.get(merchantId);
                if (CollectionUtils.isNotEmpty(mapList)) {
                    String email = (String) mapList.get(0).get("email");
                    if (StringUtils.isBlank(email)) {
                        continue;
                    }
                    String tenantId = (String) mapList.get(0).get("tenantId");
                    String receiveDate = (String) mapList.get(0).get("receiveDate");
                    String manager = (String) mapList.get(0).get("manager");
                    String managerPhone = (String) mapList.get(0).get("managerPhone");

                    String billListStr = "";
                    BigDecimal sumNeedPay = new BigDecimal(0);
                    for (Map<String, Object> bill : mapList) {
                        String billType = bill.get("billType").toString();
                        BigDecimal needPay = (BigDecimal) bill.get("needPay");
                        BigDecimal price = needPay.divide(new BigDecimal(100)).setScale(2, RoundingMode.HALF_EVEN);

                        sumNeedPay = sumNeedPay.add(price);
                        billListStr += "<div style=\"margin: 0 5%;width:90%;box-sizing: content-box; border: 1px solid #DEDEDE;background: #FFFFFF;\"><div style=\"overflow: hidden;height: auto;width: 100%;\">";
                        billListStr += "<div style=\"width: 33.3%;float: left;height: 60px;line-height: 60px;text-align: center;font-family:MicrosoftYaHei;color:rgba(85,85,85,1);\">" + billType + "</div>";
                        billListStr += "<div style=\"width: 33.3%;float: left;height: 60px;line-height: 60px;text-align: center;font-family:MicrosoftYaHei;color:rgba(85,85,85,1);\">" + price + "</div>";
                        billListStr += "<div style=\"width: 33.3%;float: left;height: 60px;line-height: 60px;text-align: center;font-family:MicrosoftYaHei;color:rgba(85,85,85,1);\">" + receiveDate + "</div>";
                        billListStr += "</div></div>";
                    }
                    //发邮件
                    Map<String, String> map = new HashedMap();
                    map.put("price", sumNeedPay.toString());
                    map.put("date", receiveDate);
                    map.put("billList", billListStr);
                    map.put("linkName", manager == null ? "" : manager);
                    map.put("linkPhone", managerPhone == null ? "" : managerPhone);
                    MailMsg mailMsg = new MailMsg();
                    mailMsg.setSubject("待缴账单通知");
                    mailMsg.setHtml(true);
                    mailMsg.setMsgType(EnumMsgRecordType.EMAIL.getCode());
                    mailMsg.setModelType(EnumMailMsgModel.MAIL_BILL_WAIT_PAY.getCode());
                    mailMsg.setModelId(EnumMsgModelId.MAIL_MSG_FLOW.getCode());
                    mailMsg.setTo(new String[]{email});
                    mailMsg.setTenantId(tenantId);
                    mailMsg.setDynamicContentMap(map);
                    mqBaseProducer.sendMessage(mailMsg, EnumMsgMqTopic.DEFAULT.getCode(), EnumMsgMqTag.DEFAULT.getCode(), EnumMsgMqKey.DEFAULT.getCode());
                }
            }
        }
    }

    @Override
    public void sendOweBillForEmail() {
        List<Map<String, Object>> oweBillForEmail = wxBillAllMapper.getOweBillForEmail();

        if (CollectionUtils.isNotEmpty(oweBillForEmail)) {
            Map<Long, List<Map<String, Object>>> merchantMap = toMap(oweBillForEmail);
            for (Long merchantId : merchantMap.keySet()) {
                List<Map<String, Object>> mapList = merchantMap.get(merchantId);
                if (CollectionUtils.isNotEmpty(mapList)) {
                    String email = (String) mapList.get(0).get("email");
                    if (StringUtils.isBlank(email)) {
                        continue;
                    }
                    String tenantId = (String) mapList.get(0).get("tenantId");
                    String receiveDate = (String) mapList.get(0).get("receiveDate");
                    String manager = (String) mapList.get(0).get("manager");
                    String managerPhone = (String) mapList.get(0).get("managerPhone");
                    Long expiredDay = (Long) mapList.get(0).get("expiredDay");

                    String billListStr = "";
                    BigDecimal sumNeedPay = new BigDecimal(0);
                    for (Map<String, Object> bill : mapList) {
                        String billType = bill.get("billType").toString();
                        BigDecimal needPay = (BigDecimal) bill.get("owe");
                        BigDecimal price = needPay.divide(new BigDecimal(100)).setScale(2, RoundingMode.HALF_EVEN);

                        sumNeedPay = sumNeedPay.add(price);
                        billListStr += "<div style=\"margin: 0 5%;width:90%;box-sizing: content-box; border: 1px solid #DEDEDE;background: #FFFFFF;\">";
                        billListStr += "<div style=\"overflow: hidden;height: auto;width: 100%;font-size:14px;\">";
                        billListStr += "<div style=\"width: 25%;float: left;height: 60px;line-height: 60px;text-align: center;font-family:MicrosoftYaHei;color:rgba(85,85,85,1);\">" + billType + "</div>";
                        billListStr += "<div style=\"width: 25%;float: left;height: 60px;line-height: 60px;text-align: center;font-family:MicrosoftYaHei;color:rgba(85,85,85,1);\">" + price + "</div>";
                        billListStr += "<div style=\"width: 25%;float: left;height: 60px;line-height: 60px;text-align: center;font-family:MicrosoftYaHei;color:rgba(85,85,85,1);\">" + receiveDate + "</div>";
                        billListStr += "<div style=\"width: 25%;float: left;height: 60px;line-height: 60px;text-align: center;font-family:MicrosoftYaHei;color:rgba(85,85,85,1);\">" + expiredDay + "</div>";
                        billListStr += "</div></div>";
                    }
                    //发邮件
                    Map<String, String> map = new HashedMap();
                    map.put("price", sumNeedPay.toString());
                    map.put("date", receiveDate);
                    map.put("billList", billListStr);
                    map.put("linkName", manager == null ? "" : manager);
                    map.put("linkPhone", managerPhone == null ? "" : managerPhone);
                    MailMsg mailMsg = new MailMsg();
                    mailMsg.setSubject("欠缴账单通知");
                    mailMsg.setHtml(true);
                    mailMsg.setMsgType(EnumMsgRecordType.EMAIL.getCode());
                    mailMsg.setModelId(EnumMsgModelId.MAIL_MSG_FLOW.getCode());
                    mailMsg.setModelType(EnumMailMsgModel.MAIL_BILL_OWE.getCode());
                    mailMsg.setTo(new String[]{email});
                    mailMsg.setTenantId(tenantId);
                    mailMsg.setDynamicContentMap(map);
                    mqBaseProducer.sendMessage(mailMsg, EnumMsgMqTopic.DEFAULT.getCode(), EnumMsgMqTag.DEFAULT.getCode(), EnumMsgMqKey.DEFAULT.getCode());
                }
            }
        }

    }

    @Override
    public Map<String, Object> getOweBillAsPage(WxBillAll record, Integer pageNum, Integer pageSize) {
        WxPayAccountBill wxPayAccountBill = wxPayAccountBillService.getByTenantId(record.getTenantId());
        PageInfo<Map<String, Object>> pageInfo = PageHelper.startPage(pageNum, pageSize).doSelectPageInfo(() -> wxBillAllMapper.getOweBillAsPage(record));
        List<Map<String, Object>> list = pageInfo.getList();
        for (Map<String, Object> map : list) {
            map.put("rentOwe", subZeroAndDot(map.get("rentOwe").toString()));
            map.put("propertyOwe", subZeroAndDot(map.get("propertyOwe").toString()));
            map.put("depositOwe", subZeroAndDot(map.get("depositOwe").toString()));
            map.put("otherOwe", subZeroAndDot(map.get("otherOwe").toString()));
            map.put("totalOwe", subZeroAndDot(map.get("totalOwe").toString()));

            //加上手续费
            //todo:把手续费率传进sql,在sql中算，汇总到max,直接出结果
            map.put("totalReceivePay", subZeroAndDot(map.get("totalOwe").toString()));

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

    @Override
    public Map<String, Object> getReceiveAndPayBillAsPage(WxBillAll record, Integer pageNum, Integer pageSize) {
        Map<String, Object> result = new HashMap<>();
        record.setLimitStart(0);
        record.setLimitEnd(Integer.MAX_VALUE);
        List totalList = wxBillAllMapper.getReceiveAndPayBillAsPage(record);
        if (CollectionUtils.isEmpty(totalList)) {
            PageHelper.startPage(pageNum, pageSize);
            PageInfo<Map<String, Object>> pageInfo = new PageInfo(new ArrayList());
            pageInfo.setPages(0);
            pageInfo.setTotal(0);
            PageHelper.clearPage();
            result.put("pageInfo", pageInfo);
            return result;
        }

        int total = totalList.size();
        int pages;
        if (total % pageSize == 0) {
            pages = total / pageSize;
        } else {
            pages = total / pageSize + 1;
        }
        record.setLimitStart((pageNum - 1) * pageSize);
        record.setLimitEnd(pageSize);
        List<Map<String, Object>> list = wxBillAllMapper.getReceiveAndPayBillAsPage(record);

        PageHelper.startPage(pageNum, pageSize);
        PageInfo<Map<String, Object>> pageInfo = new PageInfo(list);
        pageInfo.setPages(pages);
        pageInfo.setTotal(total);
        PageHelper.clearPage();
        result.put("pageInfo", pageInfo);
        return result;
    }

    /**
     * 使用java正则表达式去掉多余的.与0
     *
     * @param s
     * @return
     */
    public static String subZeroAndDot(String s) {
        if (s.indexOf(".") > 0) {
            s = s.replaceAll("0+?$", "");//去掉多余的0
            s = s.replaceAll("[.]$", "");//如最后一位是.则去掉
        }
        return s;
    }

    @Override
    public void exportOweMerchant(WxBillAll record, HttpServletRequest request, HttpServletResponse response) {
        List<Map<String, Object>> data = wxBillAllMapper.getOweBillAsPage(record);
        List<OweMerchantVo> list = new ArrayList<>();
        for (Map<String, Object> map : data) {
            OweMerchantVo oweMerchantVo = new OweMerchantVo();
            oweMerchantVo.setLinkPerson((String) map.get("manager"));
            oweMerchantVo.setName((String) map.get("merchantName"));
            oweMerchantVo.setLinkPhone((String) map.get("managerPhone"));

            oweMerchantVo.setDepositOwe(new BigDecimal(subZeroAndDot(map.get("depositOwe").toString())));
            oweMerchantVo.setOtherOwe(new BigDecimal(subZeroAndDot(map.get("otherOwe").toString())));
            oweMerchantVo.setPropertyOwe(new BigDecimal(subZeroAndDot(map.get("propertyOwe").toString())));
            oweMerchantVo.setRentOwe(new BigDecimal(subZeroAndDot(map.get("rentOwe").toString())));
            oweMerchantVo.setTotalOwe(new BigDecimal(subZeroAndDot(map.get("totalOwe").toString())));
            list.add(oweMerchantVo);
        }
        String name = "欠缴商户列表";
        excelService.exportExcel(list, null, name, OweMerchantVo.class, name + ".xlsx", response, false);
    }

    @Override
    public void exportReceiveAndPayBillAsPage(WxBillAll record, HttpServletRequest request, HttpServletResponse response) {
        List<Map<String, Object>> data = wxBillAllMapper.getReceiveAndPayBillAsPage(record);
        List<ReceivedAndPayVo> list = new ArrayList<>();
        for (Map<String, Object> map : data) {
            ReceivedAndPayVo oweMerchantVo = new ReceivedAndPayVo();
            oweMerchantVo.setLinkPerson((String) map.get("linkPerson"));
            oweMerchantVo.setName((String) map.get("name"));
            oweMerchantVo.setLinkPhone((String) map.get("linkPhone"));
            oweMerchantVo.setShopNumber((String) map.get("shopNumber"));
            if (EnumRentShopType.POINT.getCode().equals(map.get("type"))) {
                oweMerchantVo.setShopType("多经点位");
            } else if (EnumRentShopType.SHOP.getCode().equals(map.get("type"))) {
                oweMerchantVo.setShopType("商铺");
            }
            oweMerchantVo.setReceivePay(map.get("receivePay") == null ? "0" : map.get("receivePay").toString());
            oweMerchantVo.setPayOut(map.get("payOut") == null ? "0" : map.get("payOut").toString());
            oweMerchantVo.setBalance(map.get("balance") == null ? "0" : map.get("balance").toString());
            list.add(oweMerchantVo);
        }
        String name = "商户账单列表";
        excelService.exportExcel(list, null, name, ReceivedAndPayVo.class, name + ".xlsx", response, false);
    }

    @Override
    public void exportWaitMerchant(WxBillAll record, HttpServletRequest request, HttpServletResponse response) {
        List<Map<String, Object>> data = wxBillAllMapper.getOweBillAsPage(record);
        List<WaitMerchantVo> list = new ArrayList<>();
        for (Map<String, Object> map : data) {
            WaitMerchantVo oweMerchantVo = new WaitMerchantVo();
            oweMerchantVo.setLinkPerson((String) map.get("manager"));
            oweMerchantVo.setName((String) map.get("merchantName"));
            oweMerchantVo.setLinkPhone((String) map.get("managerPhone"));

            oweMerchantVo.setRentReceivePay(new BigDecimal(subZeroAndDot(map.get("rentReceivePay").toString())));
            oweMerchantVo.setPropertyReceivePay(new BigDecimal(subZeroAndDot(map.get("propertyReceivePay").toString())));
            oweMerchantVo.setDepositReceivePay(new BigDecimal(subZeroAndDot(map.get("depositReceivePay").toString())));
            oweMerchantVo.setOtherReceivePay(new BigDecimal(subZeroAndDot(map.get("otherReceivePay").toString())));
            oweMerchantVo.setTotalReceivePay(new BigDecimal(subZeroAndDot(map.get("totalReceivePay").toString())));
            list.add(oweMerchantVo);
        }
        String name = "待缴商户列表";
        excelService.exportExcel(list, null, name, WaitMerchantVo.class, name + ".xlsx", response, false);
    }

    @Override
    public List<Map<String, Object>> allDepositList(WxBillAll wxBillAll) {
        return wxBillAllMapper.allDepositList(wxBillAll);
    }
}
