package com.iformall.service.impl;

import com.alibaba.fastjson.JSON;
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.Result;
import com.iformall.common.ResultData;
import com.iformall.domain.po.*;
import com.iformall.domain.po.base.BaseEntity;
import com.iformall.domain.vo.BillTimeVo;
import com.iformall.domain.vo.RatioVo;
import com.iformall.enums.*;
import com.iformall.exception.MallinkException;
import com.iformall.mapper.*;
import com.iformall.service.*;
import com.iformall.utils.*;
import org.apache.commons.collections.map.HashedMap;
import org.apache.commons.compress.utils.Lists;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.flowable.engine.RuntimeService;
import org.flowable.engine.TaskService;
import org.flowable.task.api.Task;
import org.joda.time.DateTime;
import org.joda.time.Months;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.SimpleDateFormat;
import java.util.*;

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

    @Autowired
    private String fmUploadDir;

    @Autowired
    WxRentContractMapper wxRentContractMapper;

    @Autowired
    WxShopMapper wxShopMapper;

    @Autowired
    WxMerchantService wxMerchantService;

    @Autowired
    WxBillRentMapper wxBillRentMapper;

    @Autowired
    WxBillDepositMapper wxBillDepositMapper;

    @Autowired
    WxPropertyContractMapper wxPropertyContractMapper;

    @Autowired
    WxMerchantMapper wxMerchantMapper;

    @Autowired
    WxBusinessMapper wxBusinessMapper;

    @Autowired
    WxMallMapper wxMallMapper;

    @Autowired
    WxBrandMapper WxBrandMapper;

    @Autowired
    WxFlowRecordService wxFlowRecordService;

    @Autowired
    RuntimeService runtimeService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private WxFlowService wxFlowService;

    @Autowired
    WxMerchantShopMapper wxMerchantShopMapper;

    @Autowired
    WxFlowRecordMapper wxFlowRecordMapper;

    @Autowired
    WxBillPropertyMapper wxBillPropertyMapper;

    @Autowired
    WxPropertyContractService wxPropertyContractService;

    @Autowired
    WxPayAccountBillService wxPayAccountBillService;

    @Override
    public Map<String, Object> listAsPage(WxRentContract record, Integer pageIndex, Integer pageSize) {
        //Object rentContractStatusInfo = getRentContractStatusInfo(record);
        PageHelper.startPage(pageIndex, pageSize);
        List<Map<String, Object>> rentContractData = wxRentContractMapper.queryRentContractData(record);
        PageInfo<Map<String, Object>> pageInfo = new PageInfo<>(rentContractData);
        Map<String, Object> result = new HashMap<>();
        //result.put("rentContractStatusInfo", rentContractStatusInfo);
        result.put("pageInfo", pageInfo);
        return result;
    }

    @Override
    public Map<String, Object> getById(Long id) {
        Map<String, Object> result = new HashMap<>();
        WxRentContract wxRentContract = wxRentContractMapper.selectById(id);
        if (wxRentContract == null) {
            throw new MallinkException(ErrorCode.RENT_CONTRACT_IS_NOT_FOUND);
        }

        //init dateDiff
        if(wxRentContract.getRentalStartDate() != null && wxRentContract.getRentalEndDate() != null){
            //加1天
            Date newEndDate = DateUtils.getDaySet(wxRentContract.getRentalEndDate(),Calendar.DATE,1);
            int[] array = DateUtils.getDiff(wxRentContract.getRentalStartDate(),newEndDate);
            result.put("totalPeriodMonth",array[0]);
            result.put("totalPeriodDay",array[1]);
        }

        //init rentPrice
        if(StringUtils.isNotBlank(wxRentContract.getRentPrice())){
            wxRentContract.setRentPrice(Double.parseDouble(wxRentContract.getRentPrice())/100 + "");
        }

        //init 租赁单价
        String rentInfo = wxRentContract.getRentInfo();
        if(StringUtils.isNotBlank(rentInfo)){
            JSONArray rentInfoArray = JSONArray.parseArray(rentInfo);
            int size = rentInfoArray.size();
            //查询rent_info 包括shopId
            for (int i = 0; i < size; i++) {
                JSONObject rentInfoObject = rentInfoArray.getJSONObject(i);
                Double rentPrice = rentInfoObject.getDouble("rentPrice");
                Long price = wxRentContract.getPrice()/100;
                if(rentPrice == null){
                    if(StringUtils.isNotBlank(wxRentContract.getRentArea()) && !"0".equals(wxRentContract.getRentArea()) && !"0.00".equals(wxRentContract.getRentArea()) && !"0.0".equals(wxRentContract.getRentArea()) ) {
                        Double rentArea = Double.parseDouble(wxRentContract.getRentArea());
                        rentPrice = new BigDecimal((float) price / rentArea).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
                        rentInfoObject.put("rentPrice", rentPrice);
                    }
                }
            }
            wxRentContract.setRentInfo(rentInfoArray.toJSONString());
        }else{
            if(wxRentContract.getRentPrice() == null || "0".equals(wxRentContract.getRentPrice())){
                if(StringUtils.isNotBlank(wxRentContract.getRentArea()) && !"0".equals(wxRentContract.getRentArea()) && !"0.00".equals(wxRentContract.getRentArea()) && !"0.0".equals(wxRentContract.getRentArea()) ) {
                    Long price = wxRentContract.getPrice()/100;
                    Double rentArea = Double.parseDouble(wxRentContract.getRentArea());
                    Double rentPrice = new BigDecimal((float)price/rentArea).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
                    if(rentPrice > 0){
                        wxRentContract.setRentPrice(rentPrice.toString());
                    }else{
                        wxRentContract.setRentPrice("0");
                    }
                }

            }
        }
        if(wxRentContract.getPriceUnit() == null){
            wxRentContract.setPriceUnit(EnumPriceUnit.M.getCode());
        }
        if(wxRentContract.getAdjustPeriod().equals(EnumRentContractAdjustPeriod.ADJUST_PERIOD_DAY.getCode())){
            wxRentContract.setAdjustPeriod(EnumRentContractAdjustPeriod.ADJUST_PERIOD_MONTH.getCode());
            wxRentContract.setPriceUnit(EnumPriceUnit.D.getCode());
        }

        //商场信息
        WxMall wxMall = new WxMall();
        wxMall.setTenantId(wxRentContract.getTenantId());
        List<WxMall> mallList = wxMallMapper.findList(wxMall);
        if (!mallList.isEmpty()) {
            result.put("mall", mallList.get(0));
        }
        wxRentContract.setPrice(wxRentContract.getPrice() != null ? wxRentContract.getPrice() : 0);
        wxRentContract.setDeposit(wxRentContract.getDeposit() != null ? wxRentContract.getDeposit() : 0);

        result.put("wxRentContract", wxRentContract);
        //关联的商户
        if (wxRentContract.getMerchantId() != null) {
            WxMerchant wxMerchant = wxMerchantService.getById(wxRentContract.getMerchantId());
            result.put("wxMerchant", wxMerchant);
        } else {
            result.put("wxMerchant", null);
        }
        //关联的店铺
        if (wxRentContract.getShopId() != null) {
            WxShop record = new WxShop();
            record.setId(wxRentContract.getShopId());
            List<Map<String, Object>> list = wxShopMapper.findListMap(record);
            result.put("wxShops", list);
        } else {
            result.put("wxShops", Collections.EMPTY_LIST);
        }
        //设置审批流程状态
        result.put("applyStatus", wxRentContract.getApplyStatus());

        //租赁费用欠缴
        result.put("rentOweCount",wxRentContractMapper.queryOweCount(wxRentContract));
        //物业费用欠缴
        WxPropertyContract propertyContract = new WxPropertyContract();
        propertyContract.setRentContractId(id);
        result.put("propertyOweCount",wxPropertyContractMapper.queryOweCount(propertyContract));
        //押金欠缴
        result.put("depositOweCount",wxBillDepositMapper.queryOweCount(wxRentContract));
        //押金状态
        WxBillDeposit wxBillDeposit = new WxBillDeposit();
        wxBillDeposit.setRentContractId(id);
        List<WxBillDeposit> select = wxBillDepositMapper.selectList(new QueryWrapper(wxBillDeposit));
        if (!select.isEmpty()) {
            result.put("depositStatus", select.get(0).getStatus());
        }
        //发起人备注
        WxFlowRecord wxFlowRecord = new WxFlowRecord();
        wxFlowRecord.setBusinessId(id);
        wxFlowRecord.setStatus(EnumFlowRecordStatus.NEW.getCode());
        List<WxFlowRecord> flowRecordList = wxFlowRecordService.findList(wxFlowRecord);
        if(!CollectionUtils.isEmpty(flowRecordList)){
            result.put("remark",flowRecordList.get(0).getRemark());
        }

        //查询预账单用于展示
        WxBillRent wxBillRent = new WxBillRent();
        wxBillRent.setRentContractId(id);
        wxBillRent.setSortColumns(BaseEntity.SortField.Period_ASC);
        List<WxBillRent> resultList = wxBillRentMapper.findList(wxBillRent);
        result.put("previewBillRentList",resultList);

        return result;
    }
    /**
     * 计算金额
     * @param ratio
     * @param revenueLong
     * @return
     */
    public static Long countPrice(Integer ratio,Long revenueLong,int timeType,int period,int from){
        BigDecimal hundred = new BigDecimal(100);
        BigDecimal revenue = new BigDecimal(revenueLong == null ? 0 : revenueLong).divide(hundred);
        BigDecimal payRatio = new BigDecimal(ratio == null ? 0 : ratio).divide(new BigDecimal(10000));
        BigDecimal price;
        if(EnumMissTimeType.YEAR.getCode().equals(timeType) && EnumGetRatioFrom.RENT.getCode().equals(from)){
            price = revenue.multiply(new BigDecimal(12)).multiply(payRatio).setScale(2, RoundingMode.HALF_EVEN);;;
        }else if(EnumMissTimeType.PERIOD.getCode().equals(timeType) && EnumGetRatioFrom.RENT.getCode().equals(from)){
            price = revenue.multiply(new BigDecimal(period)).multiply(payRatio).setScale(2, RoundingMode.HALF_EVEN);;
        }else{
            price = revenue.multiply(payRatio).setScale(2, RoundingMode.HALF_EVEN);
        }
        return price.multiply(hundred).longValue();
    }

    /**
     * 获取设置的跳点率
     * ["1000-1200:10",">3000:20"]
     */
    public static RatioVo getPayRatio(int from,Long revenueLong,String busDiscountRatio,int timeType,long dayCount,int period){
        RatioVo ratioVo = new RatioVo();
        if(StringUtils.isBlank(busDiscountRatio)){
            return ratioVo;
        }
        List<String> ratioList = JSONArray.parseArray(busDiscountRatio, String.class);
        ratioVo.setUseRatio(busDiscountRatio);

        for (int i = 0; i < ratioList.size(); i++) {
            BigDecimal revenue = new BigDecimal(revenueLong).divide(new BigDecimal(1000000)).setScale(8, RoundingMode.HALF_EVEN);
            String e = ratioList.get(i);
            String[] array = e.split(":");
            Integer ratio = Integer.parseInt(array[1]);

            if(e.indexOf("-") >= 0){
                String[] revenueArray = array[0].split("-");
                BigDecimal start = new BigDecimal(revenueArray[0]);
                BigDecimal end = new BigDecimal(revenueArray[1]);

                //残年 （小金额 / 365  *  账单周期天数 ）--（大金额 / 365  *  账单周期天数）
                if(EnumMissTimeType.YEAR.getCode().equals(timeType)){
                    if(EnumGetRatioFrom.BILL.getCode().equals(from)) {
                        start = new BigDecimal(revenueArray[0]).divide(new BigDecimal(365), 10, BigDecimal.ROUND_HALF_DOWN).multiply(new BigDecimal(dayCount));
                        end = new BigDecimal(revenueArray[1]).divide(new BigDecimal(365), 10, BigDecimal.ROUND_HALF_DOWN).multiply(new BigDecimal(dayCount));
                    }
                    if(EnumGetRatioFrom.RENT.getCode().equals(from)) {
                        revenue = revenue.multiply(new BigDecimal(12));
                    }
                }else if(EnumMissTimeType.MONTH.getCode().equals(timeType)){
                    if(EnumGetRatioFrom.BILL.getCode().equals(from)) {
                        start = new BigDecimal(revenueArray[0]).divide(new BigDecimal(30), 10, BigDecimal.ROUND_HALF_DOWN).multiply(new BigDecimal(dayCount));
                        end = new BigDecimal(revenueArray[1]).divide(new BigDecimal(30), 10, BigDecimal.ROUND_HALF_DOWN).multiply(new BigDecimal(dayCount));
                    }
                }else if(EnumMissTimeType.PERIOD.getCode().equals(timeType)){
                    if(EnumGetRatioFrom.RENT.getCode().equals(from)) {
                        revenue = revenue.multiply(new BigDecimal(period));
                    }
                }

                if (revenue.compareTo(start) >= 0 && revenue.compareTo(end)<= 0){
                    ratioVo.setRatio(ratio);
                    ratioVo.setPrice(countPrice(ratioVo.getRatio(),revenueLong,timeType,period,from));
                    break;
                }
            }else if(e.indexOf(">") >= 0){
                String[] revenueArray = array[0].split(">");
                BigDecimal end = new BigDecimal(revenueArray[1]);

                //残年 （小金额 / 365  *  账单周期天数 ）--（大金额 / 365  *  账单周期天数）
                if(EnumMissTimeType.YEAR.getCode().equals(timeType)){
                    if(EnumGetRatioFrom.BILL.getCode().equals(from)) {
                        end = new BigDecimal(revenueArray[1]).divide(new BigDecimal(365), 10, BigDecimal.ROUND_HALF_DOWN).multiply(new BigDecimal(dayCount));
                    }
                    if(EnumGetRatioFrom.RENT.getCode().equals(from)) {
                        revenue = revenue.multiply(new BigDecimal(12));
                    }
                }else if(EnumMissTimeType.MONTH.getCode().equals(timeType)){
                    if(EnumGetRatioFrom.BILL.getCode().equals(from)) {
                        end = new BigDecimal(revenueArray[1]).divide(new BigDecimal(30), 10, BigDecimal.ROUND_HALF_DOWN).multiply(new BigDecimal(dayCount));
                    }
                }else if(EnumMissTimeType.PERIOD.getCode().equals(timeType)){
                    if(EnumGetRatioFrom.RENT.getCode().equals(from)) {
                        revenue = revenue.multiply(new BigDecimal(period));
                    }
                }

                if (revenue.compareTo(end) >= 0){
                    ratioVo.setRatio(ratio);

                    //计算超出部分
                    BigDecimal payRatio = new BigDecimal(ratio).divide(new BigDecimal(10000));
                    BigDecimal balance = revenue.subtract(end).multiply(new BigDecimal(1000000));
                    BigDecimal price = balance.multiply(payRatio).setScale(2, RoundingMode.HALF_EVEN);

                    array = ratioList.get(i-1).split(":");
                    Integer frontatio = Integer.parseInt(array[1]);
                    revenueArray = array[0].split("-");

                    BigDecimal frontEnd;
                    if(EnumGetRatioFrom.BILL.getCode().equals(from)){
                        if(EnumMissTimeType.YEAR.getCode().equals(timeType)){
                            frontEnd = new BigDecimal(revenueArray[1]).divide(new BigDecimal(365), 10, BigDecimal.ROUND_HALF_DOWN).multiply(new BigDecimal(dayCount));
                        }else if(EnumMissTimeType.MONTH.getCode().equals(timeType)){
                            frontEnd = new BigDecimal(revenueArray[1]).divide(new BigDecimal(30), 10, BigDecimal.ROUND_HALF_DOWN).multiply(new BigDecimal(dayCount));
                        }else{
                            frontEnd = new BigDecimal(revenueArray[1]);
                        }
                    }else{
                        frontEnd = new BigDecimal(revenueArray[1]);
                    }

                    BigDecimal frontRatio = new BigDecimal(frontatio).divide(new BigDecimal(10000));
                    BigDecimal frontPrice = frontEnd.multiply(new BigDecimal(1000000).multiply(frontRatio).setScale(2, RoundingMode.HALF_EVEN));

                    ratioVo.setPrice(price.add(frontPrice).longValue());
                    break;
                }
            }
        }
        return ratioVo;
    }

    @Transactional(rollbackFor = {Exception.class})
    @Override
    public ResultData save(WxRentContract record,Long userId,String userName,Date oldRentStartDate) {
        //保存租赁合同信息
        final IdWorker idWorker = IdWorker.get();
        record.setId(idWorker.nextId());
        int dayType = record.getAdjustPeriod().equals(EnumRentContractAdjustPeriod.ADJUST_PERIOD_DAY.getCode()) ? Calendar.DAY_OF_MONTH : Calendar.MONTH;
        //计租开始时间
        Calendar instance = Calendar.getInstance();
        instance.setTime(record.getRentalStartDate());
        instance.add(dayType, record.getLease());
        instance.add(Calendar.DAY_OF_MONTH, -1);
        //起租结束时间
        if (!record.getStartDate().equals(record.getRentalStartDate())) {
            instance.clear();
            instance.setTime(record.getRentalStartDate());
            instance.add(Calendar.DAY_OF_MONTH, -1);
            record.setEndDate(instance.getTime());
        } else {
            record.setEndDate(record.getStartDate());
        }

        if (record.getType().equals(EnumRentContractType.RENT_BY_JOINT.getCode())) {
            if(record.getRevenue() == null || record.getRevenue().longValue() <= 0){
                record.setPrice(0l);
            }else{
                if(record.getPayRatio()!=null && record.getPayRatio().intValue() > 0){
                    record.setPrice(countPrice(record.getPayRatio(),record.getRevenue(),EnumMissTimeType.OTHER.getCode(),record.getAdjustPeriod(),EnumGetRatioFrom.RENT.getCode()));
                }else{
                    int dayCount = record.getReceivePeriod() * 30;
                    RatioVo ratioVo = getPayRatio(EnumGetRatioFrom.RENT.getCode(),record.getRevenue(),record.getBusDiscountRatio(),record.getBusDiscountTime(),dayCount,record.getReceivePeriod());
                    //record.setPayRatio(ratioVo.getRatio());
                    record.setPrice(ratioVo.getPrice());
                }
            }
        } else {
            if (StringUtils.isNotEmpty(record.getPriceStr())) {
                record.setPrice(new BigDecimal(record.getPriceStr()).multiply(new BigDecimal(100)).longValue());
            } else {
                record.setPrice(0L);
            }
        }
        if (StringUtils.isNotEmpty(record.getDepositStr())) {
            record.setDeposit(new BigDecimal(record.getDepositStr()).multiply(new BigDecimal(100)).longValue());
        } else {
            record.setDeposit(0L);
        }

        Date date = new Date();
        record.setCreatetime(date);
        record.setUpdatetime(date);

        List<Long> shopList = Lists.newArrayList();
        if (record.getRentShopType().equals(EnumRentShopType.SHOP.getCode())) {
            String rentInfo = record.getRentInfo();
            JSONArray rentInfoArray = JSONArray.parseArray(rentInfo);
            int size = rentInfoArray.size();
            if (size == 0) {
                return new ResultData(ErrorCode.SHOP_NOT_SELECTED);
            }
            //查询rent_info 包括 shopId
            for (int i = 0; i < size; i++) {
                JSONObject rentInfoObject = rentInfoArray.getJSONObject(i);
                WxRentContract wxRentContract = new WxRentContract();
                wxRentContract.setTenantId(record.getTenantId());
                Long shopId = rentInfoObject.getLong("shopId");
                wxRentContract.setShopId(shopId);
                int count = wxRentContractMapper.selectRentContractCountByShopId(wxRentContract);
                String shopNumber = rentInfoObject.getString("shopNumber");
                if (count > 0) {
                    return new ResultData(ErrorCode.SHOP_IS_RENT.getCode(), "店铺 " + shopNumber + " 已出租");
                }
                if (record.getMerchantId() != null) {
                    WxMerchantShop wxMerchantShop = new WxMerchantShop();
                    wxMerchantShop.setShopId(shopId);
                    wxMerchantShop.setIsDel(EnumDelStatus.NOT_DEL.getCode());
                    List<WxMerchantShop> wxMerchantShopList = wxMerchantShopMapper.findList(wxMerchantShop);
                    long total = wxMerchantShopList.parallelStream().
                            filter(ms -> !ms.getMerchantId().equals(record.getMerchantId())).count();
                    if (total > 0) {
                        return new ResultData(ErrorCode.SHOP_IS_RENT.getCode(), "店铺 " + shopNumber + " 已出租");
                    }
                } else {
                    WxShop wxShop = wxShopMapper.selectById(shopId);
                    if (wxShop == null) {
                        return new ResultData(ErrorCode.SHOP_IS_NOT_FOUND.getCode(), "店铺 " + shopNumber + " 已删除");
                    }
                    if (wxShop.getStatus().equals(EnumShopStatus.RENT.getCode())) {
                        return new ResultData(ErrorCode.SHOP_IS_RENT.getCode(), "店铺 " + wxShop.getShopNumber() + " 已出租");
                    }
                }
                shopList.add(shopId);
            }
        } else {
            WxRentContract wxRentContract = new WxRentContract();
            wxRentContract.setTenantId(record.getTenantId());
            wxRentContract.setShopId(record.getShopId());
            long count = wxRentContractMapper.queryRentContractData(wxRentContract).stream().
                    filter(rc -> rc.get("status").equals(EnumRentContractStatus.SIGNED_RENT_UNPAID.getCode())
                            || rc.get("status").equals(EnumRentContractStatus.RENT_PAID.getCode())
                            || rc.get("status").equals(EnumRentContractStatus.CONTRACT_END_SOON.getCode())).count();
            if (count > 0) {
                return new ResultData(ErrorCode.RENT_CONTRACT_WITH_SHOP_IS_FOUND);
            }
            shopList.add(record.getShopId());
        }

        try {
            record.setApplyStatus(EnumRentContractAppStatus.DEFAULT.getCode());

            Date tempDate = record.getRentalStartDate();
            record.setRentalStartDate(oldRentStartDate);
            wxRentContractMapper.insert(record);
            record.setRentalStartDate(tempDate);
        } catch (Exception e) {
            logger.error("保存租赁合同信息失败,e:" + e.getMessage());
            throw new MallinkException(ErrorCode.DB_FAIL.getCode(), "DB FAILD " + e.getMessage());
        }

        //有模板，启动审批流，没有，直接生产账单
        if (!CollectionUtils.isEmpty(record.getFlowParams())){
            if (wxFlowService.getModelByType((Integer) record.getFlowParams().get("businessType"), record.getTenantId()) == null
                    && record.getMerchantId() != null) {
                updateRentContractStatus(record.getId());
            }else{
                record.getFlowParams().put("businessId", record.getId().toString());
                if (record.getMerchantId() != null) {
                    record.getFlowParams().put("supplement", true);  //设置补录
                }
                wxFlowService.start(record.getFlowParams(), userId, userName, record.getTenantId());

                // 合同状态改成待签约
                WxRentContract updateRentContract = new WxRentContract();
                updateRentContract.setId(record.getId());
                updateRentContract.setStatus(EnumRentContractStatus.WAIT_SIGN.getCode());
                wxRentContractMapper.updateStatus(updateRentContract);
                logger.info("id:{},启动审批流成功, 是否补录:{}", record.getId().toString(), record.getMerchantId() != null);
            }
        }else{
            //审批状态重置
            WxRentContract updateRentContract = new WxRentContract();
            updateRentContract.setId(record.getId());
            updateRentContract.setApplyStatus(EnumRentContractAppStatus.DEFAULT.getCode());
            updateApplyStatus(updateRentContract);
        }

        //生成预览账单（补录第二步，第三步走编辑）
        if (record.getReceivePeriod() != null && record.getLease() != null && record.getPrice() != null
                && !record.getReceivePeriod().equals(0) && !record.getLease().equals(0) && !record.getPrice().equals(0l)) {
            wxBillRentMapper.deletePreviewBill(record);
            //重新生成
            List<WxBillRent> resultList = buildRent(new WxMerchant(), null, record, EnumIsPreview.YES.getCode(),true);
            record.setPreviewBillRentList(resultList);
        }

        EventUtil.publistRentEvent(this, record);
        return new ResultData(Result.SUCCESS, "保存租赁合同信息成功", record);
    }

    @Override
    public List<Long> getShopIds(WxRentContract record) {
        List<Long> shopList = Lists.newArrayList();
        if (record.getRentShopType().equals(EnumRentShopType.SHOP.getCode())) {
            String rentInfo = record.getRentInfo();
            JSONArray rentInfoArray = JSONArray.parseArray(rentInfo);
            int size = rentInfoArray.size();
            //查询rent_info 包括 shopId
            for (int i = 0; i < size; i++) {
                JSONObject rentInfoObject = rentInfoArray.getJSONObject(i);
                WxRentContract wxRentContract = new WxRentContract();
                wxRentContract.setTenantId(record.getTenantId());
                Long shopId = rentInfoObject.getLong("shopId");
                shopList.add(shopId);
            }
        } else {
            WxRentContract wxRentContract = new WxRentContract();
            wxRentContract.setTenantId(record.getTenantId());
            wxRentContract.setShopId(record.getShopId());
            shopList.add(record.getShopId());
        }
        return shopList;
    }

    @Transactional(rollbackFor = {Exception.class})
    @Override
    public ResultData update(WxRentContract record, Long userId,String userName,int from,Date oldRentStartDate) {
        //查询预账单用于展示
        WxBillRent wxBillRent = new WxBillRent();
        wxBillRent.setRentContractId(record.getId());
        wxBillRent.setSortColumns(BaseEntity.SortField.Period_ASC);
        wxBillRent.setIsPreview(EnumIsPreview.YES.getCode());
        List<WxBillRent> resultList = wxBillRentMapper.findList(wxBillRent);

        //更新
        ResultData resultData = getResultDataForUpdate(record, userId,from,oldRentStartDate);
        if (resultData.code != Result.SUCCESS) {
            return resultData;
        }

        if(CollectionUtils.isEmpty(record.getPreviewBillRentList())) {
            if (record.getReceivePeriod() != null && record.getLease() != null
                    && !record.getReceivePeriod().equals(0) && !record.getLease().equals(0)) {
                //删除预账单，重新生成
                wxBillRentMapper.deletePreviewBill(record);
                resultList = buildRent(new WxMerchant(), null, record, EnumIsPreview.YES.getCode(),true);
            }
        }

        //有模板，启动审批流，没有，直接生产账单
        if (!CollectionUtils.isEmpty(record.getFlowParams())) {
            if (wxFlowService.getModelByType((Integer) record.getFlowParams().get("businessType"), record.getTenantId()) == null
                    && record.getMerchantId() != null) {
                updateRentContractStatus(record.getId());
            }else{
                //补录
                record.getFlowParams().put("businessId", record.getId().toString());
                if (record.getMerchantId() != null) {
                    record.getFlowParams().put("supplement", true);  //设置补录
                }
                wxFlowService.start(record.getFlowParams(), userId, userName, record.getTenantId());

                //合同状态改成补录状态
                WxRentContract updateRentContract = new WxRentContract();
                updateRentContract.setId(record.getId());
                updateRentContract.setStatus(EnumRentContractStatus.SUPPLE.getCode());
                wxRentContractMapper.updateStatus(updateRentContract);
                logger.info("id:{},启动审批流成功 ,是否补录:{}", record.getId().toString(), record.getMerchantId() != null);
            }
        }else{
            //审批状态重置
            WxRentContract updateRentContract = new WxRentContract();
            updateRentContract.setId(record.getId());
            updateRentContract.setApplyStatus(EnumRentContractAppStatus.DEFAULT.getCode());
            updateApplyStatus(updateRentContract);
        }

        //保存调整金额（预账单调整）
        savePreviewBill(record);

        WxRentContract wxRentContract = (WxRentContract)resultData.data;
        wxRentContract.setPreviewBillRentList(resultList);
        return new ResultData(wxRentContract);
    }

    /**
     * 重新生成账单（预账单调整）
     */
    public void savePreviewBill(WxRentContract record){
        if(CollectionUtils.isEmpty(record.getPreviewBillRentList())){
            return;
        }
        wxBillRentMapper.deletePreviewBill(record);
        final IdWorker idWorker = IdWorker.get();
        int count = 1;
        for (WxBillRent bill:record.getPreviewBillRentList()) {
            bill.setId(idWorker.nextId());
            Date date = new Date();
            bill.setRentContractId(record.getId());
            bill.setCreatetime(date);
            bill.setTenantId(record.getTenantId());
            bill.setOwe(bill.getReceivePay());
            bill.setNeedPay(bill.getNeedPay());
            bill.setUpdatetime(date);
            bill.setRentShopType(record.getRentShopType());
            bill.setPeriod(count);
            bill.setIsPreview(EnumIsPreview.YES.getCode());
            bill.setShopInfo(getShopInfoStr(record));
            bill.setRevenue(0L);
            bill.setLatePayRatio(0);
            bill.setPay(0L);
            bill.setIsDel(EnumDelStatus.NOT_DEL.getCode());
            bill.setShopId(record.getShopId());
            setExpiredDay(bill,Calendar.MONTH,record.getReceivePeriod());
            if (bill.getReceivePay().equals(0L)) {
                bill.setStatus(EnumBillRentStatus.PAID.getCode());
                bill.setPayDate(date);
            }
            count++;
        }
        wxBillRentMapper.insertBills(record.getPreviewBillRentList());
    }

    public ResultData getResultDataForUpdate(WxRentContract record, Long userId,int from,Date oldRentStartDate) {
        //更新租赁合同信息
        WxRentContract wxRentContract = wxRentContractMapper.selectById(record.getId());
        if (wxRentContract == null) {
            return new ResultData(ErrorCode.RENT_CONTRACT_IS_NOT_FOUND);
        }
        wxRentContract.setBusDiscountTime(record.getBusDiscountTime());
        wxRentContract.setBusDiscountRatio(record.getBusDiscountRatio());
        wxRentContract.setPayRatio(record.getPayRatio());

        int dayType = wxRentContract.getAdjustPeriod().equals(EnumRentContractAdjustPeriod.ADJUST_PERIOD_DAY.getCode()) ? Calendar.DAY_OF_MONTH : Calendar.MONTH;

        Calendar instance = Calendar.getInstance();
        instance.setTime(record.getRentalStartDate());
        instance.add(dayType, record.getLease());
        instance.add(Calendar.DAY_OF_MONTH, -1);

        if(!EnumFromType.SWITCH.getCode().equals(from)){
            if (record.getType().equals(EnumRentContractType.RENT_BY_JOINT.getCode())) {
                if(record.getPayRatio()!=null && record.getPayRatio().intValue() > 0){
                    record.setPrice(countPrice(record.getPayRatio(),record.getRevenue(),EnumMissTimeType.OTHER.getCode(),record.getAdjustPeriod(),from));
                }else{
                    int dayCount = record.getReceivePeriod() * 30;
                    RatioVo ratioVo = getPayRatio(EnumGetRatioFrom.RENT.getCode(),record.getRevenue(),record.getBusDiscountRatio(),record.getBusDiscountTime(),dayCount,record.getReceivePeriod());
                    //record.setPayRatio(ratioVo.getRatio());
                    record.setPrice(ratioVo.getPrice());
                }
            } else {
                if (StringUtils.isNotEmpty(record.getPriceStr())) {
                    record.setPrice(new BigDecimal(record.getPriceStr()).multiply(new BigDecimal(100)).longValue());
                } else {
                    record.setPrice(0L);
                }
            }
        }

        if (StringUtils.isNotEmpty(record.getDepositStr())) {
            record.setDeposit(new BigDecimal(record.getDepositStr()).multiply(new BigDecimal(100)).longValue());
        } else {
            record.setDeposit(0L);
        }

        record.setUpdatetime(new Date());

        if (record.getRentShopType().equals(EnumRentShopType.SHOP.getCode())) {
            String rentInfo = record.getRentInfo();
            JSONArray rentInfoArray = JSONArray.parseArray(rentInfo);
            int size = rentInfoArray.size();
            if (size == 0) {
                return new ResultData(ErrorCode.SHOP_NOT_SELECTED);
            }
            //查询rent_info 包括 shopId
            for (int i = 0; i < size; i++) {
                JSONObject rentInfoObject = rentInfoArray.getJSONObject(i);
                WxRentContract wxRentContractQuery = new WxRentContract();
                wxRentContractQuery.setTenantId(record.getTenantId());
                Long shopId = rentInfoObject.getLong("shopId");
                String shopNumber = rentInfoObject.getString("shopNumber");
                if (shopId == null) {
                    return new ResultData(ErrorCode.SHOP_IS_NOT_FOUND.getCode(), "店铺 " + shopNumber + " 已删除");
                }
                wxRentContractQuery.setShopId(shopId);
                wxRentContractQuery.setId(record.getId());
                int count = wxRentContractMapper.selectRentContractCountByShopId(wxRentContractQuery);
                if (count > 0) {
                    return new ResultData(ErrorCode.SHOP_IS_RENT.getCode(), "店铺 " + shopNumber + " 已出租");
                }
                if (record.getMerchantId() != null) {
                    WxMerchantShop wxMerchantShop = new WxMerchantShop();
                    wxMerchantShop.setShopId(shopId);
                    wxMerchantShop.setIsDel(EnumDelStatus.NOT_DEL.getCode());
                    List<WxMerchantShop> wxMerchantShopList = wxMerchantShopMapper.findList(wxMerchantShop);
                    long total = wxMerchantShopList.parallelStream().
                            filter(ms -> !ms.getMerchantId().equals(record.getMerchantId())).count();
                    if (total > 0) {
                        return new ResultData(ErrorCode.SHOP_IS_RENT.getCode(), "店铺 " + shopNumber + " 已出租");
                    }
                } else {
                    WxShop wxShop = wxShopMapper.selectById(shopId);
                    if (wxShop == null) {
                        return new ResultData(ErrorCode.SHOP_IS_NOT_FOUND.getCode(), "店铺 " + shopNumber + " 已删除");
                    }
                    if (wxShop.getStatus().equals(EnumShopStatus.RENT.getCode())) {
                        return new ResultData(ErrorCode.SHOP_IS_RENT.getCode(), "店铺 " + wxShop.getShopNumber() + " 已出租");
                    }
                }
            }
        } else {
            WxRentContract wxRentContractQuery = new WxRentContract();
            wxRentContractQuery.setTenantId(record.getTenantId());
            wxRentContractQuery.setShopId(record.getShopId());
            long count = wxRentContractMapper.queryRentContractData(wxRentContract).stream().
                    filter(rc -> rc.get("status").equals(EnumRentContractStatus.SIGNED_RENT_UNPAID.getCode())
                            || rc.get("status").equals(EnumRentContractStatus.RENT_PAID.getCode())
                            || rc.get("status").equals(EnumRentContractStatus.CONTRACT_END_SOON.getCode())).count();
            if (count > 0) {
                return new ResultData(ErrorCode.RENT_CONTRACT_WITH_SHOP_IS_FOUND);
            }
        }

        try {
            Date tempDate = record.getRentalStartDate();
            record.setRentalStartDate(oldRentStartDate);
            wxRentContractMapper.updateById(record);
            record.setRentalStartDate(tempDate);
        } catch (Exception e) {
            logger.error("更新租赁合同信息失败,e:" + e.getMessage());
            throw new MallinkException(ErrorCode.DB_FAIL.getCode(), "DB FAILD " + e.getMessage());
        }
        return new ResultData(Result.SUCCESS, "保存租赁合同信息成功", wxRentContract);
    }


    @Transactional(rollbackFor = {Exception.class})
    @Override
    public void buildDeposit(WxMerchant wxMerchant, Long userId,Long rentContractId) {
        WxRentContract wxRentContract = wxRentContractMapper.selectById(rentContractId);
        if (wxRentContract != null && wxRentContract.getDeposit() > 0) {
            final IdWorker idWorker = IdWorker.get();
            WxBillDeposit wxBillDeposit = new WxBillDeposit();
            wxBillDeposit.setId(idWorker.nextId());
            wxBillDeposit.setRentContractId(wxRentContract.getId());
            wxBillDeposit.setPay(0L);
            long needpay = wxRentContract.getDeposit();
            wxBillDeposit.setReceivePay(needpay);
            wxBillDeposit.setNeedPay(needpay);
            wxBillDeposit.setOwe(needpay);
            //找到计租方式
            int dayType = wxRentContract.getAdjustPeriod().equals(EnumRentContractAdjustPeriod.ADJUST_PERIOD_DAY.getCode()) ? Calendar.DAY_OF_MONTH : Calendar.MONTH;

            Date date = new Date();
            Calendar instance = Calendar.getInstance();
            instance.setTime(wxRentContract.getRentalStartDate());
            instance.add(Calendar.DAY_OF_MONTH, -1);
            Date time = instance.getTime();
            wxBillDeposit.setReceiveDate(time);

            //账单开始时间
            instance.clear();
            instance.setTime(wxBillDeposit.getReceiveDate());
            instance.add(Calendar.DAY_OF_MONTH, 1);
            wxBillDeposit.setStarttime(instance.getTime());
            //账单结束时间
            instance.clear();
            instance.setTime(wxBillDeposit.getReceiveDate());
            instance.add(dayType, wxRentContract.getLease());
            wxBillDeposit.setEndtime(instance.getTime());
            wxBillDeposit.setStatus(EnumBillRentStatus.WAIT_PAY.getCode());
            wxBillDeposit.setExpiredDay(0L);
            wxBillDeposit.setReceiveDate(time);
            wxBillDeposit.setTenantId(wxMerchant.getTenantId());
            wxBillDeposit.setIsDel(0);
            wxBillDeposit.setMerchantId(wxMerchant.getId());
            wxBillDeposit.setUserId(userId);
            wxBillDeposit.setShopId(wxRentContract.getShopId());
            wxBillDeposit.setCreatetime(date);
            wxBillDeposit.setUpdatetime(date);
            wxBillDeposit.setIsDel(EnumDelStatus.NOT_DEL.getCode());
            wxBillDeposit.setRentShopType(wxRentContract.getRentShopType());
            if (wxRentContract.getRentShopType().equals(EnumRentShopType.SHOP.getCode())) {
                String rentInfo = wxRentContract.getRentInfo();
                if (rentInfo != null) {
                    JSONArray rentInfoArray = JSONArray.parseArray(rentInfo);
                    Map<String, Object> shopInfo = new HashMap<>();
                    for (int i = 0, size = rentInfoArray.size(); i < size; i++) {
                        JSONObject rentInfoObject = rentInfoArray.getJSONObject(i);
                        shopInfo.put(rentInfoObject.getString("shopNumber"), rentInfoObject.get("deposit"));
                    }
                    wxBillDeposit.setShopInfo(JSONObject.toJSONString(shopInfo));
                }
            }
            try {
                wxBillDepositMapper.insert(wxBillDeposit);
            } catch (Exception e) {
                logger.error("添加押金账单失败,e:" + e.getMessage());
                throw new MallinkException(ErrorCode.DB_FAIL.getCode(), "DB FAILD " + e.getMessage());
            }
        }
    }

    @Override
    public Object getMerchants(WxRentContract wxRentContract) {
        List<WxRentContract> rentContractList = wxRentContractMapper.getMerchants(wxRentContract);
        return rentContractList;
    }

    @Override
    public void updateInvalidContract(Long rentContractId) {
        WxRentContract wxRentContract = wxRentContractMapper.selectById(rentContractId);
        if (wxRentContract.getRentShopType().equals(EnumRentShopType.SHOP.getCode())) {
            String rentInfo = wxRentContract.getRentInfo();
            JSONArray rentInfoArray = JSONArray.parseArray(rentInfo);
            WxRentContract record = new WxRentContract();
            for (int i = 0, size = rentInfoArray.size(); i < size; i++) {
                JSONObject rentInfoObject = rentInfoArray.getJSONObject(i);
                Long shopId = rentInfoObject.getLong("shopId");
                record.setShopId(shopId);
                record.setTenantId(wxRentContract.getTenantId());
                record.setStatus(EnumRentContractStatus.INVALID.getCode());
                wxRentContractMapper.updateInvalidContract(record);
                List<WxRentContract> rentContractList = wxRentContractMapper.selectRentContractByShopId(record);
                for (WxRentContract updateContract : rentContractList) {
                    updateInvalidStatus(updateContract);
                }
            }
        } else {
            WxRentContract record = new WxRentContract();
            record.setTenantId(wxRentContract.getTenantId());
            record.setRentShopType(wxRentContract.getRentShopType());
            record.setStatus(EnumRentContractStatus.INVALID.getCode());
            wxRentContractMapper.updateRentInvalidStatus(record);
            List<WxRentContract> rentContractList = wxRentContractMapper.selectList(new QueryWrapper(record));
            for (WxRentContract updateContract : rentContractList) {
                updateInvalidStatus(updateContract);
            }
        }

    }

    @Override
    public ResultData hasRentStatus(WxRentContract record) {
        String rentInfo = record.getRentInfo();
        if (StringUtils.isEmpty(rentInfo)) {
            return new ResultData(ErrorCode.SHOP_NOT_SELECTED);
        }
        String[] split = rentInfo.split(",");
        int size = split.length;
        //查询rent_info 包括 shopId
        for (int i = 0; i < size; i++) {
            String shopId = split[i];
            WxShop wxShop = wxShopMapper.selectById(shopId);
            WxRentContract wxRentContractQuery = new WxRentContract();
            wxRentContractQuery.setTenantId(record.getTenantId());
            String shopNumber = wxShop.getShopNumber();
            if (shopId == null) {
                return new ResultData(ErrorCode.SHOP_IS_NOT_FOUND.getCode(), "店铺 " + shopNumber + " 已删除");
            }
            wxRentContractQuery.setShopId(Long.valueOf(shopId));
            int count = wxRentContractMapper.selectRentContractCountByShopId(wxRentContractQuery);
            if (count > 0) {
                return new ResultData(ErrorCode.SHOP_IS_RENT.getCode(), "店铺 " + shopNumber + " 已出租");
            }
        }
        return new ResultData(Result.SUCCESS, "操作成功");
    }

    @Override
    public ResultData hasContractNumber(WxRentContract wxRentContract) {
        int count = wxRentContractMapper.hasContractNumber(wxRentContract);
        return new ResultData(Result.SUCCESS, "操作成功", count > 0 ? true : false);
    }

    public void updateInvalidStatus(WxRentContract record) {
        Long id = record.getId();
        //审核流程中止
        try {
            // 修改合同审核状态
            WxRentContract rentContract = record;
            rentContract.setId(id);
            rentContract.setApplyStatus(EnumRentContractAppStatus.CANCLE.getCode());
            updateApplyStatus(rentContract);

            //修改flowRecord
            WxFlowRecord fr = new WxFlowRecord();
            fr.setBusinessId(id);
            fr.setCurrStatus(EnumRentContractAppStatus.CANCLE.getCode());
            wxFlowRecordMapper.updateCurrStatus(fr);

            logger.info("合同id:{},开始停止...", id);
            //结束审批流 by luozukai
            WxFlowModel flowModel = wxFlowService.getModelByType(EnumFlowKey.NEW_RENT_CONTRACT.getCode().intValue(),record.getTenantId());
            WxFlowModel flowModelPoint = wxFlowService.getModelByType(EnumFlowKey.NEW_SHOP_CONTRACT.getCode().intValue(),record.getTenantId());

            WxFlowModel flowModel_pro = wxFlowService.getModelByType(EnumFlowKey.NEW_PRO_CONTRACT.getCode().intValue(),record.getTenantId());
            WxFlowModel flowModelPoint_pro = wxFlowService.getModelByType(EnumFlowKey.NEW_PRO_POINT_CONTRACT.getCode().intValue(),record.getTenantId());

            WxFlowModel flowModel_rent = wxFlowService.getModelByType(EnumFlowKey.NNEW_RENT_CONTRACT.getCode().intValue(),record.getTenantId());
            WxFlowModel flowModelPoint_rent = wxFlowService.getModelByType(EnumFlowKey.NEW_RENT_POINT_CONTRACT.getCode().intValue(),record.getTenantId());

            List<String> keyList = new ArrayList<>();
            if(flowModel != null){
                keyList.add(flowModel.getFlowId());
            }
            if(flowModelPoint != null){
                keyList.add(flowModelPoint.getFlowId());
            }
            if(flowModel_pro != null){
                keyList.add(flowModel_pro.getFlowId());
            }
            if(flowModelPoint_pro != null){
                keyList.add(flowModelPoint_pro.getFlowId());
            }
            if(flowModel_rent != null){
                keyList.add(flowModel_rent.getFlowId());
            }
            if(flowModelPoint_rent != null){
                keyList.add(flowModelPoint_rent.getFlowId());
            }
            keyList.add(EnumFlowKey.CONTRACT.getMessage());
            List<Task> tasks = taskService.createTaskQuery()
                    .processDefinitionKeyIn(keyList)
                    .processVariableValueEquals("businessId", id+"").list();
            if (!CollectionUtils.isEmpty(tasks)) {
                for (Task task : tasks) {
                    logger.info("合同id:{},taskid:{}", id, task.getId());
                    runtimeService.deleteProcessInstance(task.getProcessInstanceId(), "合同作废");

                    // 保存审批历史入
                    MallUserInfo mallUserInfo = (MallUserInfo) SecurityUtils.getSubject().getSession().getAttribute("userSession");
                    WxFlowRecord updateRecord = new WxFlowRecord();
                    updateRecord.setBusinessId(id);
                    updateRecord.setStatus(EnumFlowRecordStatus.CANCLE.getCode());
                    updateRecord.setBusinessType(1);
                    updateRecord.setUserId(mallUserInfo.getId());
                    updateRecord.setProcessInstanceId(task.getProcessInstanceId());
                    wxFlowRecordService.saveOrUpdate(updateRecord);
                }
            }

        } catch (Exception e) {
            logger.error("deleteProcessInstance error", e);
        }
    }

    @Override
    @Transactional(rollbackFor = {Exception.class})
    public List<WxBillRent> buildRent(WxMerchant wxMerchant, Long userId,WxRentContract rentContract,Integer isPreview,boolean saveDb) {
        List<WxBillRent> rentList = new ArrayList<>();
        //根据商户ID找出合同
        WxRentContract wxRentContract;
        if(rentContract == null){
            wxRentContract = new WxRentContract();
            wxRentContract.setMerchantId(wxMerchant.getId());
            List<WxRentContract> list = wxRentContractMapper.findList(wxRentContract);
            if (list.size() > 0) {
                wxRentContract = list.get(0);
            }
        }else{
            wxRentContract = rentContract;
        }
        if (wxRentContract != null) {
            int receivePeriod = wxRentContract.getReceivePeriod().intValue();
            Integer lease = wxRentContract.getLease();

            Date rentalStartDate = wxRentContract.getRentalStartDate();
            Long price = wxRentContract.getPrice();

            //按月计租
//            if (wxRentContract.getAdjustPeriod().equals(EnumRentContractAdjustPeriod.ADJUST_PERIOD_MONTH.getCode())
//                    ||wxRentContract.getAdjustPeriod().equals(EnumRentContractAdjustPeriod.ADJUST_PERIOD_NAR_MONTH.getCode())) {
            rentList = buildRentMonth(userId, wxRentContract, receivePeriod, lease, rentalStartDate, price, isPreview,saveDb);
//            } else {
//                //如果按日
//                List<Date> yearList = new ArrayList<>();
//                yearList.add(rentalStartDate);
//                Map<String, Object> resultMap = buildRent(receivePeriod, new long[]{price}, yearList, Calendar.DAY_OF_MONTH, wxRentContract, userId, wxMerchant, 0, isPreview,null);
//                rentList = ( List<WxBillRent>)resultMap.get("billList");
//            }
        }
        for (int i = 0; i < rentList.size(); i++) {
            rentList.get(i).setPeriod(i+1);
        }
        return rentList;
    }

    //计算租金,每年-每个店铺租金
    public List<long[]> computePrice(String rentInfo, WxRentContract wxRentContract) {

        JSONArray rentInfoArray = JSONArray.parseArray(rentInfo);
        int arraySize = rentInfoArray.size();
        List<long[]> priceList = new ArrayList<>();
        //第一年
        long[] priceArr = new long[arraySize];
        for (int i = 0; i < arraySize; i++) {
            JSONObject rentInfoObject = rentInfoArray.getJSONObject(i);
            String priceStr = rentInfoObject.getString("price");
            if (priceStr.equalsIgnoreCase("NaN")) {
                priceStr = "0";
            }
            priceArr[i] = new BigDecimal(priceStr).multiply(new BigDecimal(100)).longValue();
        }
        priceList.add(priceArr);
        //大于一年
        JSONObject rentInfoObject = rentInfoArray.getJSONObject(0);
        JSONArray adjustRatio = rentInfoObject.getJSONArray("adjustRatio");
        int adjustRatioSize = adjustRatio.size();
        //判断年租金调整方式
        if (wxRentContract.getAdjustRatioWay().equals(EnumRentContractAdjustRatioWay.RATIO.getCode())) {
            for (int i = 0; i < adjustRatioSize; i++) {
                long[] priceArrs = new long[arraySize];
                for (int j = 0; j < arraySize; j++) {
                    rentInfoObject = rentInfoArray.getJSONObject(j);
                    adjustRatio = rentInfoObject.getJSONArray("adjustRatio");
                    BigDecimal multiply = new BigDecimal(priceList.get(i)[j]).multiply(new BigDecimal(adjustRatio.getString(i)).divide(new BigDecimal(100)));
                    BigDecimal price = new BigDecimal(priceList.get(i)[j]).add(multiply);
                    priceArrs[j] = price.setScale(0, RoundingMode.HALF_EVEN).longValue();
                }
                priceList.add(priceArrs);
            }
            return priceList;
        }
        if (wxRentContract.getAdjustRatioWay().equals(EnumRentContractAdjustRatioWay.MONEY.getCode())) {
            for (int i = 0; i < adjustRatioSize; i++) {
                long[] priceArrs = new long[arraySize];
                for (int j = 0; j < arraySize; j++) {
                    rentInfoObject = rentInfoArray.getJSONObject(j);
                    adjustRatio = rentInfoObject.getJSONArray("adjustRatio");
                    BigDecimal price = new BigDecimal(priceList.get(i)[j]).add(new BigDecimal(adjustRatio.getString(i)).multiply(new BigDecimal(100)));
                    priceArrs[j] = price.setScale(0, RoundingMode.HALF_EVEN).longValue();
                }
                priceList.add(priceArrs);
            }
            return priceList;
        }
        if (wxRentContract.getAdjustRatioWay().equals(EnumRentContractAdjustRatioWay.CUSTOM.getCode())) {
            for (int i = 0; i < adjustRatioSize; i++) {
                long[] priceArrs = new long[arraySize];
                for (int j = 0; j < arraySize; j++) {
                    rentInfoObject = rentInfoArray.getJSONObject(j);
                    adjustRatio = rentInfoObject.getJSONArray("adjustRatio");
                    BigDecimal price = new BigDecimal(adjustRatio.getString(i)).multiply(new BigDecimal(100));
                    priceArrs[j] = price.setScale(0, RoundingMode.HALF_EVEN).longValue();
                }
                priceList.add(priceArrs);
            }
        }
        return priceList;
    }

    public List<WxBillRent> buildRentMonth(Long userId, WxRentContract wxRentContract, int receivePeriod, Integer lease, Date rentalStartDate, Long price, Integer isPreview, boolean saveDb) {
        int size = 0;
        long[] priceArrs = null;
        List<Map<String, Object>> shopInfos = new ArrayList<>();
        if (wxRentContract.getRentShopType().equals(EnumRentShopType.SHOP.getCode()) &&
                wxRentContract.getRentInputWay().equals(EnumRentContractRentInputWay.PART.getCode()) &&
                !wxRentContract.getType().equals(EnumRentContractType.RENT_BY_JOINT.getCode())) {
            String rentInfo = wxRentContract.getRentInfo();
            JSONArray rentInfoArray = JSONArray.parseArray(rentInfo);
            List<long[]> priceList = computePrice(rentInfo, wxRentContract);
            size = priceList.size();
            priceArrs = new long[size];
            for (int i = 0; i < size; i++) {
                long[] priceInt = priceList.get(i);
                long sum = 0;
                for (long p : priceInt) {
                    sum += p;
                }
                priceArrs[i] = sum;
            }

            for (int i = 0; i < size; i++) {
                Map<String, Object> shopInfo = new HashMap<>();
                long[] ints = priceList.get(i);
                for (int j = 0; j < ints.length; j++) {
                    JSONObject rentInfoObject = rentInfoArray.getJSONObject(j);
                    String s = new BigDecimal(ints[j]).divide(new BigDecimal(100)).toPlainString();
                    shopInfo.put(rentInfoObject.getString("shopNumber"), s);
                }
                shopInfos.add(shopInfo);
            }
        } else {
            String adjustRatio = wxRentContract.getAdjustRatio();
            List<Integer> integers = JSONArray.parseArray(adjustRatio, Integer.class);
            integers.add(0, 0);
            size = integers.size();
            priceArrs = new long[size];
            priceArrs[0] = price;
            BigDecimal priceD = new BigDecimal(price);
            if (wxRentContract.getAdjustRatioWay().equals(EnumRentContractAdjustRatioWay.RATIO.getCode())) {
                for (int i = 1; i < size; i++) {
                    BigDecimal divide = priceD.multiply(new BigDecimal(integers.get(i))).divide(new BigDecimal(10000));
                    priceD = priceD.add(divide);
                    priceArrs[i] = priceD.setScale(0, RoundingMode.HALF_EVEN).longValue();
                }
            } else if (wxRentContract.getAdjustRatioWay().equals(EnumRentContractAdjustRatioWay.MONEY.getCode())) {
                for (int i = 1; i < size; i++) {
                    priceD = priceD.add(new BigDecimal(integers.get(i)));
                    priceArrs[i] = priceD.setScale(0, RoundingMode.HALF_EVEN).longValue();
                }
            } else {
                for (int i = 1; i < size; i++) {
                    if (wxRentContract.getType().equals(EnumRentContractType.RENT_BY_JOINT.getCode())) {
                        if (EnumMissTimeType.YEAR.getCode().equals(wxRentContract.getBusDiscountTime())) {
                            priceArrs[i] = new BigDecimal(integers.get(i)).multiply(new BigDecimal(12)).setScale(0, RoundingMode.HALF_EVEN).longValue();
                            continue;
                        }
                        if (EnumMissTimeType.PERIOD.getCode().equals(wxRentContract.getBusDiscountTime())) {
                            priceArrs[i] = new BigDecimal(integers.get(i)).multiply(new BigDecimal(wxRentContract.getReceivePeriod())).setScale(0, RoundingMode.HALF_EVEN).longValue();
                            continue;
                        }
                    }
                    priceArrs[i] = new BigDecimal(integers.get(i)).setScale(0, RoundingMode.HALF_EVEN).longValue();
                }
            }
        }

        int month = 12;
        int divide = lease / month;
        int mod = lease % month;
        int[] leaseArr = new int[size];
        for (int i = 0; i < divide; i++) {
            leaseArr[i] = month;
        }
        if (mod > 0) {
            leaseArr[divide] = mod;
        }

        int billcount = 0;
        List<WxBillRent> resultList = new ArrayList<>();

        List<Date> yearList = new ArrayList<>();
        for (int i = 0; i < size; i++) {
            Calendar instance = Calendar.getInstance();
            Date startDate;
            //自然月
            if(wxRentContract.getAdjustPeriod().equals(EnumRentContractAdjustPeriod.ADJUST_PERIOD_NAR_MONTH.getCode())){
                if(i == 0){ //第一期
                    startDate = rentalStartDate;
                }else{
                    instance.setTime(rentalStartDate);
                    instance.add(Calendar.MONTH, month * i);
                    startDate = DateUtils.getFirstDayForCurrMonth(instance.getTime());
                }
            }else{
                instance.setTime(rentalStartDate);
                instance.add(Calendar.MONTH, month * i);
                startDate = instance.getTime();
            }
            yearList.add(startDate);
        }

        String shopInfoStr = getShopInfoStr(wxRentContract);
        Map<String, Object> resultMap = buildRent(receivePeriod, priceArrs, yearList, Calendar.MONTH, wxRentContract, userId, billcount, isPreview, shopInfoStr,saveDb);
        List<WxBillRent> billRentList = (List<WxBillRent>)resultMap.get("billList");
        resultList.addAll(billRentList);
        return resultList;
    }

    public String getShopInfoStr(WxRentContract wxRentContract){
        String shopInfoStr = null;
        if (wxRentContract.getRentShopType().equals(EnumRentShopType.SHOP.getCode())) {
            String rentInfo = wxRentContract.getRentInfo();
            JSONArray rentInfoArray = JSONArray.parseArray(rentInfo);
            int rentSize = rentInfoArray.size();
            Map<String, Object> shopInfoMap = new HashMap<>(rentSize);
            for (int j = 0; j < rentSize; j++) {
                JSONObject rentInfoObject = rentInfoArray.getJSONObject(j);
                shopInfoMap.put(rentInfoObject.getString("shopNumber"), rentInfoObject.getString("buildArea"));
            }
            shopInfoStr = JSONObject.toJSONString(shopInfoMap);
        }
        return shopInfoStr;
    }


    public Map<String, Object> buildRent(int receivePeriod, long[] priceArrs, List<Date> yearList, int dayType, WxRentContract wxRentContract, Long userId, int billcount, Integer isPreview, String shopInfoStr,boolean saveDb) {
        WxPayAccountBill wxPayAccountBill = wxPayAccountBillService.getByTenantId(wxRentContract.getTenantId());
        SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd");
        Map<String,Object> resultMap = new HashedMap();
        List<WxBillRent> resultList = new ArrayList<>();
        final IdWorker idWorker = IdWorker.get();

        Date endDate = null;//每年的截止日期
        if(yearList.size() > 1){
            endDate = yearList.get(1);
        }

        List<BillTimeVo> billTimeVoList = new ArrayList<>();
        if(saveDb){
            billTimeVoList = initBillTimeList(wxRentContract.getRentalStartDate(),wxRentContract.getRentalEndDate(),wxRentContract.getAdjustPeriod(),dayType,receivePeriod);
        }else{
            //预账单编辑账期，生成金额
            for (WxBillRent rent:wxRentContract.getPreviewBillRentList()) {
                BillTimeVo billTimeVo = new BillTimeVo();
                billTimeVo.setStartDate(rent.getStarttime());
                billTimeVo.setEndDate(rent.getEndtime());
                billTimeVo.setReceiveDate(DateUtils.getDaySet(rent.getStarttime(),Calendar.DATE,-1));
                billTimeVoList.add(billTimeVo);
            }
        }

        int index = 0;
        for (int i = 0; i < billTimeVoList.size(); i++) {
            BillTimeVo billTimeVo =  billTimeVoList.get(i);
            //计算金额
            long needpay = 0;

            boolean flag = false;
            if(yearList.size() > 1) {
                if (endDate!=null && (sd.format(billTimeVo.getStartDate()).equals(sd.format(endDate)) || billTimeVo.getStartDate().after(endDate) || billTimeVo.getEndDate().after(endDate) )) {
                    if(yearList.size() > 1) {
                        if (endDate!=null && (sd.format(billTimeVo.getStartDate()).equals(sd.format(endDate)) || billTimeVo.getStartDate().after(endDate) || billTimeVo.getEndDate().after(endDate) )) {
                            //logger.info("=====billTimeVo.getStartDate():"+sd.format(billTimeVo.getStartDate())+" endDate:"+sd.format(endDate));

                            index++;

                            //如果是计算账单金额&cross 拆分日期进行计算
                            if(billTimeVo.getEndDate().after(endDate)) {
                                long needpayFront = 0;
                                long needpayAfter = 0;
                                //同一天，算一天
                                if(sd.format(billTimeVo.getStartDate()).equals(sd.format(billTimeVo.getEndDate()))){
                                    needpayFront = getNeedPayMoney(wxRentContract,priceArrs[index-1],billTimeVo.getStartDate(),endDate,i,billTimeVoList.size(),saveDb,dayType,receivePeriod,false);
                                }else{
                                    if(billTimeVo.getStartDate().before(endDate)){
                                        if (EnumRentContractType.RENT_BY_JOINT.getCode().equals(wxRentContract.getType()) && EnumMissTimeType.PERIOD.getCode().equals(wxRentContract.getBusDiscountTime())) {
                                            //设置跳点率为年周期 price不变
                                            needpayFront = priceArrs[index - 1];
                                        }else {
                                            needpayFront = getNeedPayMoney(wxRentContract, priceArrs[index - 1], billTimeVo.getStartDate(), DateUtils.getDaySet(endDate, Calendar.DATE, -1), i, billTimeVoList.size(), saveDb, dayType, receivePeriod,true);
                                            needpayAfter = getNeedPayMoney(wxRentContract, priceArrs[index], endDate, billTimeVo.getEndDate(), i, billTimeVoList.size(), saveDb, dayType, receivePeriod,true);
                                        }
                                    }else{
                                        needpayFront = getNeedPayMoney(wxRentContract, priceArrs[index], billTimeVo.getStartDate(), billTimeVo.getEndDate(), i, billTimeVoList.size(), saveDb,dayType,receivePeriod,false);
                                    }
                                }
                                needpay = needpayFront+needpayAfter;
                                flag = true;
                            }
                            if(index >= yearList.size()-1){
                                endDate = null;
                            }else{
                                endDate = yearList.get(index+1);//price index 0开始，year.end 从第二年开始
                                //logger.info("==========cross:"+sd.format(endDate));
                            }
                        }
                    }
                }
            }

            //计算金额
            if(!flag){
                needpay = getNeedPayMoney(wxRentContract, priceArrs[index], billTimeVo.getStartDate(), billTimeVo.getEndDate(), i, billTimeVoList.size(),saveDb,dayType,receivePeriod,false);
            }

            WxBillRent wxBillRent = new WxBillRent();
            wxBillRent.setIsPreview(isPreview);
            wxBillRent.setId(idWorker.nextId());
            wxBillRent.setRentContractId(wxRentContract.getId());
            wxBillRent.setPay(0L);
            wxBillRent.setStarttime(billTimeVo.getStartDate());
            wxBillRent.setEndtime(billTimeVo.getEndDate());
            wxBillRent.setReceiveDate(billTimeVo.getReceiveDate());

            wxBillRent.setNeedPay(needpay);
            wxBillRent.setOwe(needpay);
            wxBillRent.setReceivePay(needpay);

            //截止收租日在当前时间之前
            Date date = new Date();
            setExpiredDay(wxBillRent,dayType,receivePeriod);
            wxBillRent.setRevenue(0L);
            wxBillRent.setTenantId(wxRentContract.getTenantId());
            wxBillRent.setIsDel(0);
            wxBillRent.setMerchantId(wxRentContract.getMerchantId());
            wxBillRent.setUserId(userId);
            wxBillRent.setShopId(wxRentContract.getShopId());
            wxBillRent.setCreatetime(date);
            wxBillRent.setUpdatetime(date);
            wxBillRent.setIsDel(EnumDelStatus.NOT_DEL.getCode());
            wxBillRent.setRentShopType(wxRentContract.getRentShopType());
            wxBillRent.setPeriod(++billcount);
            wxBillRent.setShopInfo(shopInfoStr);
            wxBillRent.setLatePayRatio(0);

            //计算手续费
            BigDecimal servicePay = new BigDecimal(wxBillRent.getReceivePay()).multiply(new BigDecimal(wxPayAccountBill.getServiceChargeRate())).divide(new BigDecimal(10000), 2, BigDecimal.ROUND_HALF_UP);
            wxBillRent.setServiceChargePay(servicePay.intValue());
            resultList.add(wxBillRent);
        }

        //批量插入账单
        if(saveDb) {
            wxBillRentMapper.insertBills(resultList);
        }
        resultMap.put("billcount",billcount);
        resultMap.put("billList",resultList);
        return resultMap;
    }

    public long getNeedPayMoney(WxRentContract wxRentContract,long price,Date startDate,Date endDate,int i,int billTimeVoListSize,boolean saveDb,int dayType,int receivePeriod,boolean part){
        long needpay;
        //按日
        if (wxRentContract.getPriceUnit().equals(EnumPriceUnit.D.getCode())){
            Double priceD = new Double(price);
            double needpayD = WxRentContractServiceImpl.getNeedPay(0,priceD,startDate,endDate);
            needpay = new Double(needpayD).longValue();
        }else{
            Double priceD = new Double(price);
            if (EnumRentContractType.RENT_BY_JOINT.getCode().equals(wxRentContract.getType())) {
                //设置跳点率为年周期 price不变
                if (EnumMissTimeType.PERIOD.getCode().equals(wxRentContract.getBusDiscountTime())) {
                    return priceD.longValue();
                }
                //年或者设置跳点率为年周期 除12
                if (EnumMissTimeType.YEAR.getCode().equals(wxRentContract.getBusDiscountTime())) {
                    priceD = new Double(price) / 12;
                }
            }else{
                //年 除12
                if(EnumPriceUnit.Y.getCode().equals(wxRentContract.getPriceUnit())){
                    priceD = new Double(price)/12;
                }
            }


            //生成金额直接计算
            if(!saveDb){
                needpay = new Double(getMonthNeedPay(priceD, startDate, endDate,dayType,receivePeriod,part)).longValue();
                return needpay;
            }

            SimpleDateFormat sdM = new SimpleDateFormat("yyyy-MM");
            SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd");

            if(i == billTimeVoListSize - 1){//最后
                //判断是否满足整月
                Calendar instance = Calendar.getInstance();
                instance.setTime(startDate);
                instance.add(dayType, receivePeriod);
                instance.add(Calendar.DATE, -1);
                if(sd.format(instance.getTime()).equals(sd.format(endDate))){
                    int months = getMonths(sdM.format(startDate)+"-01",sdM.format(DateUtils.getDaySet(endDate,Calendar.DATE,1))+"-01");
                    needpay = new Double(months * priceD).longValue();
                }else{
                    needpay = new Double(getMonthNeedPay(priceD, startDate, endDate,dayType,receivePeriod,false)).longValue();
                }
            }else if(i == 0){//第一期
                if(wxRentContract.getAdjustPeriod().equals(EnumRentContractAdjustPeriod.ADJUST_PERIOD_NAR_MONTH.getCode())){
                    if(isFirstDay(startDate)){
                        int months = getMonths(sdM.format(startDate)+"-01",sdM.format(endDate)+"-01");
                        months++;
                        needpay = new Double(months * priceD).longValue();
                    }else{
                        needpay = new Double(getMonthNeedPay(priceD, startDate, endDate,dayType,receivePeriod,false)).longValue();
                    }
                }else{
                    if(isFirstDay(startDate)){
                        int months = getMonths(sdM.format(startDate)+"-01",sdM.format(endDate)+"-01");
                        if(isFirstDay(startDate)){
                            months++;
                        }
                        needpay = new Double(months * priceD).longValue();
                    }else{
                        needpay = new Double(getMonthNeedPay(priceD, startDate, endDate,dayType,receivePeriod,false)).longValue();
                    }
                }
            }else{//中间
                int months = getMonths(sdM.format(startDate)+"-01",sdM.format(endDate)+"-01");
                if(isFirstDay(startDate)){
                    months++;
                }
                needpay = new Double(months * priceD).longValue();
            }
        }
        return needpay;
    }

    public void setExpiredDay(WxBillRent wxBillRent,int dayType, int receivePeriod){
        //截止收租日在当前时间之前
        Date date = new Date();
        wxBillRent.setExpiredDay(0L);
        if (wxBillRent.getReceiveDate().before(date)) {
            long day = (date.getTime() - wxBillRent.getReceiveDate().getTime()) / (24 * 60 * 60 * 1000);
            wxBillRent.setStatus(EnumBillRentStatus.NOT_PAID.getCode());
            if (day > 0) {
                wxBillRent.setExpiredDay(day);
            }
        } else {//截止收租日在当前时间之后
            Calendar now = Calendar.getInstance();
            now.add(dayType, receivePeriod);
            Date currenttime = now.getTime();
            //当前日期加上周期后小于截止收租日就是没有到期，否则当前待缴
            if (currenttime.before(wxBillRent.getReceiveDate())) {
                wxBillRent.setStatus(EnumBillRentStatus.NOT_EXPIRED.getCode());
            } else {
                wxBillRent.setStatus(EnumBillRentStatus.WAIT_PAY.getCode());
            }
        }
    }

    public boolean isFirstDay(Date date){
        int dateInt = Integer.parseInt(new SimpleDateFormat("d").format(date));
        if(dateInt == 1){
            return true;
        }
        return false;
    }

    public static int getMonths(String startStr,String endStr){
        DateTimeFormatter formatter = DateTimeFormat.forPattern("yyyy-MM-dd");
        DateTime start = formatter.parseDateTime(startStr);
        DateTime end = formatter.parseDateTime(endStr);
        int months = Months.monthsBetween(start, end).getMonths();
        return months;
    }


    @Transactional(rollbackFor = {Exception.class})
    @Override
    public ResultData deleteById(String id) {
        wxRentContractMapper.deleteById(id);
        return new ResultData(Result.SUCCESS, "删除租赁合同信息成功");
    }

    @Override
    public void download(HttpServletRequest request, HttpServletResponse response, String tenantId) {
        String id = request.getParameter("id");
        WxRentContract wxRentContract = wxRentContractMapper.selectById(id);
        String filesuffix = wxRentContract.getFilepath().substring(wxRentContract.getFilepath().lastIndexOf("."));
        String filename = UUID.randomUUID() + filesuffix;
        String filepath = fmUploadDir;
        String destPath = filepath + filename;
        File dest = new File(destPath);
        File pDest = dest.getParentFile();
        if (!pDest.exists()) {
            pDest.mkdirs();
        }
        try {
            String exportFileName = wxRentContract.getFilename();
            DownFileUtil.downLoadFromUrl(wxRentContract.getFilepath(), filename, filepath);
            DownFileUtil.downFile(destPath, exportFileName, response, request);
            org.apache.commons.io.FileUtils.forceDelete(dest);
        } catch (IOException e) {
            logger.info("创建本地文件失败" + e.getMessage());
        }
    }

    @Transactional(rollbackFor = {Exception.class})
    @Override
    public Object getRentContractStatusInfo(WxRentContract rentContract) {

        Map<String, Object> resultData = new HashMap();
        //商铺信息
        WxShop wxShop = new WxShop();
        wxShop.setTenantId(rentContract.getTenantId());
        wxShop.setType(rentContract.getRentShopType());
        wxShop.setStatus(EnumShopStatus.RENT.getCode());
        List<WxShop> rentedList = wxShopMapper.findList(wxShop);
        wxShop.setStatus(EnumShopStatus.NOT_RENT.getCode());
        List<WxShop> unrentedList = wxShopMapper.findList(wxShop);

        HashMap<String, Object> shopMap = new HashMap<>(3);
        int rentedCount = rentedList.size();
        int unrentedCount = unrentedList.size();
        shopMap.put("rentedCount", rentedCount);
        shopMap.put("unrentedCount", unrentedCount);
        shopMap.put("allCount", rentedCount + unrentedCount);
        resultData.put("shopCountInfo", shopMap);

        //需要更新的状态
        resultData.putAll(updateStatus(rentContract));
        return resultData;
    }

    @Transactional(rollbackFor = {Exception.class})
    @Override
    public ResultData endRentContract(Long id, Integer status) {

        WxRentContract wxRentContract = wxRentContractMapper.selectById(id);
        if (wxRentContract == null) {
            return new ResultData(ErrorCode.RENT_CONTRACT_IS_NOT_FOUND);
        }
        wxRentContract.setStatus(EnumRentContractStatus.CONTRACT_TERMINATE.getCode());
        try {
            wxRentContract.setUpdatetime(new Date());
            wxRentContractMapper.updateById(wxRentContract);
            //停用商户
            wxMerchantService.disable(wxRentContract.getMerchantId());
            //物业合同终止
            if (status == 1) {
                WxPropertyContract wxPropertyContract = new WxPropertyContract();
                wxRentContract.setTenantId(wxRentContract.getTenantId());
                wxPropertyContract.setRentContractId(id);
                List<Map<String, Object>> contractData = wxPropertyContractMapper.queryPropertyContractData(wxPropertyContract);
                if (contractData.size() > 0) {
                    Map<String, Object> propertyContract = contractData.get(0);
                    Long propertyContractId = (Long) propertyContract.get("id");
                    if (propertyContract != null && propertyContractId != null) {
                        WxPropertyContract propertyContractUpdate = wxPropertyContractMapper.selectById(propertyContractId);
                        propertyContractUpdate.setStatus(EnumRentContractStatus.CONTRACT_TERMINATE.getCode());
                        propertyContractUpdate.setUpdatetime(new Date());
                        wxPropertyContractMapper.updateById(propertyContractUpdate);
                    }
                }
            }
        } catch (MallinkException e) {
            logger.info("终止合同失败:" + e.getMessage());
            throw new MallinkException(ErrorCode.DB_FAIL.getCode(), "DB FAILD " + e.getMessage());
        }
        return new ResultData(Result.SUCCESS, "操作成功");
    }

    @Transactional(rollbackFor = {Exception.class})
    @Override
    public ResultData updateMerchant(WxRentContract wxRentContract) {
        WxRentContract record = wxRentContractMapper.selectById(wxRentContract);
        if (wxRentContract == null) {
            return new ResultData(ErrorCode.RENT_CONTRACT_IS_NOT_FOUND);
        }
        record.setMerchantId(wxRentContract.getMerchantId());
        try {
            wxRentContractMapper.updateById(record);
        } catch (MallinkException e) {
            logger.info("关联合同商户失败:" + e.getMessage());
            throw new MallinkException(ErrorCode.DB_FAIL.getCode(), "DB FAILD " + e.getMessage());
        }
        return new ResultData(Result.SUCCESS, "操作成功");
    }

    @Override
    public PageInfo<WxRentContract> getRentContractList(WxRentContract rentContract, Integer pageIndex, Integer pageSize) {
        PageInfo<WxRentContract> pageInfo = PageHelper.startPage(pageIndex, pageSize).doSelectPageInfo(() -> wxRentContractMapper.getRentContractList(rentContract));
        return pageInfo;
    }

    @Override
    public Map<String, Object> updateStatus(WxRentContract record) {
        Map<String, Object> resultData = new HashMap();
        WxRentContract wxRentContract = new WxRentContract();
        wxRentContract.setTenantId(record.getTenantId());
        wxRentContract.setRentShopType(record.getRentShopType());

        int allCount = wxRentContractMapper.selectCount(new QueryWrapper(wxRentContract));
        resultData.put("allCount", allCount);

        //待签约
        wxRentContract.setStatus(EnumRentContractStatus.WAIT_SIGN.getCode());
        int waitSignCount = wxRentContractMapper.queryRentContractWaitSignStatus(wxRentContract);
        resultData.put("waitSignCount", waitSignCount);

        //计租中
        wxRentContract.setStatus(EnumRentContractStatus.RENT_PAID.getCode());
        wxRentContractMapper.updateRentContractPaidStatus(wxRentContract);
        int rendPaidCount = wxRentContractMapper.queryRentContractPaidStatus(wxRentContract);
        resultData.put("rendPaidCount", rendPaidCount);

        //将到期
        wxRentContract.setStatus(EnumRentContractStatus.CONTRACT_END_SOON.getCode());
        wxRentContractMapper.updateRentContractEndSoonStatus(wxRentContract);
        int endSoonCount = wxRentContractMapper.queryRentContractEndSoonStatus(wxRentContract);
        resultData.put("endSoonCount", endSoonCount);

        //到期
        wxRentContract.setStatus(EnumRentContractStatus.CONTRACT_END.getCode());
        wxRentContractMapper.updateRentContractEndStatus(wxRentContract);
        int endCount = wxRentContractMapper.queryRentContractEndStatus(wxRentContract);
        resultData.put("endCount", endCount);

        //合同到期
        contractEnd(record.getTenantId());

        return resultData;
    }

    private void contractEnd(String tenantId) {
        //查询状态为合同正常到期的数据
        WxRentContract wxRentContract = new WxRentContract();
        wxRentContract.setTenantId(tenantId);
        wxRentContract.setStatus(EnumRentContractStatus.CONTRACT_END.getCode());
        List<Map<String, Object>> rentContractData = wxRentContractMapper.queryRentContractData(wxRentContract);
        for (int i = 0, size = rentContractData.size(); i < size; i++) {
            Map<String, Object> contract = rentContractData.get(i);
            Object merchantId = contract.get("merchantId");
            if (merchantId != null) {
                WxMerchant merchant = wxMerchantMapper.selectById((Long) merchantId);
                Integer status = merchant.getStatus();
                if (status.equals(EnumMerchantStatus.VALID.getCode())) {
                    wxMerchantService.disable((Long) merchantId);
                }
            }
        }
    }

    @Override
    public void exportContract(HttpServletRequest request, HttpServletResponse response, String tenantId, Long id) {
        String contracType = "0";
        String templatePath = null;
        Map<String, Object> result = null;
        if (EnumContractType.ALL.getCode().toString().equals(contracType)) {
            logger.info("获取租赁及物业合同数据");
            result = getRentAndPropertyInfo(id);
            result.put("contractType", EnumContractType.ALL.getMessage());
            if (EnumRentContractType.RENT_BY_AREA.getCode().equals(result.get("type"))) {
                templatePath = "contract-word-template/contract_rent_property.docx";
            } else {
                templatePath = "contract-word-template/contract_rent_property_by_ratio.docx";
            }
            logger.info("租赁及物业合同数据结果:" + result);
        }

        if (templatePath == null) {
            logger.info("没有租赁及物业合同模板");
            return;
        }
        String filepath = fmUploadDir;
        String filename = UUID.randomUUID() + ".docx";
        String exportFileName = result.get("merchantName").toString() + "合同.docx";
        WordUtil.exportWord(templatePath, filepath, filename, exportFileName, result, request, response,null);
    }

    @Override
    @Transactional(rollbackFor = {Exception.class})
    public ResultData updateFile(WxRentContract record, Long userId,String userName,Date oldRentStartDate) {
        // 保存调整金额（预账单调整）
        if(!CollectionUtils.isEmpty(record.getPreviewBillRentList())){
            savePreviewBill(record);
        }
        ResultData resultData = getResultDataForUpdate(record, userId,0,oldRentStartDate);
        if (resultData.code != Result.SUCCESS) {
            return resultData;
        }

        //有模板，启动审批流，没有，直接生产账单
        if (!CollectionUtils.isEmpty(record.getFlowParams())) {
            if (wxFlowService.getModelByType((Integer) record.getFlowParams().get("businessType"), record.getTenantId()) == null
                    && record.getMerchantId() != null) {
                updateRentContractStatus(record.getId());
            }else{
                record.getFlowParams().put("businessId", record.getId().toString());
                if (record.getMerchantId() != null) {
                    record.getFlowParams().put("supplement", true);  //设置补录
                }
                wxFlowService.start(record.getFlowParams(), userId, userName, record.getTenantId());

                // 合同状态改成待签约
                WxRentContract updateRentContract = new WxRentContract();
                updateRentContract.setId(record.getId());
                updateRentContract.setStatus(EnumRentContractStatus.WAIT_SIGN.getCode());
                wxRentContractMapper.updateStatus(updateRentContract);
                logger.info("id:{},启动审批流成功,是否补录:{}", record.getId().toString(), record.getMerchantId() != null);
            }
        }else{
            //审批状态重置
            WxRentContract updateRentContract = new WxRentContract();
            updateRentContract.setId(record.getId());
            updateRentContract.setApplyStatus(EnumRentContractAppStatus.DEFAULT.getCode());
            updateApplyStatus(updateRentContract);
        }

        return resultData;
    }

    @Override
    public ResultData updateRentContractStatus(Long id) {
        if (id == null) {
            return new ResultData(ErrorCode.SYS_PARAMETER_ERROR);
        }
        WxRentContract record = wxRentContractMapper.selectById(id);
        if (record == null) {
            return new ResultData(ErrorCode.RENT_CONTRACT_IS_NOT_FOUND);
        }
        //更新合同状态为签约
        WxRentContract wxRentContract = new WxRentContract();
        wxRentContract.setId(id);
        if (record.getRentalStartDate().before(new Date())) {
            wxRentContract.setStatus(EnumRentContractStatus.RENT_PAID.getCode());
        } else {
            wxRentContract.setStatus(EnumRentContractStatus.SIGNED_RENT_UNPAID.getCode());
        }
        wxRentContractMapper.updateById(wxRentContract);
        EventUtil.publistRentEvent(this, wxRentContract);
        //建立账单
        if (record != null &&
                record.getMerchantId() != null &&
                record.getReceivePeriod() != null &&
                record.getPrice() > 0 ) {
            //预览账单改为正式,并写入商户id
            WxBillRent billRent = new WxBillRent();
            billRent.setRentContractId(id);
            billRent.setIsPreview(EnumIsPreview.NO.getCode());
            billRent.setMerchantId(record.getMerchantId());
            wxBillRentMapper.updatePreviewStatus(billRent);
            WxMerchant wxMerchant = new WxMerchant();
            wxMerchant.setId(record.getMerchantId());
            wxMerchant.setTenantId(record.getTenantId());
            if(record.getDeposit() > 0) {
                //押金
                buildDeposit(wxMerchant, null, id);
            }
            updatePropertyPreviewBill(record);
            //作废合同
            updateInvalidContract(id);
        }

        return new ResultData(Result.SUCCESS, "操作成功");
    }

    @Override
    public void updatePropertyPreviewBill(WxRentContract record) {
        //合并合同-更新物业账单
        if (record.getOperationType().equals(EnumContractOperationType.WHOLE.getCode())) {
            WxPropertyContract wxPropertyContract = new WxPropertyContract();
            wxPropertyContract.setRentContractId(record.getId());
            wxPropertyContract.setStatus(EnumRentContractStatus.WAIT_SIGN.getCode());
            WxPropertyContract propertyContract = wxPropertyContractMapper.selectOne(new QueryWrapper(wxPropertyContract));
            if (propertyContract != null) {
                propertyContract.setMerchantId(record.getMerchantId());
                wxPropertyContractMapper.updateById(propertyContract);
                wxPropertyContractService.updatePropertyContractStatus(propertyContract.getId());
            }
        }
    }

    public Map<String, Object> getRentAndPropertyInfo(Long id) {
        logger.info("获取租赁物业合同数据>>>>>>id:" + id);
        Map<String, Object> result = new HashMap<>();
        WxRentContract wxRentContract = wxRentContractMapper.selectById(id);
        if (wxRentContract.getRentShopType().equals(EnumRentShopType.SHOP.getCode())) {
            JSONArray jsonArray = JSONArray.parseArray(wxRentContract.getRentInfo());
            StringBuffer shopNumberStr = new StringBuffer();
            StringBuffer floorNameStr = new StringBuffer();
            StringBuffer buildingNameStr = new StringBuffer();
            StringBuffer buildAreaStr = new StringBuffer();
            StringBuffer operationAreaStr = new StringBuffer();
            for (int i = 0, size = jsonArray.size(); i < size; i++) {
                JSONObject jsonObject = jsonArray.getJSONObject(i);
                shopNumberStr.append("[").append(jsonObject.getString("shopNumber")).append("]");
                floorNameStr.append("[").append(jsonObject.getString("floor")).append("]");
                buildingNameStr.append("[").append(jsonObject.getString("building")).append("]");
                buildAreaStr.append("[").append(jsonObject.getString("buildArea")).append("]");
                operationAreaStr.append("[").append(jsonObject.getString("operationArea")).append("]");
            }
            result.put("shopNumber", shopNumberStr);
            result.put("floorName", floorNameStr);
            result.put("buildingName", buildingNameStr);
            result.put("buildArea", buildAreaStr);
            result.put("operationArea", operationAreaStr);
        } else {
            WxShop record = new WxShop();
            record.setId(wxRentContract.getShopId());
            List<Map<String, Object>> wxShops = wxShopMapper.findListMap(record);
            if (!wxShops.isEmpty()) {
                //店铺信息
                Map<String, Object> wxShop = wxShops.get(0);
                result.put("shopNumber", wxShop.get("shopNumber"));
                result.put("floorName", wxShop.get("floor"));
                result.put("buildingName", wxShop.get("building"));
                result.put("buildArea", wxShop.get("buildArea"));
                result.put("operationArea", wxShop.get("operationArea"));
            } else {
                result.put("shopNumber", " ");
                result.put("floorName", " ");
                result.put("buildingName", " ");
                result.put("buildArea", " ");
                result.put("operationArea", " ");
            }
        }
        //MALL信息
        WxMall wxMall = new WxMall();
        wxMall.setTenantId(wxRentContract.getTenantId());
        wxMall = wxMallMapper.findList(wxMall).get(0);
        result.put("mallName", wxMall.getName());
        result.put("province", wxMall.getProvince());
        result.put("city", wxMall.getCity());
        //经营业态
        WxBusiness wxBusiness = wxBusinessMapper.selectById(wxRentContract.getBusinessId());
        result.put("business", wxBusiness.getTitle());

        //商户信息
        WxMerchant merchant = wxMerchantService.getById(wxRentContract.getMerchantId());
        if (merchant != null) {
            result.put("merchantName", merchant.getName());
            //法人信息
            WxMerchantCorp wxMerchantCorp = merchant.getWxMerchantCorp();
            result.put("corpPapersNumber", StringUtils.isNotEmpty(wxMerchantCorp.getCorpPapersNumber()) ? wxMerchantCorp.getCorpPapersNumber() : " ");
            result.put("corpPapersType", wxMerchantCorp.getCorpPapersType() != null ? EnumPapersType.getEnum(wxMerchantCorp.getCorpPapersType()).getMessage() : " ");
            result.put("corpPapersPerson", StringUtils.isNotEmpty(wxMerchantCorp.getCorpPapersPerson()) ? wxMerchantCorp.getCorpPapersPerson() : " ");
            //税务信息
            WxMerchantTax wxMerchantTax = merchant.getWxMerchantTax();
            result.put("taxPapersType", wxMerchantTax.getTaxPapersType() != null ? EnumTaxpayerType.getEnum(wxMerchantTax.getTaxPapersType()).getMessage() : " ");
            result.put("bankName", StringUtils.isNotEmpty(wxMerchantTax.getBankName()) ? wxMerchantTax.getBankName() : " ");
            result.put("bankAccount", StringUtils.isNotEmpty(wxMerchantTax.getBankAccount()) ? wxMerchantTax.getBankAccount() : " ");
            result.put("invoiceAddressPhone", StringUtils.isNotEmpty(wxMerchantTax.getInvoiceAddressPhone()) ? wxMerchantTax.getInvoiceAddressPhone() : " ");
        } else {
            result.put("merchantName", "");
            //法人信息
            result.put("corpPapersNumber", " ");
            result.put("corpPapersType", " ");
            result.put("corpPapersPerson", " ");
            //税务信息
            result.put("taxPapersType", " ");
            result.put("bankName", " ");
            result.put("bankAccount", " ");
            result.put("invoiceAddressPhone", " ");
        }
        //租赁合同信息
        String rentalStartDate = DateUtils.date2String(wxRentContract.getRentalStartDate(), "yyyy-MM-dd");
        result.put("rentalStartDate", rentalStartDate);
        result.put("rentalStartDateYear", rentalStartDate.substring(0, 4));
        result.put("rentalStartDateMonth", rentalStartDate.substring(5, 7));
        result.put("rentalStartDateDay", rentalStartDate.substring(8));
        String rentalEndDate = DateUtils.date2String(wxRentContract.getRentalEndDate(), "yyyy-MM-dd");
        result.put("rentalEndDate", rentalEndDate);
        result.put("rentalEndDateYear", rentalEndDate.substring(0, 4));
        result.put("rentalEndDateMonth", rentalEndDate.substring(5, 7));
        result.put("rentalEndDateDay", rentalEndDate.substring(8));
        result.put("price", wxRentContract.getPrice());
        result.put("contractNumber", wxRentContract.getContractNumber());
        Integer lease = wxRentContract.getLease();
        Integer receivePeriod = wxRentContract.getReceivePeriod();
        result.put("lease", lease);
        result.put("receivePeriod", receivePeriod);
        String payAccountStr = " ";
        if(wxRentContract.getPayAccount() != null && !wxRentContract.getPayAccount().equals("")) {
            payAccountStr = wxRentContract.getPayAccount();
        }
        result.put("payAccount", payAccountStr);
        result.put("signDate", DateUtils.date2String(wxRentContract.getSignDate(), "yyyy-MM-dd"));
        //主体名称-乙方
        if (StringUtils.isNotEmpty(wxRentContract.getSubjectName())) {
            result.put("corpPapersPerson", wxRentContract.getSubjectName());
        } else {
            result.put("corpPapersPerson", " ");
        }

        //品牌
        Long brandId = wxRentContract.getBrand();
        String brand = " ";
        if (brandId != null) {
            WxBrand wxBrand = WxBrandMapper.selectById(brandId);
            if (wxBrand != null) {
                brand = wxBrand.getName();
            }
        }
        result.put("brand", brand);
        // TODO
        //double adjustRatio = wxRentContract.getAdjustRatio() != null ? wxRentContract.getAdjustRatio() / 100.0 : 0;
        result.put("adjustRatio", 0);
        double priceRent = new BigDecimal(wxRentContract.getPrice())
                .divide(new BigDecimal(100)).setScale(2, RoundingMode.HALF_EVEN).doubleValue();
        result.put("priceRent", priceRent);
        if (!wxRentContract.getRentArea().equals("0")) {
            double unitPrice = new BigDecimal(wxRentContract.getPrice())
                    .divide(new BigDecimal(wxRentContract.getRentArea()), 2, RoundingMode.HALF_EVEN)
                    .divide(new BigDecimal(100))
                    .setScale(2, RoundingMode.HALF_EVEN).doubleValue();
            result.put("unitPriceRent", unitPrice);
            result.put("priceRentUpper", PriceUtil.digitUppercase(priceRent));
            result.put("unitPriceRentUpper", PriceUtil.digitUppercase(unitPrice));
        } else {
            result.put("unitPriceRent", 0);
            result.put("priceRentUpper", PriceUtil.digitUppercase(0));
            result.put("unitPriceRentUpper", PriceUtil.digitUppercase(0));
        }

        //租赁保证金
        int cashDepositMonthRent = 3;
        double cashDepositRent = new BigDecimal(wxRentContract.getPrice()).multiply(new BigDecimal(cashDepositMonthRent))
                .divide(new BigDecimal(100)).setScale(2, RoundingMode.HALF_EVEN).doubleValue();
        result.put("cashDepositMonthRent", cashDepositMonthRent);
        result.put("cashDepositRent", cashDepositRent);
        result.put("cashDepositRentUpper", PriceUtil.digitUppercase(cashDepositRent));
        result.put("type", wxRentContract.getType());
        int extralease = lease % 12;
        int extracount = extralease > 0 ? 1 : 0;
        int paycount = lease / 12 + extracount;
        int index = 10 - paycount;
        int count = paycount - 1;
        BigDecimal rentPrice = new BigDecimal(priceRent);
        //保底
        if (wxRentContract.getRevenue() != null) {
            double revenue = new BigDecimal(wxRentContract.getRevenue())
                    .divide(new BigDecimal(100)).setScale(2, RoundingMode.HALF_EVEN).doubleValue();
            result.put("revenue", revenue);
            result.put("revenueUpper", PriceUtil.digitUppercase(revenue));
        } else {
            result.put("revenue", 0);
            result.put("revenueUpper", PriceUtil.digitUppercase(0));
        }
        if (!wxRentContract.getType().equals(EnumRentContractType.RENT_BY_JOINT.getCode())) {
            areaWay(wxRentContract, result, lease, extralease, extracount, paycount, index, count, rentPrice);
        } else {
            ratioWay(wxRentContract, result, lease, extralease, extracount, paycount, index, count, rentPrice);
        }
        //物业合同信息
        WxPropertyContract propertyContract = new WxPropertyContract();
        propertyContract.setTenantId(wxRentContract.getTenantId());
        propertyContract.setRentContractId(wxRentContract.getId());
        Optional<Map<String, Object>> first = wxPropertyContractMapper.queryPropertyContractData(propertyContract)
                .stream().filter(rc -> !rc.get("status").equals(EnumRentContractStatus.CONTRACT_TERMINATE.getCode())
                        && !rc.get("status").equals(EnumRentContractStatus.WAIT_SIGN.getCode())
                        && !rc.get("status").equals(EnumRentContractStatus.INVALID.getCode())
                        && !rc.get("status").equals(EnumRentContractStatus.CONTRACT_END.getCode())
                        && !rc.get("status").equals(EnumRentContractStatus.INTENTION.getCode())).findFirst();
        Map<String, Object> wxPropertyContract = null;
        if (first.isPresent()) {
            wxPropertyContract = first.get();
        }
        if (wxPropertyContract != null) {
            Integer receivePeriodProperty = (Integer) wxPropertyContract.get("receivePeriod");
            result.put("receivePeriodProperty", receivePeriodProperty);
            double priceProperty = new BigDecimal(wxPropertyContract.get("price").toString())
                    .divide(new BigDecimal(100)).setScale(2, RoundingMode.HALF_EVEN).doubleValue();
            result.put("priceProperty", priceProperty);
            if (!wxRentContract.getRentArea().equals("0")) {
                double unitPriceProperty = new BigDecimal(wxPropertyContract.get("price").toString())
                        .divide(new BigDecimal(wxRentContract.getRentArea()), 2, RoundingMode.HALF_EVEN)
                        .divide(new BigDecimal(100)).setScale(2, RoundingMode.HALF_EVEN).doubleValue();
                result.put("unitPriceProperty", unitPriceProperty);
                result.put("pricePropertyUpper", PriceUtil.digitUppercase(priceProperty));
                result.put("unitPricePropertyUpper", PriceUtil.digitUppercase(unitPriceProperty));
            } else {
                result.put("unitPriceProperty", 0);
                result.put("pricePropertyUpper", PriceUtil.digitUppercase(0));
                result.put("unitPricePropertyUpper", PriceUtil.digitUppercase(0));
            }

            //首期物业费
            Calendar instance = Calendar.getInstance();
            instance.setTime(wxRentContract.getRentalStartDate());
            instance.add(Calendar.MONTH, 0);
            Date starttime = instance.getTime();
            String startdate = DateUtils.date2String(starttime, "yyyy-MM-dd");
            result.put("rentalStartDateProperty", startdate);
            result.put("rentalStartDateYearProperty", startdate.substring(0, 4));
            result.put("rentalStartDateMonthProperty", startdate.substring(5, 7));
            result.put("rentalStartDateDayProperty", startdate.substring(8));
            //结束时间
            instance.clear();
            instance.setTime(starttime);
            instance.add(Calendar.MONTH, receivePeriodProperty);
            instance.add(Calendar.DAY_OF_MONTH, -1);
            Date endtime = instance.getTime();
            String enddate = DateUtils.date2String(endtime, "yyyy-MM-dd");
            result.put("rentalEndDateProperty", enddate);
            result.put("rentalEndDateYearProperty", enddate.substring(0, 4));
            result.put("rentalEndDateMonthProperty", enddate.substring(5, 7));
            result.put("rentalEndDateDayProperty", enddate.substring(8));
            double pricePropertyFirst = new BigDecimal(priceProperty)
                    .multiply(new BigDecimal(receivePeriodProperty))
                    .setScale(2, RoundingMode.HALF_EVEN).doubleValue();
            result.put("pricePropertyFirst", pricePropertyFirst);
            result.put("pricePropertyFirstUpper", PriceUtil.digitUppercase(pricePropertyFirst));


            //物业保证金
            int cashDepositMonthProperty = 3;
            double cashDepositProperty = new BigDecimal(wxPropertyContract.get("price").toString()).multiply(new BigDecimal(cashDepositMonthProperty))
                    .divide(new BigDecimal(100)).setScale(2, RoundingMode.HALF_EVEN).doubleValue();
            result.put("cashDepositMonthProperty", cashDepositMonthProperty);
            result.put("cashDepositProperty", cashDepositProperty);
            result.put("cashDepositPropertyUpper", PriceUtil.digitUppercase(cashDepositProperty));


        } else {
            result.put("receivePeriodProperty", " ");
            result.put("priceProperty", " ");
            result.put("unitPriceProperty", " ");
            result.put("pricePropertyUpper", " ");
            result.put("unitPricePropertyUpper", " ");
            //首期物业费
            result.put("rentalStartDateProperty", " ");
            result.put("rentalStartDateYearProperty", " ");
            result.put("rentalStartDateMonthProperty", " ");
            result.put("rentalStartDateDayProperty", " ");
            //结束时间
            result.put("rentalEndDateProperty", " ");
            result.put("rentalEndDateYearProperty", " ");
            result.put("rentalEndDateMonthProperty", " ");
            result.put("rentalEndDateDayProperty", " ");
            result.put("pricePropertyFirst", " ");
            result.put("pricePropertyFirstUpper", " ");
            //物业保证金
            result.put("cashDepositMonthProperty", " ");
            result.put("cashDepositProperty", " ");
            result.put("cashDepositPropertyUpper", " ");
        }


        return result;
    }

    public void ratioWay(WxRentContract wxRentContract, Map<String, Object> result, Integer lease, int extralease, int extracount, int paycount, int index, int count, BigDecimal rentPrice) {
        String adjustRatio = wxRentContract.getAdjustRatio();
        List<Integer> integers = JSONArray.parseArray(adjustRatio, Integer.class);
        integers.add(0, 0);
        //常规租期
        for (int i = 0; i <= count; i++) {
            //开始时间
            Calendar instance = Calendar.getInstance();
            instance.setTime(wxRentContract.getRentalStartDate());
            instance.add(Calendar.MONTH, lease * i);
            Date starttime = instance.getTime();
            String startdate = DateUtils.date2String(starttime, "yyyy-MM-dd");
            result.put("rentalStartDate" + i, startdate);
            result.put("rentalStartDateYear" + i, startdate.substring(0, 4));
            result.put("rentalStartDateMonth" + i, startdate.substring(5, 7));
            result.put("rentalStartDateDay" + i, startdate.substring(8));
            //结束时间
            instance.clear();
            instance.setTime(starttime);
            instance.add(Calendar.MONTH, lease);
            instance.add(Calendar.DAY_OF_MONTH, -1);
            Date endtime = instance.getTime();
            String enddate = DateUtils.date2String(endtime, "yyyy-MM-dd");
            result.put("rentalEndDate" + i, enddate);
            result.put("rentalEndDateYear" + i, enddate.substring(0, 4));
            result.put("rentalEndDateMonth" + i, enddate.substring(5, 7));
            result.put("rentalEndDateDay" + i, enddate.substring(8));
            String ratio = new BigDecimal(integers.get(i)).divide(new BigDecimal(100)).toPlainString();
            result.put("adjustRatio" + i, ratio);
            result.put("adjustPeriod" + i, wxRentContract.getAdjustPeriod());
            Integer tempPayRatio = Optional.ofNullable(wxRentContract.getPayRatio()).orElse(0);
            String payRatio = new BigDecimal(tempPayRatio).divide(new BigDecimal(100)).toPlainString();
            result.put("payRatio" + i, payRatio);

        }
        if (extracount > 0) {
            //额外租期
            //开始时间
            Calendar instance = Calendar.getInstance();
            instance.setTime(wxRentContract.getRentalStartDate());
            instance.add(Calendar.MONTH, lease * count);
            Date starttime = instance.getTime();
            String startdate = DateUtils.date2String(starttime, "yyyy-MM-dd");
            result.put("rentalStartDate" + count, startdate);
            result.put("rentalStartDateYear" + count, startdate.substring(0, 4));
            result.put("rentalStartDateMonth" + count, startdate.substring(5, 7));
            result.put("rentalStartDateDay" + count, startdate.substring(8));
            //结束时间
            instance.clear();
            instance.setTime(starttime);
            instance.add(Calendar.MONTH, extralease);
            instance.add(Calendar.DAY_OF_MONTH, -1);
            Date endtime = instance.getTime();
            String enddate = DateUtils.date2String(endtime, "yyyy-MM-dd");
            result.put("rentalEndDate" + count, enddate);
            result.put("rentalEndDateYear" + count, enddate.substring(0, 4));
            result.put("rentalEndDateMonth" + count, enddate.substring(5, 7));
            result.put("rentalEndDateDay" + count, enddate.substring(8));
            result.put("adjustRatio" + count, wxRentContract.getAdjustRatio());
            result.put("adjustPeriod" + count, wxRentContract.getAdjustPeriod());
            Integer tempPayRatio = Optional.ofNullable(wxRentContract.getPayRatio()).orElse(0);
            String payRatio = new BigDecimal(tempPayRatio).divide(new BigDecimal(100)).toPlainString();
            result.put("payRatio" + count, payRatio);

        }
        //无数据租期
        for (int i = paycount; i <= 10; i++) {
            result.put("rentalStartDate" + i, "/");
            result.put("rentalStartDateYear" + i, "/");
            result.put("rentalStartDateMonth" + i, "/");
            result.put("rentalStartDateDay" + i, "/");
            result.put("rentalEndDate" + i, "/");
            result.put("rentalEndDateYear" + i, "/");
            result.put("rentalEndDateMonth" + i, "/");
            result.put("rentalEndDateDay" + i, "/");
            result.put("adjustRatio" + i, "/");
            result.put("adjustPeriod" + i, "/");
            result.put("payRatio" + i, "/");
        }
    }

    public void areaWay(WxRentContract wxRentContract, Map<String, Object> result, Integer lease, int extralease, int extracount, int paycount, int index, int count, BigDecimal rentPrice) {

        long[] priceArrs = new long[]{};
        List<String> adjustRatioList = new ArrayList<>();
        adjustRatioList.add(0, "0");
        if (wxRentContract.getRentShopType().equals(EnumRentShopType.SHOP.getCode())) {
            String rentInfo = wxRentContract.getRentInfo();
            JSONArray objects = JSONArray.parseArray(rentInfo);
            JSONObject jsonObject = objects.getJSONObject(0);
            JSONArray adjustRatio = jsonObject.getJSONArray("adjustRatio");
            for (int i = 0, size = adjustRatio.size(); i < size; i++) {
                StringBuffer adjustRatioStr = new StringBuffer();
                for (int j = 0, shopSize = objects.size(); j < shopSize; j++) {
                    JSONObject shopObject = objects.getJSONObject(j);
                    JSONArray adjustRatioArr = shopObject.getJSONArray("adjustRatio");
                    String shopNumber = shopObject.getString("shopNumber");
                    adjustRatioStr.append(shopNumber).append("[").append(adjustRatioArr.getIntValue(i)).append("]");
                }
                adjustRatioList.add(adjustRatioStr.toString());
            }
            List<long[]> priceList = computePrice(rentInfo, wxRentContract);
            int size = priceList.size();
            priceArrs = new long[size];
            for (int i = 0; i < size; i++) {
                long[] priceInt = priceList.get(i);
                long sum = 0;
                for (long p : priceInt) {
                    sum += p;
                }
                priceArrs[i] = sum;
            }
        } else {
            String adjustRatio = wxRentContract.getAdjustRatio();
            List<Integer> integers = JSONArray.parseArray(adjustRatio, Integer.class);
            for (int i = 0, size = integers.size(); i < size; i++) {
                double ratioStr = new BigDecimal(integers.get(i)).divide(new BigDecimal(100)).doubleValue();
                adjustRatioList.add(String.valueOf(ratioStr));
            }
        }
        String payRatioStr = "0";
        if (wxRentContract.getPayRatio() != null) {
            payRatioStr = new BigDecimal(wxRentContract.getPayRatio()).divide(new BigDecimal(100)).toPlainString();
        }
        //常规租期
        for (int i = 0; i <= count; i++) {
            //开始时间
            Calendar instance = Calendar.getInstance();
            instance.setTime(wxRentContract.getRentalStartDate());
            instance.add(Calendar.MONTH, lease * i);
            Date starttime = instance.getTime();
            String startdate = DateUtils.date2String(starttime, "yyyy-MM-dd");
            result.put("rentalStartDate" + i, startdate);
            result.put("rentalStartDateYear" + i, startdate.substring(0, 4));
            result.put("rentalStartDateMonth" + i, startdate.substring(5, 7));
            result.put("rentalStartDateDay" + i, startdate.substring(8));
            //结束时间
            instance.clear();
            instance.setTime(starttime);
            instance.add(Calendar.MONTH, lease);
            instance.add(Calendar.DAY_OF_MONTH, -1);
            Date endtime = instance.getTime();
            String enddate = DateUtils.date2String(endtime, "yyyy-MM-dd");
            result.put("rentalEndDate" + i, enddate);
            result.put("rentalEndDateYear" + i, enddate.substring(0, 4));
            result.put("rentalEndDateMonth" + i, enddate.substring(5, 7));
            result.put("rentalEndDateDay" + i, enddate.substring(8));

            if (wxRentContract.getRentShopType().equals(EnumRentShopType.SHOP.getCode())) {
                rentPrice = new BigDecimal(priceArrs[i]).divide(new BigDecimal(100)).setScale(2, RoundingMode.HALF_EVEN);
                result.put("priceRentUpper" + i, PriceUtil.digitUppercase(rentPrice.doubleValue()));
                result.put("priceRent" + i, rentPrice.doubleValue());
                result.put("adjustRatio" + i, adjustRatioList.get(i));
            } else {
                rentPrice = rentPrice.multiply(new BigDecimal(adjustRatioList.get(i)))
                        .add(rentPrice).setScale(2, RoundingMode.HALF_EVEN);
                result.put("priceRentUpper" + i, PriceUtil.digitUppercase(rentPrice.doubleValue()));
                result.put("priceRent" + i, rentPrice.doubleValue());
                result.put("adjustRatio" + i, adjustRatioList.get(i));
            }
            result.put("payRatio" + i, payRatioStr);
            result.put("adjustPeriod" + i, wxRentContract.getAdjustPeriod());
        }
        if (extracount > 0) {
            //额外租期
            //开始时间
            Calendar instance = Calendar.getInstance();
            instance.setTime(wxRentContract.getRentalStartDate());
            instance.add(Calendar.MONTH, lease * count);
            Date starttime = instance.getTime();
            String startdate = DateUtils.date2String(starttime, "yyyy-MM-dd");
            result.put("rentalStartDate" + count, startdate);
            result.put("rentalStartDateYear" + count, startdate.substring(0, 4));
            result.put("rentalStartDateMonth" + count, startdate.substring(5, 7));
            result.put("rentalStartDateDay" + count, startdate.substring(8));
            //结束时间
            instance.clear();
            instance.setTime(starttime);
            instance.add(Calendar.MONTH, extralease);
            instance.add(Calendar.DAY_OF_MONTH, -1);
            Date endtime = instance.getTime();
            String enddate = DateUtils.date2String(endtime, "yyyy-MM-dd");
            result.put("rentalEndDate" + count, enddate);
            result.put("rentalEndDateYear" + count, enddate.substring(0, 4));
            result.put("rentalEndDateMonth" + count, enddate.substring(5, 7));
            result.put("rentalEndDateDay" + count, enddate.substring(8));

            if (wxRentContract.getRentShopType().equals(EnumRentShopType.SHOP.getCode())) {
                rentPrice = new BigDecimal(priceArrs[count]).divide(new BigDecimal(100)).setScale(2, RoundingMode.HALF_EVEN);
                result.put("priceRentUpper" + count, PriceUtil.digitUppercase(rentPrice.doubleValue()));
                result.put("priceRent" + count, rentPrice.doubleValue());
            } else {
                rentPrice = rentPrice.multiply(new BigDecimal(adjustRatioList.get(count)))
                        .add(rentPrice).setScale(2, RoundingMode.HALF_EVEN);
                result.put("priceRentUpper" + count, PriceUtil.digitUppercase(rentPrice.doubleValue()));
                result.put("priceRent" + count, rentPrice.doubleValue());
            }

        }
        //无数据租期
        for (int i = paycount; i <= 10; i++) {
            result.put("rentalStartDate" + i, "/");
            result.put("rentalStartDateYear" + i, "/");
            result.put("rentalStartDateMonth" + i, "/");
            result.put("rentalStartDateDay" + i, "/");
            result.put("rentalEndDate" + i, "/");
            result.put("rentalEndDateYear" + i, "/");
            result.put("rentalEndDateMonth" + i, "/");
            result.put("rentalEndDateDay" + i, "/");
            result.put("priceRentUpper" + i, "/");
            result.put("priceRent" + i, "/");
            result.put("adjustRatio" + i, "/");
            result.put("payRatio" + i, "/");
            result.put("adjustPeriod" + i, "/");
        }
    }


    @Override
    public void updateApplyStatus(WxRentContract wxRentContract) {
        wxRentContractMapper.updateApplyStatus(wxRentContract);
    }

    @Override
    public Integer getShopType(WxRentContract wxRentContract) {
        return wxRentContractMapper.getShopType(wxRentContract);
    }

    public static double getMonthNeedPay(Double price,Date start,Date end,int dayType,int receivePeriod,boolean part){
        SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd");
        SimpleDateFormat sdM = new SimpleDateFormat("yyyy-MM");
        SimpleDateFormat sdD = new SimpleDateFormat("d");
        Double total = new Double(0);
        int[] diff;

        //同一天
        if(sd.format(start).equals(sd.format(end))){
            int dayCount = DateUtils.getMonthDayCount(start);
            return 1 * (price/dayCount);
        }

        //同月
        if(sdM.format(start).equals(sdM.format(end))){

            diff = DateUtils.getDiff(start,end);
            int dayCount = DateUtils.getMonthDayCount(start);
            total += (diff[1]+1) * (price/dayCount);
            return total;
        }

        //判断是否满足整月
        boolean isFullMonth = false;
        if(part){
            int startInt = Integer.parseInt(sdD.format(start));
            int endInt = Integer.parseInt(sdD.format(DateUtils.getDaySet(end,Calendar.DATE,1)));
            if(startInt == endInt){
                isFullMonth = true;
            }
        }else{
            Calendar instance = Calendar.getInstance();
            instance.setTime(start);
            instance.add(dayType, receivePeriod);
            instance.add(Calendar.DATE, -1);
            if(sd.format(instance.getTime()).equals(sd.format(end))){
                isFullMonth = true;
            }
        }

        if(isFullMonth){
            int months = getMonths(sdM.format(start)+"-01",sdM.format(DateUtils.getDaySet(end,Calendar.DATE,1))+"-01");
            return (months) * price;
        }

        //第一个月
        Date lastMonthDay = DateUtils.getLastDayForMonth(start);
        diff = DateUtils.getDiff(start,lastMonthDay);
        int dayCount = DateUtils.getMonthDayCount(start);
        total += (diff[1]+1) * (price/dayCount);

        //中间月份
        Date newStartDate = DateUtils.getDaySet(lastMonthDay,Calendar.DATE,1);
        int months = getMonths(sdM.format(newStartDate)+"-01",sdM.format(end)+"-01");
        total += months * price;

        //最后一个月
        diff = DateUtils.getDiff(DateUtils.getFirstDayForCurrMonth(end),end);
        dayCount = DateUtils.getMonthDayCount(end);
        total += (diff[1]+1) * (price/dayCount);
        return total;
    }

    /**
     * 按日计租  根据每月的日期总数计算needpay
     * @param monthPrice
     * @param start
     * @param end
     * @return
     */
    public static double getNeedPay(long monthPrice,Double dayPrice,Date start,Date end){
        SimpleDateFormat sd = new SimpleDateFormat("yyyy-MM-dd");
        SimpleDateFormat sdM = new SimpleDateFormat("yyyy-MM");
        Double total;
        int[] diff;

        int dayCount = DateUtils.getMonthDayCount(start);
        double price;
        if(monthPrice > 0){
            price = (double) monthPrice/dayCount;
        }else{
            price = dayPrice;
        }

        //同一天
        if(sd.format(start).equals(sd.format(end))){
            return 1 * price; //算1天
        }
        //同月
        if(sdM.format(start).equals(sdM.format(end))){
            diff = DateUtils.getDiff(start,end);
            return (diff[1]+1) * price;
        }

        Date currEnd = DateUtils.getLastDayForMonth(start);
        diff = DateUtils.getDiff(start,currEnd);
        total = (diff[1]+1) * price;

        int warnCount = 0;
        while (true){
            Date monthStartDate = DateUtils.getDaySet(currEnd,Calendar.DATE,1);
            dayCount = DateUtils.getMonthDayCount(monthStartDate);
            if(monthPrice > 0){
                price = (double) monthPrice/dayCount;
            }else{
                price = dayPrice;
            }

            //最后一个月
            if(sdM.format(monthStartDate).equals(sdM.format(end))){
                diff = DateUtils.getDiff(monthStartDate,end);
                total += price * (diff[1]+1);
                break;
            }else{
                currEnd = DateUtils.getLastDayForMonth(monthStartDate);
                diff = DateUtils.getDiff(monthStartDate,currEnd);
                total += price * (diff[1]+1);
            }

            //预警
            if(warnCount >= 1000){
                Logger logger = LoggerFactory.getLogger(WxRentContractServiceImpl.class);
                logger.error("getNeedPay() warnCount max error !!! monthPrice:{},dayPrice:{},start:{},end:{}",monthPrice,dayPrice,sd.format(start),sd.format(end));
                break;
            }
            warnCount ++;
        }
        return total;
    }

    public static List<BillTimeVo> initBillTimeList(Date start,Date end,Integer adjustPeriod,Integer dayType,int receivePeriod){
        List<BillTimeVo> list = new ArrayList<>();

        int count = 0;
        while (true){
            BillTimeVo timeVo = new BillTimeVo();

            //开始时间
            timeVo.setStartDate(start);

            //账单日
            Calendar instance = Calendar.getInstance();
            instance.setTime(start);
            if(!adjustPeriod.equals(EnumRentContractAdjustPeriod.ADJUST_PERIOD_NAR_MONTH.getCode())){
                instance.add(Calendar.DATE, -1);
            }
            timeVo.setReceiveDate(instance.getTime());

            //结束时间
            instance.clear();
            instance.setTime(start);
            instance.add(dayType, receivePeriod);
            instance.add(Calendar.DATE, -1);
            timeVo.setEndDate(instance.getTime());

            //自然月
            if(adjustPeriod.equals(EnumRentContractAdjustPeriod.ADJUST_PERIOD_NAR_MONTH.getCode())){
                if(count == 0){
                    if(receivePeriod == 1) { //周期1个月 头一个月到当月底
                        timeVo.setEndDate(DateUtils.getLastDayForMonth(timeVo.getStartDate()));
                    }else{
                        Date firstDay = DateUtils.getFirstDayForCurrMonth(start);
                        instance.clear();
                        instance.setTime(firstDay);
                        //最后一个期有余，加上残月,不整除时，最后一个月有余，否则为0
                        instance.add(dayType, receivePeriod);
                        instance.add(Calendar.DAY_OF_MONTH, -1);
                        timeVo.setEndDate(instance.getTime());
                    }
                }
            }

            if(timeVo.getEndDate().after(end)){
                timeVo.setEndDate(end);
            }

            list.add(timeVo);

            //next
            start = DateUtils.getDaySet(timeVo.getEndDate(),Calendar.DATE,1);

            if(start.after(end)) {
                break;
            }
            count ++;

            //预警
            if(count >= 1000){
                Logger logger = LoggerFactory.getLogger(WxRentContractServiceImpl.class);
                logger.error("initBillTimeList() warnCount max error !!!");
                break;
            }
        }
        return list;
    }

    @Override
    public void endContract(WxRentContract wxRentContract) {
        wxRentContract.setStatus(EnumRentContractStatus.CONTRACT_TERMINATE.getCode());
        wxRentContractMapper.updateStatus(wxRentContract);

        //终止租赁合同，同时终止物业合同
        if(EnumEndProperty.END_RENT_AND_PROPERTY.getCode().equals(wxRentContract.getEndProperty())){
            WxPropertyContract wxPropertyContract = new WxPropertyContract();
            wxPropertyContract.setRentContractId(wxRentContract.getId());
            wxPropertyContract.setStatus(EnumRentContractStatus.CONTRACT_TERMINATE.getCode());
            wxPropertyContractMapper.updateStatusByRentContractId(wxPropertyContract);

            //物业账单失效
            wxBillPropertyMapper.updateInvalidStatusByRent(wxRentContract);
        }
        //租赁账单失效
        WxBillRent wxBillRent = new WxBillRent();
        wxBillRent.setRentContractId(wxRentContract.getId());
        wxBillRentMapper.updateInvalidStatus(wxBillRent);

        //解绑商户和商铺关系
        WxRentContract rentContract = wxRentContractMapper.selectById(wxRentContract.getId());
        if(rentContract != null && rentContract.getMerchantId() != null){
            wxMerchantService.disable(rentContract.getMerchantId());
        }
    }

    @Override
    public WxRentContract getByBill(WxBillRent billRent) {
        return wxRentContractMapper.getByBill(billRent);
    }

    @Override
    public Map<Long, WxRentContract> selectRentContractByShopIds(Collection<Long> shopIds, String shopIdsRegexp,String tenantId) {
        List<WxRentContract> list = wxRentContractMapper.selectRentContractByShopIds(shopIds, shopIdsRegexp,tenantId);
        List<String> shopIdArr = Arrays.asList(StringUtils.split(shopIdsRegexp,"|")) ;
        Map<Long, WxRentContract> allShopContract = new HashMap<>();
        for (WxRentContract wxRentContract : list) {
            if (wxRentContract.getRentShopType().equals(EnumRentShopType.SHOP.getCode())) {
                String rentInfo = wxRentContract.getRentInfo();
                JSONArray rentInfoArray = JSONArray.parseArray(rentInfo);
                int size = rentInfoArray.size();
                //查询rent_info 包括 shopId
                for (int i = 0; i < size; i++) {
                    JSONObject rentInfoObject = rentInfoArray.getJSONObject(i);
                    Long shopId = rentInfoObject.getLong("shopId");
                    if (!shopIdArr.contains(String.valueOf(shopId))) {
                        continue;
                    }
                    WxRentContract rentContract = new WxRentContract();
                    BeanUtils.copyProperties(wxRentContract,rentContract);
                    rentContract.setRentalStartDate(wxRentContract.getRentalStartDate());
                    rentContract.setRentalEndDate(wxRentContract.getRentalEndDate());
                    rentContract.setShopId(shopId);
                    allShopContract.put(shopId, rentContract);
                }
            }
            if (shopIds.contains(wxRentContract.getShopId())) {
                allShopContract.put(wxRentContract.getShopId(), wxRentContract);
            }
        }
        return allShopContract;
    }

    @Override
    public int selectContractCountByShopId(WxRentContract wxRentContract) {
        return wxRentContractMapper.selectContractCountByShopId(wxRentContract) ;
    }
}
