package common.service.impl;

import com.amazonaws.services.dynamodbv2.xspec.S;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
import common.model.*;
import common.repository.*;
import common.service.ShareIncomeService;
import dic.ContractStatusEnum;
import dic.RoleEnum;
import net.sf.json.JSONArray;
import offline.model.AccountVO;
import offline.model.TrackFlowVO;
import offline.repository.TkioOfflineRepository;
import org.joda.time.DateTime;
import org.joda.time.Days;
import org.joda.time.Months;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import tkio.model.Account;
import tkio.repository.AccountRepository;
import tkio.repository.AppRepository;
import tkio.service.AccountFlowRestrictService;
import util.Constant;
import util.ContractBranchUtil;
import util.DateUtil;
import util.StringUtil;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

@Service
public class ShareIncomeServiceImpl implements ShareIncomeService {

    private final Logger logger = LoggerFactory.getLogger(ShareIncomeServiceImpl.class);

    @Autowired
    private ContractRepository contractRepository;
    @Autowired
    private AuthRepository authRepository;
    @Autowired
    private ContractBodyRepository contractBodyRepository;
    @Autowired
    private ContractChangeRepository contractChangeRepository;
    @Autowired
    private BarrioCityRepository barrioCityRepository;
    @Autowired
    private AppRepository appRepository;
    @Autowired
    private AccountRepository accountRepository;
    @Autowired
    private AccountFlowRestrictService accountFlowRestrictService;
    @Autowired
    private PackageBaseRepository packageBaseRepository;
    @Autowired
    private TkioFlowRepository tkioFlowRepository;
    @Autowired
    private TkioOfflineRepository tkioOfflineRepository;

    @Override
    public List<Contract> shareIncomeList(User loginAccount, String startDate, String endDate, String platform, String bodyCode, String serchName) {

        List<Contract> contracts = new ArrayList<>();

        if ("all".equals(bodyCode)) {
            bodyCode = null;
        }

        List<String> financeBodies = null;
        if (RoleEnum.FINANCE.getKey().equals(loginAccount.getRole())) {
            Auth auth = authRepository.findByUser(loginAccount.getId());
            financeBodies = JSONArray.fromObject(auth.getAuthExtend());
        }

        if (!StringUtils.isEmpty(bodyCode) && !StringUtils.isEmpty(serchName)) {

            if (financeBodies != null && !financeBodies.contains(bodyCode)) {
                //沒有权限查看
                return contracts;
            } else {
                contracts = contractRepository.findShareContranctByDate1(startDate, endDate, platform, bodyCode, serchName);
            }

        } else if (!StringUtils.isEmpty(bodyCode)) {
            if (financeBodies != null && !financeBodies.contains(bodyCode)) {
                //沒有权限查看
                return contracts;
            } else {
                contracts = contractRepository.findShareContranctByDate2(startDate, endDate, platform, bodyCode);
            }
        } else if (!StringUtils.isEmpty(serchName)) {
            if (financeBodies != null) {
                contracts = contractRepository.findShareContranctByDateSercheFinace(startDate, endDate, platform, serchName, financeBodies);
            } else {
                contracts = contractRepository.findShareContranctByDateSerche(startDate, endDate, platform, serchName);
            }
        } else {
            if (financeBodies != null) {
                contracts = contractRepository.findShareContranctByDateFinace(startDate, endDate, platform, financeBodies);
            } else {
                contracts = contractRepository.findShareContranctByDate3(startDate, endDate, platform);
            }
        }

        /*contracts = new ArrayList<>();
        contracts.add(contractRepository.findOne(4603L));*/

        List<ContractBody> bodies = contractBodyRepository.findAll();
        Map<String, String> bodiesNameMap = bodies.stream().collect(
                Collectors.toMap(ContractBody::getCode, ContractBody::getName, (v1, v2) -> v1));

        List<BarrioCity> barrioCities = barrioCityRepository.findAll();
        Map<Long, BarrioCity> barrioCitiesNameMap = barrioCities.stream().collect(Collectors.toMap(BarrioCity::getId, Function.identity(), (v1, v2) -> v1));

        List<PackageBase> packageBases = packageBaseRepository.findByPlatAndStatus(platform, 1);
        Map<Long, PackageBase> packageBaseMap = packageBases.stream().collect(Collectors.toMap(PackageBase::getId, Function.identity(), (v1, v2) -> v1));

        DateTime start = new DateTime(startDate);
        DateTime end = new DateTime(endDate);

        long start_ = System.currentTimeMillis();
//        for (Contract contract : contracts) {
//            this.shareIncome4Contract(contract, start, end);
//            contract.setMyBodyName(bodiesNameMap.get(contract.getMyBodyCode()));
//        }
        try (Stream<Contract> streamContract = contracts.parallelStream()) {
            streamContract.forEachOrdered(v -> {
                v.setMyBodyName(bodiesNameMap.get(v.getMyBodyCode()));
                if(v.getBarrioId()!=null)
                    v.setBarrioName(barrioCitiesNameMap.get(barrioCitiesNameMap.get(v.getBarrioId()).getParentId()).getName());
                if(v.getPriceLevel()!=null)
                    v.setPriceLevelName(packageBaseMap.get(v.getPriceLevel()).getPackageName());
            });
        }
        if("tkio".equals(platform)){
            this.shareIncome4ContractTKIO_2(contracts,start,end);
        }else{
            try (Stream<Contract> streamContract = contracts.parallelStream()) {
                streamContract.forEachOrdered(v -> {

                    switch (ContractBranchUtil.getValue(platform)){
                        case "type_one":this.shareIncome4Contract(v, start, end);break;
                        case "type_two":
                            if(v.getPriceLevel()==Constant.tkioPriceLevelNotLimit){
                                //TKIO不限量套餐
                                this.shareIncome4Contract(v, start, end);
                            }else{
                                //TKIO普通流量套餐
                                //this.shareIncome4ContractTwo(v, start, end);
                                this.shareIncome4ContractTKIO(v, start, end,false);
                            }
                            break;
                         case "type_three":this.shareIncome4ContractCAS(v, start, end);break;
                        default:this.shareIncome4Contract(v, start, end);break;
                    }
                });
            }
        }

        if(ContractBranchUtil.getValue(platform).equals("type_three")){
            List<Contract> removeContracts = new ArrayList<>();
            for (Contract contract : contracts) {
                if(contract.getIntervalUseDays()<0){
                    removeContracts.add(contract);
                }
            }
            if(!CollectionUtils.isEmpty(removeContracts)){
                contracts.removeAll(removeContracts);
            }
        }


        logger.info("计算分摊收入耗时:{}", (System.currentTimeMillis() - start_));

        //结果集result二次加工
        if ("tkio".equals(platform)) {
            //查询主账号为空的 并且 结束日期在查询范围内的
            List<Long> allEmailIsNullIds = contractRepository.findAllEmailIsNull(startDate, endDate);
            for(Contract contract : contracts){
                if(StringUtil.isEmpty(contract.getEmail()) || "null".equals(contract.getEmail())){
                    //不在查询范围内的数据，全部置空
                    if(allEmailIsNullIds ==null || !allEmailIsNullIds.contains(BigInteger.valueOf(contract.getId()))) {
                        contract.setClickFlow(0D); //区间点击数(万次)
                        contract.setIntervaIncomeShare(0L);//区间分摊收入
                        contract.setAdjustmentFund(0L);//区间调整金额
                        contract.setIncomeShareAll(0L);//区间总收入
                        contract.setIncomeGross(0L);//累计总收入(元)
                    }
                }
            }
        }

        return contracts;
    }

    private void shareIncome4ContractCAS(Contract contract, DateTime start, DateTime end) {
        DateTime[] selected = new DateTime[]{
                start,
                end};//用户筛选开始/结束日期
        DateTime[] contractPart = new DateTime[]{
                new DateTime(contract.getStartDate()),
                new DateTime(contract.getEndDate())};//合同开始结束 时间
        DateTime[] contractValidPart = new DateTime[]{
                new DateTime(contract.getValidStartDate()),
                new DateTime(contract.getValidEndDate())};//合同有效日 开始结束 时间
        DateTime[] usePart = new DateTime[]{
                selected[0].compareTo(contractValidPart[0]) <= 0 ? contractValidPart[0] : selected[0],
                selected[1].compareTo(contractValidPart[1]) >= 0 ? contractValidPart[1] : selected[1]
        };

        usePart[0] = usePart[0].compareTo(usePart[1]) >= 0 ? usePart[1] : usePart[0];

        contract.setIntervalUseDays(getDayRange(contractValidPart[0], usePart[1]) + 1);

        BigDecimal bigDecimal = new BigDecimal(contract.getMoney() / 1.13)
                .setScale(8, BigDecimal.ROUND_HALF_UP);


        Long excludTax = bigDecimal.setScale(2, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100L)).longValue();//不含税收入*100
        contract.setIncomeExcludingTax(excludTax);

        BigDecimal oneTimeRecognizedRevenue = null;
        BigDecimal dailyRevenueRecognition = null;
        if(contract.getOneTime()!=null&&contract.getOneTime()==false){//处理cas是否计算一次性收入标识
            oneTimeRecognizedRevenue = new BigDecimal("0");
            dailyRevenueRecognition = bigDecimal.multiply(new BigDecimal("100"));
        }else{
            oneTimeRecognizedRevenue = bigDecimal.multiply(new BigDecimal("0.9"));
            dailyRevenueRecognition = bigDecimal.multiply(new BigDecimal("10"));//0.1*100=10，前端拿到区间分摊收入/100得到最终的值
        }
        contract.setOneTimeRecognizedRevenue(oneTimeRecognizedRevenue.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
        int contractAllDay = getDayRange(contractValidPart[0], contractValidPart[1]) + 1;//合同总天数

        //处理精度
        BigDecimal dayShareIncome = dailyRevenueRecognition.divide(new BigDecimal(String.valueOf(contractAllDay)),8,BigDecimal.ROUND_HALF_UP);

        //作废合同处理
        Contract cancleContract = this.cancledShareCAS(contract, oneTimeRecognizedRevenue,contractAllDay, dayShareIncome, contractPart, usePart, selected ,contractValidPart);
        if (cancleContract != null) {
            return;
        }

        //中止合同处理
        Contract suspendContract = this.suspendShareCAS(contract,oneTimeRecognizedRevenue, contractAllDay, dayShareIncome, contractPart, usePart, selected,contractValidPart);
        if (suspendContract != null) {
            return;
        }


        //晚录合同处理
        DateTime create = new DateTime(new DateTime(contract.getCreateTime()).toString("yyyy-MM-dd")); //录入时间点
        DateTime[] creatPoints = new DateTime[]{
                create, //录入日
                create.dayOfMonth().withMinimumValue() //录入月1日
        };
        this.afterContractCAS(contract,oneTimeRecognizedRevenue, contractAllDay, dayShareIncome, contractPart, usePart, selected, creatPoints,contractValidPart);

    }

    private void afterContractCAS(Contract contract, BigDecimal oneTimeRecognizedRevenue, int contractAllDay, BigDecimal dayShareIncome, DateTime[] contractPart, DateTime[] usePart, DateTime[] selected, DateTime[] creatPoints, DateTime[] contractValidPart) {
        int betweenMonth = Months.monthsBetween(contractPart[0], creatPoints[0]).getMonths();
        //时间范围内用于计算分摊金额的天数
        int daysIncom = getDayRange(usePart[0], usePart[1]) + 1;
        //区间分摊总收入
        contract.setIntervaIncomeShare(shareMultiply(dayShareIncome, new BigDecimal(daysIncom), 0));
        /*if(checkTwoTime(contractValidPart[0],usePart[1]) && checkTwoTime(usePart[0],contractValidPart[0])){
            contract.setIntervaIncomeShare(contract.getIntervaIncomeShare()+oneTimeRecognizedRevenue.setScale(0,BigDecimal.ROUND_HALF_UP).longValue());
        }*/
        if(checkTwoTime(contractValidPart[0],usePart[1]) && checkTwoTime(usePart[0],contractValidPart[0])){
            //contract.setIntervaIncomeShare(contract.getIntervaIncomeShare()+oneTimeRecognizedRevenue.setScale(0,BigDecimal.ROUND_HALF_UP).longValue());
        }else{
            contract.setOneTimeRecognizedRevenue(0.0);
        }


        Long adjustmentFund = 0L;//调整金

        boolean isLateContract = false; // 是否为晚录合同（为了兼容历史数据 此处做冗余判断）
        if (ContractStatusEnum.LATE.getKey().equals(contract.getStatus())) {
            isLateContract = true;
        }/* else if (checkLateContract(contractValidPart[0], creatPoints[0])) {
            isLateContract = true;
        }*/

        if (isLateContract) {
            contract.setStatus(ContractStatusEnum.LATE.getKey());
        }

        boolean isLater = true;
        if (!isLateContract || betweenMonth < 1) {
            //非合同晚录
            contract.setAdjustmentFund(0L);
            contract.setIncomeShareAll(contract.getIntervaIncomeShare());
            isLater = false;


        } else if (selected[1].isBefore(creatPoints[1])) {
            //录入月1号之前 调整金为 0 分摊为 0
            contract.setIntervaIncomeShare(0L);
            contract.setAdjustmentFund(0L);
            contract.setIncomeShareAll(contract.getIntervaIncomeShare());
            contract.setOneTimeRecognizedRevenue(0.0);
            contract.setStatus(ContractStatusEnum.LATE.getKey());
        } else {
            contract.setStatus(ContractStatusEnum.LATE.getKey());
            //合同晚录
            //所选时间范围内的分摊收入(录入月1号 即creatPoints[1] 开始计算)
            DateTime useStart = creatPoints[1].compareTo(selected[0]) >= 0 ? creatPoints[1] : selected[0];
            daysIncom = getDayRange(useStart, usePart[1]) + 1;

            contract.setIntervaIncomeShare(shareMultiply(dayShareIncome, new BigDecimal(daysIncom), 0));
            /*if(checkTwoTime(contractValidPart[0],usePart[1]) && checkTwoTime(useStart,contractValidPart[0])){
                contract.setIntervaIncomeShare(contract.getIntervaIncomeShare()+oneTimeRecognizedRevenue.setScale(0,BigDecimal.ROUND_HALF_UP).longValue());
            }*/

            adjustmentFund = shareMultiply(dayShareIncome, new BigDecimal(getDayRange(contractValidPart[0], creatPoints[1].plusDays(-1)) + 1), 0);

            adjustmentFund+=oneTimeRecognizedRevenue.multiply(new BigDecimal("100")).setScale(0,BigDecimal.ROUND_HALF_UP).longValue();
            if (checkTwoTime(selected[0], creatPoints[1]) && checkTwoTime(creatPoints[1], selected[1])) {
                //所选时间范围包含 录入月 1 号 显示统计的调整金
                contract.setAdjustmentFund(adjustmentFund);
            } else {
                contract.setAdjustmentFund(0L);
            }
        }

        if (checkTwoTime(selected[0], contractValidPart[1]) && checkTwoTime(contractValidPart[1], selected[1])) {
            contract.setIncomeGross(shareMultiply(new BigDecimal(getDayRange(contractValidPart[0], contractValidPart[1]) + 1), dayShareIncome, 0));
            contract.setIncomeGross(contract.getIncomeGross()+oneTimeRecognizedRevenue.setScale(0,BigDecimal.ROUND_HALF_UP).longValue());
        } else {
            contract.setIncomeGross(shareMultiply(new BigDecimal(getDayRange(contractValidPart[0], selected[1]) + 1), dayShareIncome, 0));
            if(checkTwoTime(contractValidPart[0],selected[1])){
                contract.setIncomeGross(contract.getIncomeGross()+oneTimeRecognizedRevenue.setScale(0,BigDecimal.ROUND_HALF_UP).longValue());
            }
        }

        if (checkTwoTime(contractValidPart[1], selected[1])) {
            //最后一日分摊金计算处理
            Long lastDay;
            if (isLater) {


                lastDay = contract.getIncomeExcludingTax() - adjustmentFund
                        - shareMultiply(dayShareIncome, new BigDecimal(getDayRange(creatPoints[1], contractValidPart[1])), 0);
            } else {
                lastDay = contract.getIncomeExcludingTax() - adjustmentFund
                        - shareMultiply(dayShareIncome, new BigDecimal(getDayRange(contractValidPart[0], contractValidPart[1])), 0);
            }

            //最后一日 或 包含最后一日 时
            contract.setIntervaIncomeShare(contract.getIntervaIncomeShare() -
                    dayShareIncome.setScale(0, BigDecimal.ROUND_HALF_UP).longValue() + lastDay);

        }
        Double v = contract.getOneTimeRecognizedRevenue() * 100L;
        contract.setIncomeShareAll(contract.getIntervaIncomeShare() + contract.getAdjustmentFund() + v.longValue());
    }

    private Contract suspendShareCAS(Contract contract, BigDecimal oneTimeRecognizedRevenue, int contractAllDay, BigDecimal dayShareIncome, DateTime[] contractPart, DateTime[] usePart, DateTime[] selected, DateTime[] contractValidPart) {
        if (!ContractStatusEnum.SUSPEND.getKey().equals(contract.getStatus())) {
            return null;
        }

        ContractChange contractChange = contractChangeRepository.findByContentCode(ContractStatusEnum.SUSPEND.getValue(),
                contract.getContractCode());

        if (contractChange == null) {
            contract.setAdjustmentFund(0L);
            contract.setIntervaIncomeShare(0L);
            contract.setIncomeShareAll(0L);
            return contract;
        }
        // 合同终止日 或 作废日
        DateTime cancelDate = new DateTime(contractChange.getDs());

        //中止操作入库时间
        DateTime suspendDate = new DateTime(new DateTime(contractChange.getCreateTime()).toString("yyyy-MM-dd"));

        Long adjustmentFund = 0L;
        if (checkTwoTime(suspendDate, cancelDate)) {
            adjustmentFund = 0L;
        } else {
            adjustmentFund = shareMultiply(new BigDecimal((getDayRange(cancelDate, suspendDate) + 1) * -1), dayShareIncome, 0);
            if(checkTwoTime(contractValidPart[0],suspendDate) && checkTwoTime(cancelDate,contractValidPart[0])){
                adjustmentFund+=oneTimeRecognizedRevenue.multiply(new BigDecimal("100")).setScale(0,BigDecimal.ROUND_HALF_UP).longValue();
            }else{
                contract.setOneTimeRecognizedRevenue(0.0);
            }
        }

        DateTime usedEnd = usePart[1].compareTo(cancelDate) <= 0 ? usePart[1] : cancelDate;
        int daysIncom = Days.daysBetween(usePart[0], usedEnd).getDays() + 1;
        daysIncom = daysIncom < 0 ? 0 : daysIncom;

        //区间分摊总收入
        contract.setIntervaIncomeShare(shareMultiply(dayShareIncome, new BigDecimal(daysIncom), 0));
        /*if(checkTwoTime(contractValidPart[0],usedEnd) && checkTwoTime(usePart[0],contractValidPart[0])){
            contract.setIntervaIncomeShare(contract.getIntervaIncomeShare()+oneTimeRecognizedRevenue.setScale(BigDecimal.ROUND_HALF_UP).longValue());
        }*/
        if(checkTwoTime(contractValidPart[0],usedEnd) && checkTwoTime(usePart[0],contractValidPart[0])){
        }else{
            contract.setOneTimeRecognizedRevenue(0.0);
        }

        if (checkTwoTime(selected[0], cancelDate) && checkTwoTime(cancelDate, selected[1])) {
            contract.setAdjustmentFund(adjustmentFund);
            contract.setIncomeGross(shareMultiply(new BigDecimal(getDayRange(contractValidPart[0], cancelDate) + 1), dayShareIncome, 0));
            if(checkTwoTime(contractValidPart[0],cancelDate) && checkTwoTime(contractPart[0],contractValidPart[0])){
                contract.setIncomeGross(contract.getIntervaIncomeShare()+oneTimeRecognizedRevenue.setScale(0,BigDecimal.ROUND_HALF_UP).longValue());
            }
        } else {
            contract.setAdjustmentFund(0L);
            contract.setIncomeGross(shareMultiply(new BigDecimal(getDayRange(contractValidPart[0], selected[1]) + 1), dayShareIncome, 0));
            if(checkTwoTime(contractValidPart[0],cancelDate) && checkTwoTime(contractPart[0],contractValidPart[0])){
                contract.setIncomeGross(contract.getIntervaIncomeShare()+oneTimeRecognizedRevenue.setScale(0,BigDecimal.ROUND_HALF_UP).longValue());
            }
        }

        Double v = contract.getOneTimeRecognizedRevenue() * 100L;
        contract.setIncomeShareAll(contract.getIntervaIncomeShare() + contract.getAdjustmentFund() + v.longValue());

        return contract;
    }

    private Contract cancledShareCAS(Contract contract, BigDecimal oneTimeRecognizedRevenue, int contractAllDay, BigDecimal dayShareIncome, DateTime[] contractPart, DateTime[] usePart, DateTime[] selected, DateTime[] contractValidPart) {
        if (!ContractStatusEnum.CANCEL.getKey().equals(contract.getStatus())) {
            return null;
        }
        ContractChange contractChange = contractChangeRepository.findByContentCode(ContractStatusEnum.CANCEL.getValue(), contract.getContractCode());

        if (contractChange == null) {
            contract.setAdjustmentFund(0L);
            contract.setIntervaIncomeShare(0L);
            contract.setIncomeShareAll(0L);
            return contract;
        }

        // 合同终止日 或 作废日
        DateTime cancelDate = new DateTime(contractChange.getDs());
        Long adjustmentFund = shareMultiply(new BigDecimal((getDayRange(contractValidPart[0], cancelDate) + 1) * -1), dayShareIncome, 0);

        adjustmentFund-=oneTimeRecognizedRevenue.multiply(new BigDecimal("100")).setScale(0,BigDecimal.ROUND_HALF_UP).longValue();
        if(checkTwoTime(contractValidPart[0],selected[1]) && checkTwoTime(selected[0],contractValidPart[0])){
        }else{
            contract.setOneTimeRecognizedRevenue(0.0);
        }

        DateTime usedEnd = usePart[1].compareTo(cancelDate) <= 0 ? usePart[1] : cancelDate;

        int daysIncom = Days.daysBetween(usePart[0], usedEnd).getDays() + 1;
        daysIncom = daysIncom < 0 ? 0 : daysIncom;

        contract.setIntervalUseDays(getDayRange(contractValidPart[0], usedEnd) + 1);
        //区间分摊总收入

        contract.setIntervaIncomeShare(shareMultiply(dayShareIncome, new BigDecimal(daysIncom), 0));

        if (checkTwoTime(selected[0], cancelDate) && checkTwoTime(cancelDate, selected[1])) {
            contract.setAdjustmentFund(adjustmentFund);
        } else {
            contract.setAdjustmentFund(0L);
        }
        contract.setIncomeGross(0L);
        Double v = contract.getOneTimeRecognizedRevenue() * 100L;
        contract.setIncomeShareAll(contract.getIntervaIncomeShare() + contract.getAdjustmentFund() + v.longValue());
        return contract;
    }

    /**
     * 功能描述:增加补充协议的逻辑
     * @author liyin
     * @date 2020/11/5
     */
    private void shareIncome4ContractTKIO_2(List<Contract> contracts, DateTime start, DateTime end) {
        Multimap<String, Contract> multimap = ArrayListMultimap.create();
        //查出所有报表->进行代码分组，按照email分组  计算
        try (Stream<Contract> streamContract = contracts.parallelStream()) {
            streamContract.forEachOrdered(v -> {
                if(!StringUtil.isEmpty(v.getEmail())){
                    multimap.put(v.getEmail(),v);
                }else{
                    if(v.getPriceLevel()== Constant.tkioPriceLevelNotLimit){
                        int contractAllDay = getDayRange(new DateTime(v.getStartDate()), new DateTime(v.getEndDate())) + 1;//合同总天数
                        v.setUnitPrice(new BigDecimal(v.getMoney()/1.06/contractAllDay).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
                    }else{
                        v.setUnitPrice(new BigDecimal(v.getMoney() / 1.06 /v.getTrackFlow())
                                .setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
                    }
                    v.setClickFlow(0.0);
                    v.setAdjustmentFund(0L);
                    if(checkTwoTime(new DateTime(v.getEndDate()),end)||checkTwoTime(start,new DateTime(v.getEndDate()))){
                        v.setIntervaIncomeShare(new BigDecimal(v.getMoney()/1.06*100).setScale(0, BigDecimal.ROUND_HALF_UP).longValue());
                        v.setIncomeGross(v.getIntervaIncomeShare());
                        v.setIncomeShareAll(v.getIntervaIncomeShare());
                    }
                }
            });
        }
        //遍历map，找出主合同，注：补充协议不能与补充协议互相绑定
        Set<String> emails = multimap.keySet();
        for (String email : emails) {
            //开始处理
            Collection<Contract> groupContracts = multimap.get(email);
            HashMap<String, Contract> map = new HashMap<>();
            //处理查询区间内只有补充协议没有主合同的情况
            for (Contract groupContract : groupContracts) {
                map.put(groupContract.getContractCode(),groupContract);
            }
            for (Contract groupContract : groupContracts) {
                if("2".equals(groupContract.getContractType())){
                    Contract contract = map.get(groupContract.getRelationCode());//补充协议查找map内是否有他的主合同(首次/续约)
                    if(contract==null){
                        //查出该补充协议之前签订的所有关联的合同(首次/续约-补充协议)
                        List<Contract> contractList = contractRepository.findByCreateTimeAndCodeNotOwn(groupContract.getRelationCode(),DateUtil.format(groupContract.getCreateTime(),DateUtil.C_TIME_PATTON_DEFAULT),groupContract.getId());
                        for (Contract contract1 : contractList) {
                            map.put(contract1.getContractCode(),contract1);
                        }
                        groupContracts = map.values();//只要不加入传进来的那个list里面就不会影响查询的列表
                    }
                }
            }


            //再次进行合同的关系分组--->master
            List<ContractVO> contractVOs = new ArrayList<>();
            for (Contract contract : groupContracts) {
                if(!"2".equals(contract.getContractType())){
                    ContractVO contractVO = new ContractVO();
                    contractVO.setMaster(contract);
                    contractVOs.add(contractVO);
                }
            }
            //再次进行合同的关系分组--->sideLette
            for (ContractVO contractVO : contractVOs) {
                for (Contract contract : groupContracts) {
                    if("2".equals(contract.getContractType()) && contractVO.getMaster().getContractCode().equals(contract.getRelationCode())){
                        List<Contract> sideLette = contractVO.getSideLette();
                        if(sideLette==null){
                            sideLette = new ArrayList<>();
                        }
                        sideLette.add(contract);
                        contractVO.setSideLette(sideLette);
                    }
                }
            }
            //1个合同<----->多个合同
            //1个合同->走普通的，走tkio逻辑
            for (ContractVO contractVO : contractVOs) {
                if(CollectionUtils.isEmpty(contractVO.getSideLette())){//1个合同
                    Contract master = contractVO.getMaster();
                    if(master.getPriceLevel()== Constant.tkioPriceLevelNotLimit){//无限流量走adi计算逻辑
                        shareIncome4Contract(master,start,end);
                    }else{//普通流量走tkio计算逻辑
                        shareIncome4ContractTKIO(master,start,end,false);
                    }
                }else{//该首次签约/续约合同 绑定了补充协议合同
                    List<Contract> sideLette = contractVO.getSideLette();
                    /*Boolean isNotLimit = false;
                    for (Contract contract : sideLette) {
                        if(contract.getPriceLevel()==Constant.tkioPriceLevelNotLimit){
                            isNotLimit = true;
                        }
                    }*/
                    //补充协议按照录入时间排序->从后到前，从大到小反推计算合同
                    sideLette.add(contractVO.getMaster());
                    Contract[] contractsArray = orderByCreateTime(sideLette);

                    for (int j = 0; j < contractsArray.length; j++){ //计算除了最后一个的每个合同历史所用流量

                        boolean isLateContract = false; // 是否为晚录合同（为了兼容历史数据 此处做冗余判断）
                        if (ContractStatusEnum.LATE.getKey().equals(contractsArray[j].getStatus())) {
                            isLateContract = true;
                        } else if (checkLateContract(new DateTime(contractsArray[j].getSignedDate()==null?contractsArray[j].getStartDate():contractsArray[j].getSignedDate()), new DateTime(new DateTime(contractsArray[j].getCreateTime()).toString("yyyy-MM-dd")))) {
                            isLateContract = true;
                            contractsArray[j].setStatus(ContractStatusEnum.LATE.getKey());
                        }

                        String startDate = null;
                        if(isLateContract && j>0) {//补充协议晚录
                            startDate = new DateTime(contractsArray[j].getCreateTime()).dayOfMonth().withMinimumValue().toString("yyyy-MM-dd");
                        }else {
                            startDate = contractsArray[j].getSignedDate()==null?contractsArray[j].getStartDate():contractsArray[j].getSignedDate();
                        }
                        String endDate = contractsArray[j].getNextSignedDate() == null ? contractsArray[j].getEndDate() : contractsArray[j].getNextSignedDate();
                        ArrayList<String> codes = new ArrayList<>();
                        for (int k = 0; k <= j; k++) {
                            codes.add(contractsArray[k].getContractCode());
                        }
                        BigDecimal flow = tkioFlowRepository.sumFlowByDsAndContractCodes(startDate,endDate,codes);
                        double i1 = flow == null ? 0 : flow.divide(new BigDecimal(10000.0)).setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue();

                        if(j>0){//上一份合同超出的流量算在当前合同上(肯定在签订日之前)合同的开始日(补充协议的开始日就是原合同的开始日，结束日为上一个合同的下一个签订日)
                            BigDecimal bigDecimal = tkioFlowRepository.sumFlowByContractCodeAndDs(contractsArray[j].getContractCode(), contractsArray[j].getStartDate(), contractsArray[j - 1].getNextSignedDate());
                            double i = bigDecimal == null ? 0 : bigDecimal.divide(new BigDecimal(10000.0)).setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue();
                            i1+=i;
                        }
                        contractsArray[j].setHistoryTkioFlow(i1);
                    }

                    //补充协议核心逻辑
                    //能运行到这里说明只有补充协议才会出现无限流量（最后一个），如果是主合同无限流量，就不可能有补充协议
                        for (int i = 0; i < contractsArray.length; i++) {
                            if(i>0){
                                Contract contract = contractsArray[i];
                                if(contracts.contains(contract)){
                                    //计算当前单价

                                        double totalFlow = 0;
                                        double totalprice = 0.0;
                                        double accruingFlow = 0;
                                        double accruingAmounts = 0.0;

                                        for (int j = 0; j < i; j++) {
                                            totalFlow+=contractsArray[j].getTrackFlow();

                                            totalprice+=new BigDecimal(contractsArray[j].getMoney()/1.06).setScale(16, BigDecimal.ROUND_HALF_UP).doubleValue();
                                            double currentFlow = totalFlow-accruingFlow;
                                            double currentMoney = totalprice-accruingAmounts;

                                            contractsArray[j].setUnitPriceAccurate(new BigDecimal(currentMoney  / currentFlow)
                                                    .setScale(16, BigDecimal.ROUND_HALF_UP));//存储16位单价

                                            accruingAmounts+= new BigDecimal(currentMoney/currentFlow*contractsArray[j].getHistoryTkioFlow())
                                                    .setScale(16, BigDecimal.ROUND_HALF_UP).doubleValue();//当前合同之前的累计消耗金额
                                            accruingFlow+=contractsArray[j].getHistoryTkioFlow();//当前合同之前的累计消耗流量，万单位
                                        }
                                        totalFlow=totalFlow-accruingFlow<0?0:totalFlow-accruingFlow;
                                        totalFlow=totalFlow+contract.getTrackFlow();
                                        totalprice = totalprice-accruingAmounts<0?0:totalprice-accruingAmounts;
                                        totalprice=totalprice+new BigDecimal(contract.getMoney()/1.06).setScale(16, BigDecimal.ROUND_HALF_UP).doubleValue();

                                        contract.setIncomeExcludingTax(new BigDecimal(totalprice)
                                                .setScale(2, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100L)).longValue());
                                        BigDecimal unitPriceAccurate =null;
                                        if(!contract.getPriceLevel().equals(Constant.tkioPriceLevelNotLimit)){
                                        unitPriceAccurate = new BigDecimal(totalprice/totalFlow)
                                                .setScale(16, BigDecimal.ROUND_HALF_UP);//当前合同的单价
                                        //四舍五入单价
                                        double unitPrice = unitPriceAccurate.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
                                        contract.setUnitPrice(unitPrice);
                                    }
                                        boolean isLateContract = false; // 是否为晚录合同（为了兼容历史数据 此处做冗余判断）
                                        if (ContractStatusEnum.LATE.getKey().equals(contract.getStatus())) {
                                            isLateContract = true;
                                        } else if (checkLateContract(new DateTime(contract.getSignedDate()==null?contract.getStartDate():contract.getSignedDate()), new DateTime(new DateTime(contract.getCreateTime()).toString("yyyy-MM-dd")))) {
                                            isLateContract = true;
                                            contract.setStatus(ContractStatusEnum.LATE.getKey());
                                        }

                                        //正常查流量
                                        DateTime[] selected = {start,end};//用户筛选日期区间
                                        DateTime[] contractPart = new DateTime[]{
                                                new DateTime(contract.getSignedDate()),
                                                new DateTime(contract.getNextSignedDate()==null?contract.getEndDate():contract.getNextSignedDate())};//合同开始结束（下一份合同签订日前一天） 时间
                                        DateTime[] usePart = new DateTime[]{
                                                selected[0].compareTo(contractPart[0]) <= 0 ? contractPart[0] : selected[0],
                                                selected[1].compareTo(contractPart[1]) >= 0 ? contractPart[1] : selected[1]
                                        };
                                        usePart[0] = usePart[0].compareTo(usePart[1]) >= 0 ? usePart[1] : usePart[0];

                                        DateTime create = new DateTime(new DateTime(contract.getCreateTime()).toString("yyyy-MM-dd")); //录入时间点
                                        DateTime[] creatPoints = new DateTime[]{
                                                create, //录入日
                                                create.dayOfMonth().withMinimumValue() //录入月1日
                                        };
                                    if(selected[1].isBefore(contractPart[0])){
                                        contract.setUnitPrice(0.0);
                                        contract.setIntervaIncomeShare(0L);
                                        contract.setAdjustmentFund(0L);
                                        contract.setIncomeShareAll(contract.getIntervaIncomeShare());
                                        contract.setClickFlow(0.0);
                                        contract.setIncomeGross(0L);
                                        contracts.remove(contract);//移出列表
                                    }else
                                    if(!contract.getPriceLevel().equals(Constant.tkioPriceLevelNotLimit)){
                                        boolean isLater = true;
                                        if(!isLateContract){//正常合同
                                            //补充协议的开始时间和结束时间是与主合同时间一致的，所以需要按照补充协议的字段再次判断补充协议是否在区间选择内
                                            if(selected[0].compareTo(contractPart[1]) > 0 || selected[1].compareTo(contractPart[0]) < 0) {
                                                contract.setIntervaIncomeShare(0L);
                                                contract.setAdjustmentFund(0L);
                                                contract.setIncomeShareAll(contract.getIntervaIncomeShare());
                                                contract.setClickFlow(0.0);
                                                contract.setIncomeGross(0L);
                                            }else{
                                                ArrayList<String> codes = new ArrayList<>();
                                                for (int k = 0; k <= i; k++) {
                                                    codes.add(contractsArray[k].getContractCode());
                                                }
                                                contract.setClickFlow(0.0);
                                                BigDecimal clickNum = tkioFlowRepository.sumFlowByDsAndContractCodes(usePart[0].toString("yyyy-MM-dd"), usePart[1].toString("yyyy-MM-dd"), codes);
                                                long clickFlow = clickNum == null ? 0L : clickNum.longValue();
                                                BigDecimal clickTenThousand = new BigDecimal(0);
                                                if (clickFlow != 0) {
                                                    clickTenThousand = new BigDecimal(clickFlow / 10000.0 * 100);
                                                    //区间点击数
                                                    contract.setClickFlow(new BigDecimal(clickFlow / 10000.0).setScale(4, BigDecimal.ROUND_HALF_UP).doubleValue());
                                                }
                                                //区间分摊收入
                                                contract.setIntervaIncomeShare(unitPriceAccurate.multiply(clickTenThousand).setScale(0, BigDecimal.ROUND_HALF_UP).longValue());
                                                //调整金，正常情况下可能存在之前合同超出的流量所产生的调整金(记录在签订日）
                                                BigDecimal beforSigndFlow = null;
                                                if (checkTwoTime(selected[0], contractPart[0]) && checkTwoTime(contractPart[1], selected[0])) {
                                                    DateTime startDate = new DateTime(contract.getStartDate());
                                                    DateTime endDate = contractPart[0].plusDays(-1);//签约日前一天
                                                    beforSigndFlow = tkioFlowRepository.sumFlowByContractCodeAndDs(contract.getContractCode(), startDate.toString("yyyy-MM-dd"), endDate.toString("yyyy-MM-dd"));
                                                    beforSigndFlow = beforSigndFlow == null ? new BigDecimal(0) : beforSigndFlow;
                                                    BigDecimal beforSigndAdjustmentFund = beforSigndFlow.divide(new BigDecimal(10000.0 / 100)).multiply(unitPriceAccurate);
                                                    contract.setAdjustmentFund(beforSigndAdjustmentFund.setScale(0, BigDecimal.ROUND_HALF_UP).longValue());
                                                } else {
                                                    contract.setAdjustmentFund(0L);
                                                }

                                                contract.setIncomeShareAll(contract.getIntervaIncomeShare());

                                                //todo 累计总收入，还得算上签订日之前的流量
                                                clickNum = tkioFlowRepository.sumFlowByDsAndContractCodes(contractPart[0].toString("yyyy-MM-dd"), usePart[1].toString("yyyy-MM-dd"), codes);
                                                clickFlow = clickNum == null ? 0L : clickNum.longValue();
                                                if (beforSigndFlow != null) {
                                                    clickFlow += beforSigndFlow.intValue();
                                                }
                                                contract.setIncomeGross(unitPriceAccurate.multiply(new BigDecimal(clickFlow / 10000.0 * 100)).setScale(0, BigDecimal.ROUND_HALF_UP).longValue());
                                            }
                                            isLater = false;
                                        } else if (selected[1].isBefore(creatPoints[1])) {
                                            //录入月1号之前 所有调整金为 0 分摊为 0
                                            contract.setIntervaIncomeShare(0L);
                                            contract.setAdjustmentFund(0L);
                                            contract.setIncomeShareAll(contract.getIntervaIncomeShare());
                                            contract.setClickFlow(0.0);
                                            contract.setIncomeGross(0L);
                                            contract.setStatus(ContractStatusEnum.LATE.getKey());
                                        }else{
                                            contract.setStatus(ContractStatusEnum.LATE.getKey());
                                            //合同晚录
                                            //所选时间范围内的分摊收入(录入月1号 即creatPoints[1] 开始计算)
                                            DateTime useStart = creatPoints[1].compareTo(selected[0]) >= 0 ? creatPoints[1] : selected[0];
                                            ArrayList<String> codes = new ArrayList<>();
                                            for (int k = 0; k <= i; k++) {
                                                codes.add(contractsArray[k].getContractCode());
                                            }
                                            BigDecimal clickNum = tkioFlowRepository.sumFlowByDsAndContractCodes(useStart.toString("yyyy-MM-dd"), usePart[1].toString("yyyy-MM-dd"), codes);
                                            long clickFlow = clickNum==null?0L:clickNum.longValue();
                                            BigDecimal clickTenThousand = new BigDecimal(0);

                                            if(clickFlow!=0){
                                                clickTenThousand = new BigDecimal(clickFlow / 10000.0 * 100);
                                                //区间点击数
                                                contract.setClickFlow(new BigDecimal(clickFlow / 10000.0).setScale(4,BigDecimal.ROUND_HALF_UP).doubleValue());
                                            }
                                            BigDecimal beforSigndFlow = null;
                                            //区间分摊收入
                                            contract.setIntervaIncomeShare(unitPriceAccurate.multiply(clickTenThousand).setScale(0, BigDecimal.ROUND_HALF_UP).longValue());
                                            if (checkTwoTime(selected[0], creatPoints[1]) && checkTwoTime(creatPoints[1], selected[1])) {
                                                //所选时间范围包含 录入月 1 号 显示统计的调整金
                                                //合同开始日期，合同录入日期的一号，-1就是上个月最后一天
                                                //contractPart[0], creatPoints[1].plusDays(-1)
                                                //晚录调整金
                                                clickNum = tkioFlowRepository.sumFlowByDsAndContractCodes(contractPart[0].toString("yyyy-MM-dd"), creatPoints[1].plusDays(-1).toString("yyyy-MM-dd"), codes);
                                                clickFlow = clickNum==null?0L:clickNum.longValue();
                                                clickTenThousand = new BigDecimal(0);
                                                if(clickFlow!=0){
                                                    clickTenThousand = new BigDecimal(clickFlow / 10000.0 * 100);
                                                }
                                                contract.setAdjustmentFund(unitPriceAccurate.multiply(clickTenThousand).setScale(0, BigDecimal.ROUND_HALF_UP).longValue());
                                                //超出流量调整金
                                                if (checkTwoTime(selected[0], contractPart[0]) && checkTwoTime(contractPart[1], selected[0])) {
                                                    DateTime startDate = new DateTime(contract.getStartDate());
                                                    DateTime endDate = creatPoints[1].plusDays(-1);//签约录入日前一天
                                                    beforSigndFlow = tkioFlowRepository.sumFlowByContractCodeAndDs(contract.getContractCode(), startDate.toString("yyyy-MM-dd"), endDate.toString("yyyy-MM-dd"));
                                                    beforSigndFlow = beforSigndFlow == null ? new BigDecimal(0) : beforSigndFlow;
                                                    BigDecimal beforSigndAdjustmentFund = beforSigndFlow.divide(new BigDecimal(10000.0 / 100)).multiply(unitPriceAccurate);
                                                    contract.setAdjustmentFund(contract.getAdjustmentFund()+beforSigndAdjustmentFund.setScale(0, BigDecimal.ROUND_HALF_UP).longValue());
                                                }
                                                //处理上一个合同的调整金
                                                if(i>0){
                                                    contractsArray[i-1].setAdjustmentFund(contractsArray[i-1].getAdjustmentFund()-contractsArray[i-1].getUnitPriceAccurate().multiply(clickTenThousand).setScale(0, BigDecimal.ROUND_HALF_UP).longValue());
                                                }

                                            } else {
                                                contract.setAdjustmentFund(0L);
                                            }

                                            //累计总收入
                                            clickNum = tkioFlowRepository.sumFlowByDsAndContractCodes(contractPart[0].toString("yyyy-MM-dd"), usePart[1].toString("yyyy-MM-dd"), codes);
                                            clickFlow = clickNum == null ? 0L : clickNum.longValue();
                                            if (beforSigndFlow != null) {
                                                clickFlow += beforSigndFlow.intValue();
                                            }
                                            contract.setIncomeGross(unitPriceAccurate.multiply(new BigDecimal(clickFlow / 10000.0 * 100)).setScale(0, BigDecimal.ROUND_HALF_UP).longValue());
                                        }

                                        //判断合同真实结束日期之前判断该合同有没有下一份合同
                                        if (contract.getNextSignedContractCode()==null&&checkTwoTime(contractPart[1], selected[1])) {
                                            //最后一日分摊收入计算处理(合同的最后一天，不管流量剩余多少，都算作做最后一天的收入)
                                            Long lastDay;
                                            DateTime lastDate[];
                                            if (isLater) {
                                                lastDate = new  DateTime[]{creatPoints[1],contractPart[1].plusDays(-1)};
                                            } else {
                                                lastDate = new  DateTime[]{contractPart[0],contractPart[1].plusDays(-1)};
                                            }
                                            //合同除去最后一天的流量
                                            ArrayList<String> codes = new ArrayList<>();
                                            for (int k = 0; k <= i; k++) {
                                                codes.add(contractsArray[k].getContractCode());
                                            }
                                            BigDecimal clickNum = tkioFlowRepository.sumFlowByDsAndContractCodes(lastDate[0].toString("yyyy-MM-dd"), lastDate[1].toString("yyyy-MM-dd"), codes);
                                            long clickFlow = clickNum==null?0L:clickNum.longValue();
                                            BigDecimal clickTenThousand = new BigDecimal(0);
                                            if(clickFlow!=0){
                                                clickTenThousand = new BigDecimal(clickFlow / 10000.0 * 100);
                                            }
                                            long beforeTheMoney = unitPriceAccurate.multiply(clickTenThousand).setScale(0, BigDecimal.ROUND_HALF_UP).longValue();

                                            //最后一天的流量
                                            clickNum = tkioFlowRepository.sumFlowByDsAndContractCodes(contractPart[1].toString("yyyy-MM-dd"), contractPart[1].toString("yyyy-MM-dd"), codes);
                                            clickFlow = clickNum==null?0L:clickNum.longValue();
                                            clickTenThousand = new BigDecimal(0);
                                            if(clickFlow!=0)clickTenThousand = new BigDecimal(clickFlow / 10000.0 * 100);
                                            long lastDayTheMoney = unitPriceAccurate.multiply(clickTenThousand).setScale(0, BigDecimal.ROUND_HALF_UP).longValue();
                                            //合同的税后总金额减去最后合同一日之前的钱和调整金
                                            long excludTax = new BigDecimal(totalprice)
                                                    .setScale(2, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100L)).longValue();
                                            //TODO 超出的流量算在了调整金了这里好像减去了
                                            lastDay = excludTax - contract.getAdjustmentFund() - beforeTheMoney;
                                            //最后一日 或 包含最后一日 时
                                            contract.setIntervaIncomeShare(contract.getIntervaIncomeShare() - lastDayTheMoney + lastDay);
                                            contract.setIncomeGross(contract.getIncomeGross() - lastDayTheMoney + lastDay);
                                        }

                                        contract.setIncomeShareAll(contract.getIntervaIncomeShare() + contract.getAdjustmentFund());
                                    }else{//不限量套餐
                                        int contractAllDay = getDayRange(contractPart[0], contractPart[1]) + 1;//合同总天数
                                        BigDecimal dayShareIncome = new BigDecimal(totalprice/contractAllDay)
                                                .setScale(16, BigDecimal.ROUND_HALF_UP);

                                        contract.setUnitPrice(dayShareIncome.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());//设置不限量套餐的单价
                                        int betweenMonth = Months.monthsBetween(contractPart[0], creatPoints[0]).getMonths();
                                        //时间范围内用于计算分摊金额的天数
                                        int daysIncom = getDayRange(usePart[0], usePart[1]) + 1;
                                        //区间分摊总收入
                                        contract.setIntervaIncomeShare(shareMultiply(dayShareIncome.multiply(new BigDecimal(100L)), new BigDecimal(daysIncom), 0));

                                        //无限流量套餐合同的区间点击数
                                        ArrayList<String> codes = new ArrayList<>();
                                        for (int k = 0; k <= i; k++) {
                                            codes.add(contractsArray[k].getContractCode());
                                        }
                                        BigDecimal clickNumLimit = tkioFlowRepository.sumFlowByDsAndContractCodes(usePart[0].toString("yyyy-MM-dd"), usePart[1].toString("yyyy-MM-dd"), codes);
                                        long clickFlowLimit = clickNumLimit==null?0L:clickNumLimit.longValue();
                                        if(clickFlowLimit!=0){
                                            contract.setClickFlow(new BigDecimal(clickFlowLimit / 10000.0).setScale(4,BigDecimal.ROUND_HALF_UP).doubleValue());
                                        }else{
                                            contract.setClickFlow(0.0);
                                        }

                                        Long adjustmentFund = 0L;//调整金

                                        if (isLateContract) {
                                            contract.setStatus(ContractStatusEnum.LATE.getKey());
                                        }

                                        boolean isLater = true;
                                        if (!isLateContract || betweenMonth < 1) {
                                            //非合同晚录
                                            contract.setAdjustmentFund(0L);
                                            contract.setIncomeShareAll(contract.getIntervaIncomeShare());
                                            isLater = false;

                                        } else if (selected[1].isBefore(creatPoints[1])) {
                                            //录入月1号之前 调整金为 0 分摊为 0
                                            contract.setIntervaIncomeShare(0L);
                                            contract.setAdjustmentFund(0L);
                                            contract.setIncomeShareAll(contract.getIntervaIncomeShare());
                                            contract.setStatus(ContractStatusEnum.LATE.getKey());
                                        } else {
                                            contract.setStatus(ContractStatusEnum.LATE.getKey());
                                            //合同晚录
                                            //所选时间范围内的分摊收入(录入月1号 即creatPoints[1] 开始计算)
                                            DateTime useStart = creatPoints[1].compareTo(selected[0]) >= 0 ? creatPoints[1] : selected[0];
                                            daysIncom = getDayRange(useStart, usePart[1]) + 1;

                                            contract.setIntervaIncomeShare(shareMultiply(dayShareIncome.multiply(new BigDecimal(100L)), new BigDecimal(daysIncom), 0));
                                            adjustmentFund = shareMultiply(dayShareIncome.multiply(new BigDecimal(100L)), new BigDecimal(getDayRange(contractPart[0], creatPoints[1].plusDays(-1)) + 1), 0);

                                            if (checkTwoTime(selected[0], creatPoints[1]) && checkTwoTime(creatPoints[1], selected[1])) {
                                                //所选时间范围包含 录入月 1 号 显示统计的调整金
                                                contract.setAdjustmentFund(adjustmentFund);
                                            } else {
                                                contract.setAdjustmentFund(0L);
                                            }


                                            //处理上一份合同
                                            BigDecimal clickNum = tkioFlowRepository.sumFlowByDsAndContractCodes(contractPart[0].toString("yyyy-MM-dd"), creatPoints[1].plusDays(-1).toString("yyyy-MM-dd"), codes);
                                            long clickFlow = clickNum==null?0L:clickNum.longValue();
                                            BigDecimal clickTenThousand = new BigDecimal(0);
                                            if(clickFlow!=0){
                                                clickTenThousand = new BigDecimal(clickFlow / 10000.0 * 100);
                                            }
                                            if(i>0){
                                                contractsArray[i-1].setAdjustmentFund(contractsArray[i-1].getAdjustmentFund()-contractsArray[i-1].getUnitPriceAccurate().multiply(clickTenThousand).setScale(0, BigDecimal.ROUND_HALF_UP).longValue());
                                            }
                                        }

                                        if (checkTwoTime(selected[0], contractPart[1]) && checkTwoTime(contractPart[1], selected[1])) {
                                            contract.setIncomeGross(shareMultiply( dayShareIncome.multiply(new BigDecimal(100L)),new BigDecimal(getDayRange(contractPart[0], contractPart[1]) + 1), 0));
                                        } else {
                                            contract.setIncomeGross(shareMultiply( dayShareIncome.multiply(new BigDecimal(100L)),new BigDecimal(getDayRange(contractPart[0], selected[1]) + 1), 0));
                                        }

                                        if (checkTwoTime(contractPart[1], selected[1])) {
                                            //最后一日分摊金计算处理
                                            Long lastDay;
                                            if (isLater) {
                                                lastDay = contract.getIncomeExcludingTax() - adjustmentFund
                                                        - shareMultiply(dayShareIncome.multiply(new BigDecimal(100L)), new BigDecimal(getDayRange(creatPoints[1], contractPart[1])), 0);
                                            } else {
                                                lastDay = contract.getIncomeExcludingTax() - adjustmentFund
                                                        - shareMultiply(dayShareIncome.multiply(new BigDecimal(100L)), new BigDecimal(getDayRange(contractPart[0], contractPart[1])), 0);
                                            }
                                            //最后一日 或 包含最后一日 时
                                            contract.setIntervaIncomeShare(contract.getIntervaIncomeShare() -
                                                    dayShareIncome.multiply(new BigDecimal(100L)).setScale(0, BigDecimal.ROUND_HALF_UP).longValue() + lastDay);
                                            contract.setIncomeGross(contract.getIncomeGross()-dayShareIncome.multiply(new BigDecimal(100L)).setScale(0, BigDecimal.ROUND_HALF_UP).longValue() + lastDay);

                                        }

                                        contract.setIncomeShareAll(contract.getIntervaIncomeShare() + contract.getAdjustmentFund());


                                    }
                                }
                            }else{
                                Contract contractMaster = contractsArray[i];
                                if(contracts.contains(contractMaster)){
                                    String endDate = contractMaster.getEndDate();
                                    contractMaster.setEndDate(contractMaster.getNextSignedDate());
                                    shareIncome4ContractTKIO(contractMaster,start,end,true);//到结束的前一天
                                    contractMaster.setEndDate(endDate);
                                }
                            }
                        }
                }
            }

        }
    }


    public Contract[] orderByCreateTime(List<Contract> contracts){//从小到大排序
        Contract[] contractsArray = new Contract[contracts.size()];
        contractsArray = contracts.toArray(contractsArray);
        for (int i = 0; i < contractsArray.length-1; i++) {
            for (int j = 0; j < contractsArray.length-1-i; j++) {
                if(contractsArray[j].getCreateTime().getTime() > contractsArray[j + 1].getCreateTime().getTime()){
                    Contract temp = contractsArray[j];
                    contractsArray[j] = contractsArray[j+1];
                    contractsArray[j + 1] = temp;
                }else if (contractsArray[j].getCreateTime().getTime() == contractsArray[j + 1].getCreateTime().getTime()){
                    String contractCode = StringUtil.matchNumber(contractsArray[j].getContractCode());
                    String contractCodeMin = StringUtil.matchNumber(contractsArray[j+ 1].getContractCode());
                    if(Long.valueOf(contractCode)>Long.valueOf(contractCodeMin)){
                        Contract temp = contractsArray[j];
                        contractsArray[j] = contractsArray[j+1];
                        contractsArray[j + 1] = temp;
                    }
                }
            }
        }
        return contractsArray;
    }
    private void shareIncome4ContractTKIO(Contract contract, DateTime start, DateTime end,Boolean isMore) {
        DateTime[] selected = new DateTime[]{
                start,
                end};//用户筛选开始/结束日期
        DateTime[] contractPart= new DateTime[]{
                    new DateTime(contract.getStartDate()),
                    new DateTime(contract.getEndDate())};//合同开始结束 时间
        DateTime[] usePart = new DateTime[]{
                selected[0].compareTo(contractPart[0]) <= 0 ? contractPart[0] : selected[0],
                selected[1].compareTo(contractPart[1]) >= 0 ? contractPart[1] : selected[1]
        };

        usePart[0] = usePart[0].compareTo(usePart[1]) >= 0 ? usePart[1] : usePart[0];

        Long excludTax = new BigDecimal(contract.getMoney() / 1.06)
                .setScale(2, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100L)).longValue();//不含税收入*100
        contract.setIncomeExcludingTax(excludTax);
        BigDecimal unitPriceAccurate = null;
        //计算单价,精准保留16位数
        try {
             unitPriceAccurate = new BigDecimal(contract.getMoney()/1.06/contract.getTrackFlow())
                    .setScale(16, BigDecimal.ROUND_HALF_UP);
        }catch (Exception e){
            e.printStackTrace();
        }
        //四舍五入单价
        double unitPrice = unitPriceAccurate.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
        //不限量套餐会在方法里面重新赋值单价
        contract.setUnitPrice(unitPrice);
        //作废合同  累计收入= 0
        //中止合同  累计收入= 如果中止日期在选择日期之内，【合同开始日期-中止日期】，否则【合同开始日期-选择结束日期】，不需要考虑调整金
        //晚录合同  累计收入= 同下
        //正常合同  累计收入= 如果合同结束日期在选择日期之内，则直接取 [合同金额/1.06]得到总金额 ，否则 【合同开始日期-选择结束日期】
        //作废合同处理
        Contract cancleContract = this.cancledShareFlow(contract, unitPriceAccurate, usePart,selected);
        if (cancleContract != null) {
            return;
        }
        //中止合同处理
        Contract suspendContract = this.suspendShareFlow(contract, unitPriceAccurate,contractPart, usePart, selected);
        if (suspendContract != null) {
            return;
        }

        //补充协议的主合同特殊处理
        if (isMore&&new DateTime(contract.getNextSignedDate()).isBefore(selected[0])) {
            contract.setIntervaIncomeShare(0L);
            contract.setAdjustmentFund(0L);
            contract.setIncomeShareAll(contract.getIntervaIncomeShare());
            contract.setClickFlow(0.0);
            contract.setIncomeGross(0L);
            return;
        }

        //晚录合同处理//正常合同处理
        DateTime create = new DateTime(new DateTime(contract.getCreateTime()).toString("yyyy-MM-dd")); //录入时间点
        DateTime[] creatPoints = new DateTime[]{
                create, //录入日
                create.dayOfMonth().withMinimumValue() //录入月1日
        };
        this.afterContractFlow(contract,unitPriceAccurate, contractPart, usePart, selected, creatPoints,isMore);
    }

    private void afterContractFlow(Contract contract, BigDecimal unitPriceAccurate, DateTime[] contractPart, DateTime[] usePart, DateTime[] selected, DateTime[] creatPoints, Boolean isMore) {
        Long adjustmentFund = 0L;//调整金
        contract.setClickFlow(0.0);
        boolean isLateContract = false; // 是否为晚录合同（为了兼容历史数据 此处做冗余判断）
        if (ContractStatusEnum.LATE.getKey().equals(contract.getStatus())) {
            isLateContract = true;
        }/* else if (checkLateContract(contractPart[0], creatPoints[0])) {
            isLateContract = true;
            contract.setStatus(ContractStatusEnum.LATE.getKey());
        }*/

        boolean isLater = true;
        if (!isLateContract) {
            //非合同晚录
            BigDecimal clickNum = tkioFlowRepository.sumFlowByContractCodeAndDs(contract.getContractCode(),usePart[0].toString("yyyy-MM-dd"),usePart[1].toString("yyyy-MM-dd"));
            long clickFlow = clickNum==null?0L:clickNum.longValue();
            BigDecimal clickTenThousand = new BigDecimal(0);

            if(clickFlow!=0){
                clickTenThousand = new BigDecimal(clickFlow / 10000.0 * 100);
                //区间点击数
                contract.setClickFlow(new BigDecimal(clickFlow / 10000.0).setScale(4,BigDecimal.ROUND_HALF_UP).doubleValue());
            }
            //区间分摊收入
            contract.setIntervaIncomeShare(unitPriceAccurate.multiply(clickTenThousand).setScale(0, BigDecimal.ROUND_HALF_UP).longValue());

            contract.setAdjustmentFund(0L);
            contract.setIncomeShareAll(contract.getIntervaIncomeShare());

            if(!isMore&&checkTwoTime(selected[0],contractPart[1]) && checkTwoTime(contractPart[1],selected[1])){
                contract.setIncomeGross(contract.getIncomeExcludingTax());
            }else{
                //累计总收入
                clickNum = tkioFlowRepository.sumFlowByContractCodeAndDs(contract.getContractCode(),contractPart[0].toString("yyyy-MM-dd"),usePart[1].toString("yyyy-MM-dd"));
                clickFlow = clickNum==null?0L:clickNum.longValue();
                contract.setIncomeGross(unitPriceAccurate.multiply(new BigDecimal(clickFlow / 10000.0 * 100)).setScale(0, BigDecimal.ROUND_HALF_UP).longValue());
            }
            isLater = false;
        } else if (selected[1].isBefore(creatPoints[1])) {
            //录入月1号之前 调整金为 0 分摊为 0
            contract.setIntervaIncomeShare(0L);
            contract.setAdjustmentFund(0L);
            contract.setIncomeShareAll(contract.getIntervaIncomeShare());
            BigDecimal clickNum = tkioFlowRepository.sumFlowByContractCodeAndDs(contract.getContractCode(),usePart[0].toString("yyyy-MM-dd"),usePart[1].toString("yyyy-MM-dd"));
            long clickFlow = clickNum==null?0L:clickNum.longValue();
            contract.setClickFlow(new BigDecimal(clickFlow / 10000.0).setScale(4,BigDecimal.ROUND_HALF_UP).doubleValue());
            contract.setIncomeGross(0L);
            contract.setStatus(ContractStatusEnum.LATE.getKey());
        } else {
            contract.setStatus(ContractStatusEnum.LATE.getKey());
            //合同晚录
            //所选时间范围内的分摊收入(录入月1号 即creatPoints[1] 开始计算)
            DateTime useStart = creatPoints[1].compareTo(selected[0]) >= 0 ? creatPoints[1] : selected[0];

            BigDecimal clickNum = tkioFlowRepository.sumFlowByContractCodeAndDs(contract.getContractCode(),useStart.toString("yyyy-MM-dd"),usePart[1].toString("yyyy-MM-dd"));
            long clickFlow = clickNum==null?0L:clickNum.longValue();
            BigDecimal clickTenThousand = new BigDecimal(0);

            if(clickFlow!=0){
                clickTenThousand = new BigDecimal(clickFlow / 10000.0 * 100);
                //区间点击数
                BigDecimal clickNumReal = tkioFlowRepository.sumFlowByContractCodeAndDs(contract.getContractCode(),selected[0].toString("yyyy-MM-dd"),usePart[1].toString("yyyy-MM-dd"));
                int clickNumRealFlow = clickNumReal==null?0:clickNumReal.intValue();
                contract.setClickFlow(new BigDecimal(clickNumRealFlow / 10000.0).setScale(4,BigDecimal.ROUND_HALF_UP).doubleValue());
            }
            //区间分摊收入
            contract.setIntervaIncomeShare(unitPriceAccurate.multiply(clickTenThousand).setScale(0, BigDecimal.ROUND_HALF_UP).longValue());


            if (checkTwoTime(selected[0], creatPoints[1]) && checkTwoTime(creatPoints[1], selected[1])) {
                //所选时间范围包含 录入月 1 号 显示统计的调整金
                //合同开始日期，合同录入日期的一号，-1就是上个月最后一天
                //contractPart[0], creatPoints[1].plusDays(-1)
                clickNum = tkioFlowRepository.sumFlowByContractCodeAndDs(contract.getContractCode(),contractPart[0].toString("yyyy-MM-dd"),creatPoints[1].plusDays(-1).toString("yyyy-MM-dd"));
                clickFlow = clickNum==null?0L:clickNum.longValue();
                clickTenThousand = new BigDecimal(0);
                if(clickFlow!=0){
                    clickTenThousand = new BigDecimal(clickFlow / 10000.0 * 100);
                    //区间点击数
                }
                contract.setAdjustmentFund(unitPriceAccurate.multiply(clickTenThousand).setScale(0, BigDecimal.ROUND_HALF_UP).longValue());
            } else {
                contract.setAdjustmentFund(0L);
            }

            if(checkTwoTime(selected[0],contractPart[1]) && checkTwoTime(contractPart[1],selected[1])){
                contract.setIncomeGross(contract.getIncomeExcludingTax());
            }else{
                //累计总收入
                clickNum = tkioFlowRepository.sumFlowByContractCodeAndDs(contract.getContractCode(),contractPart[0].toString("yyyy-MM-dd"),selected[1].plusDays(-1).toString("yyyy-MM-dd"));
                clickFlow = clickNum==null?0L:clickNum.longValue();
                contract.setIncomeGross(unitPriceAccurate.multiply(new BigDecimal(clickFlow / 10000.0 * 100)).setScale(0, BigDecimal.ROUND_HALF_UP).longValue());
            }
        }

        if (!isMore&&checkTwoTime(contractPart[1], selected[1])) {
            //最后一日分摊收入计算处理(合同的最后一天，不管流量剩余多少，都算作做最后一天的收入)
            Long lastDay;
            DateTime lastDate[];
            if (isLater) {
                lastDate = new  DateTime[]{creatPoints[1],contractPart[1].plusDays(-1)};
            } else {
                lastDate = new  DateTime[]{contractPart[0],contractPart[1].plusDays(-1)};
            }
            //合同除去最后一天的流量
            BigDecimal clickNum = tkioFlowRepository.sumFlowByContractCodeAndDs(contract.getContractCode(),lastDate[0].toString("yyyy-MM-dd"),lastDate[1].toString("yyyy-MM-dd"));
            long clickFlow = clickNum==null?0L:clickNum.longValue();
            BigDecimal clickTenThousand = new BigDecimal(0);
            if(clickFlow!=0){
                clickTenThousand = new BigDecimal(clickFlow / 10000.0 * 100);
            }
            long beforeTheMoney = unitPriceAccurate.multiply(clickTenThousand).setScale(0, BigDecimal.ROUND_HALF_UP).longValue();

            //最后一天的流量
            clickNum = tkioFlowRepository.sumFlowByContractCodeAndDs(contract.getContractCode(),contractPart[1].toString("yyyy-MM-dd"),contractPart[1].toString("yyyy-MM-dd"));
            clickFlow = clickNum==null?0L:clickNum.longValue();
            clickTenThousand = new BigDecimal(0);
            if(clickFlow!=0)clickTenThousand = new BigDecimal(clickFlow / 10000.0 * 100);
            long lastDayTheMoney = unitPriceAccurate.multiply(clickTenThousand).setScale(0, BigDecimal.ROUND_HALF_UP).longValue();
            //合同的税后总金额减去最后合同一日之前的钱和调整金
            lastDay = contract.getIncomeExcludingTax() - contract.getAdjustmentFund() - beforeTheMoney;
            //最后一日 或 包含最后一日 时
            contract.setIntervaIncomeShare(contract.getIntervaIncomeShare() - lastDayTheMoney + lastDay);
        }

        contract.setIncomeShareAll(contract.getIntervaIncomeShare() + contract.getAdjustmentFund());
    }

    private Contract suspendShareFlow(Contract contract, BigDecimal unitPriceAccurate, DateTime[] contractPart, DateTime[] usePart, DateTime[] selected) {
        if (!ContractStatusEnum.SUSPEND.getKey().equals(contract.getStatus())) {
            return null;
        }
        ContractChange contractChange = contractChangeRepository.findByContentCode(ContractStatusEnum.SUSPEND.getValue(),
                contract.getContractCode());

        if (contractChange == null) {
            contract.setAdjustmentFund(0L);
            contract.setIntervaIncomeShare(0L);
            contract.setIncomeShareAll(0L);
            contract.setClickFlow(0.0);
            return contract;
        }
        // 合同中止日
        DateTime cancelDate = new DateTime(contractChange.getDs());

        //中止操作入库时间
        DateTime suspendDate = new DateTime(new DateTime(contractChange.getCreateTime()).toString("yyyy-MM-dd"));
        contract.setClickFlow(0.0);
        //调整金
        Long adjustmentFund = 0L;
        if (checkTwoTime(suspendDate, cancelDate)) {
            adjustmentFund = 0L;
        } else {
            //查询调整金的点击，日期开始结束时间注意不能颠倒

            BigDecimal clickNum = tkioFlowRepository.sumFlowByContractCodeAndDs(contract.getContractCode(),cancelDate.toString("yyyy-MM-dd"),suspendDate.toString("yyyy-MM-dd"));
            long clickFlow = clickNum==null?0L:clickNum.longValue();

            BigDecimal clickTenThousand = new BigDecimal(0);
            if(clickFlow!=0){
                clickTenThousand = new BigDecimal(clickFlow / 10000.0 * 100);
            }
            adjustmentFund = unitPriceAccurate.multiply(clickTenThousand.multiply(new BigDecimal(-1))).setScale(0, BigDecimal.ROUND_HALF_UP).longValue();
        }
        //调整金
        contract.setAdjustmentFund(adjustmentFund);
        DateTime usedEnd = usePart[1].compareTo(cancelDate) <= 0 ? usePart[1] : cancelDate;
        //查询开始->中止日期的点击(有收入的点击)，不包括调整金
        BigDecimal clickNum = tkioFlowRepository.sumFlowByContractCodeAndDs(contract.getContractCode(),usePart[0].toString("yyyy-MM-dd"),usedEnd.toString("yyyy-MM-dd"));
        long clickFlow = clickNum==null?0L:clickNum.longValue();
        BigDecimal clickTenThousand = new BigDecimal(0);
        if(clickFlow!=0){
            clickTenThousand = new BigDecimal(clickFlow / 10000.0 * 100);
            //区间点击数
            contract.setClickFlow(new BigDecimal(clickFlow / 10000.0).setScale(4,BigDecimal.ROUND_HALF_UP).doubleValue());
        }
        //区间分摊收入,乘以100，前端除以100
        long share = unitPriceAccurate.multiply(clickTenThousand).setScale(0, BigDecimal.ROUND_HALF_UP).longValue();
        contract.setIntervaIncomeShare(share);
        contract.setIncomeShareAll(share+adjustmentFund);

        if(checkTwoTime(selected[0],contractPart[1]) && checkTwoTime(contractPart[1],selected[1])){
            contract.setIncomeGross(contract.getIncomeExcludingTax());
        }else{
            //累计总收入
            clickNum = tkioFlowRepository.sumFlowByContractCodeAndDs(contract.getContractCode(),contractPart[0].toString("yyyy-MM-dd"),selected[1].toString("yyyy-MM-dd"));
            clickFlow = clickNum==null?0L:clickNum.longValue();
            contract.setIncomeGross(unitPriceAccurate.multiply(new BigDecimal(clickFlow / 10000.0 * 100)).setScale(0, BigDecimal.ROUND_HALF_UP).longValue());
        }
        return contract;
    }

    private Contract cancledShareFlow(Contract contract, BigDecimal unitPriceAccurate, DateTime[] usePart, DateTime[] selected) {
        if (!ContractStatusEnum.CANCEL.getKey().equals(contract.getStatus())) {
            return null;
        }
        ContractChange contractChange = contractChangeRepository.findByContentCode(ContractStatusEnum.CANCEL.getValue(), contract.getContractCode());
        if (contractChange == null) {
            contract.setAdjustmentFund(0L);
            contract.setIntervaIncomeShare(0L);
            contract.setIncomeShareAll(0L);
            contract.setClickFlow(0.0);
            return contract;
        }

        DateTime cancelDate = new DateTime(contractChange.getDs());//合同作废日
        DateTime usedEnd = usePart[1].compareTo(cancelDate) <= 0 ? usePart[1] : cancelDate;


        BigDecimal clickNum = tkioFlowRepository.sumFlowByContractCodeAndDs(contract.getContractCode(),usePart[0].toString("yyyy-MM-dd"),usedEnd.toString("yyyy-MM-dd"));
        long clickFlow = clickNum==null?0L:clickNum.longValue();
        //区间点击数
        contract.setClickFlow(0.0);
        BigDecimal clickTenThousand = new BigDecimal(0);
        if(clickFlow!=0){
            clickTenThousand = new BigDecimal(clickFlow / 10000.0 * 100);
            //区间点击数
            contract.setClickFlow(new BigDecimal(clickFlow / 10000.0).setScale(4,BigDecimal.ROUND_HALF_UP).doubleValue());
        }
        //区间分摊收入,乘以100，前端除以100
        long share = unitPriceAccurate.multiply(clickTenThousand).setScale(0, BigDecimal.ROUND_HALF_UP).longValue();
        contract.setIntervaIncomeShare(share);
        //调整金
        if (checkTwoTime(selected[0], cancelDate) && checkTwoTime(cancelDate, selected[1])) {
            clickNum = tkioFlowRepository.sumFlowByContractCodeAndDs(contract.getContractCode(),contract.getStartDate(),usedEnd.toString("yyyy-MM-dd"));
            clickFlow = clickNum==null?0L:clickNum.longValue();
            //区间点击数
            clickTenThousand = new BigDecimal(0);
            if(clickFlow!=0){
                clickTenThousand = new BigDecimal(clickFlow / 10000.0 * 100);
                //区间点击数
                contract.setAdjustmentFund(unitPriceAccurate.multiply(clickTenThousand).setScale(0, BigDecimal.ROUND_HALF_UP).longValue() * -1L);
            }else{
                contract.setAdjustmentFund(0L);
            }
        }else{
            contract.setAdjustmentFund(0L);
        }
        //分摊总收入
        contract.setIncomeShareAll(0L);
        contract.setIncomeGross(0L);
        return contract;
    }

    //需求禅道 1608
    public void shareIncome4ContractTwo(Contract contract, DateTime start, DateTime end) {
        DateTime[] selected = new DateTime[]{
                start,
                end};//用户筛选开始/结束日期
        DateTime[] contractPart = new DateTime[]{
                new DateTime(contract.getStartDate()),
                new DateTime(contract.getEndDate())};//合同开始结束 时间
        DateTime[] usePart = new DateTime[]{
                selected[0].compareTo(contractPart[0]) <= 0 ? contractPart[0] : selected[0],
                selected[1].compareTo(contractPart[1]) >= 0 ? contractPart[1] : selected[1]
        };
        usePart[0] = usePart[0].compareTo(usePart[1]) >= 0 ? usePart[1] : usePart[0];

        Long excludTax = new BigDecimal(contract.getMoney() / 1.06)
                .setScale(2, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100L)).longValue();//不含税收入*100
        contract.setIncomeExcludingTax(excludTax);

        //计算单价,精准保留16位数
        BigDecimal unitPriceAccurate = new BigDecimal(contract.getMoney()/1.06/contract.getTrackFlow())
                .setScale(16, BigDecimal.ROUND_HALF_UP);
        //四舍五入单价
        double unitPrice = unitPriceAccurate.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
        //不限量套餐会在方法里面重新赋值单价
        contract.setUnitPrice(unitPrice);
        //查询用户下所有appkey
        Account account = accountRepository.findByEmail(contract.getEmail());
        List<Account> accountList = accountRepository.findByRootParent(account.getRootParent());
        List<Long> idList = new ArrayList<>();
        for (Account ac : accountList) {
            idList.add(ac.getId());
        }
        List<String> appkeys = appRepository.findAppkeysNotDebug(idList);
        String appkeyStr = String.join("','", appkeys);
        appkeyStr= "'"+appkeyStr+"'";

        //作废合同  累计收入= 0
        //中止合同  累计收入= 如果中止日期在选择日期之内，【合同开始日期-中止日期】，否则【合同开始日期-选择结束日期】，不需要考虑调整金
        //晚录合同  累计收入= 同下
        //正常合同  累计收入= 如果合同结束日期在选择日期之内，则直接取 [合同金额/1.06]得到总金额 ，否则 【合同开始日期-选择结束日期】

        //作废合同处理
        Contract cancleContract = this.cancledShareTKIO(contract, appkeyStr, unitPriceAccurate, usePart,selected);
        if (cancleContract != null) {
            return;
        }

        //中止合同处理
        Contract suspendContract = this.suspendShareTKIO(contract, appkeyStr, unitPriceAccurate,contractPart, usePart, selected);
        if (suspendContract != null) {
            return;
        }

        //晚录合同处理//正常合同处理
        DateTime create = new DateTime(new DateTime(contract.getCreateTime()).toString("yyyy-MM-dd")); //录入时间点
        DateTime[] creatPoints = new DateTime[]{
                create, //录入日
                create.dayOfMonth().withMinimumValue() //录入月1日
        };
        this.afterContractTKIO(contract, appkeyStr,unitPriceAccurate, contractPart, usePart, selected, creatPoints);




    }

    private void afterContractTKIO(Contract contract, String appkeyStr,BigDecimal unitPriceAccurate, DateTime[] contractPart,DateTime[] usePart, DateTime[] selected, DateTime[] creatPoints) {


        Long adjustmentFund = 0L;//调整金
        contract.setClickFlow(0.0);
        boolean isLateContract = false; // 是否为晚录合同（为了兼容历史数据 此处做冗余判断）
        if (ContractStatusEnum.LATE.getKey().equals(contract.getStatus())) {
            isLateContract = true;
        } else if (checkLateContract(contractPart[0], creatPoints[0])) {
            isLateContract = true;
            contract.setStatus(ContractStatusEnum.LATE.getKey());
        }

        boolean isLater = true;
        if (!isLateContract) {
            //非合同晚录
            BigInteger clickNum = accountFlowRestrictService.getTotalNum(usePart[0].toString("yyyy-MM-dd"), usePart[1].toString("yyyy-MM-dd"), appkeyStr, "account_track_flow_restrict", "click_sum");
            long clickFlow = clickNum==null?0L:clickNum.longValue();
            BigDecimal clickTenThousand = new BigDecimal(0);

            if(clickFlow!=0){
                clickTenThousand = new BigDecimal(clickFlow / 10000.0 * 100);
                //区间点击数
                contract.setClickFlow(new BigDecimal(clickFlow / 10000.0).setScale(4,BigDecimal.ROUND_HALF_UP).doubleValue());
            }
            //区间分摊收入
            contract.setIntervaIncomeShare(unitPriceAccurate.multiply(clickTenThousand).setScale(0, BigDecimal.ROUND_HALF_UP).longValue());

            contract.setAdjustmentFund(0L);
            contract.setIncomeShareAll(contract.getIntervaIncomeShare());

            if(checkTwoTime(selected[0],contractPart[1]) && checkTwoTime(contractPart[1],selected[1])){
                contract.setIncomeGross(contract.getIncomeExcludingTax());
            }else{
                //累计总收入
                clickNum = accountFlowRestrictService.getTotalNum(contractPart[0].toString("yyyy-MM-dd"), selected[1].toString("yyyy-MM-dd"), appkeyStr, "account_track_flow_restrict", "click_sum");
                clickFlow = clickNum==null?0L:clickNum.longValue();
                contract.setIncomeGross(unitPriceAccurate.multiply(new BigDecimal(clickFlow / 10000.0 * 100)).setScale(0, BigDecimal.ROUND_HALF_UP).longValue());
            }

            isLater = false;
        } else if (selected[1].isBefore(creatPoints[1])) {
            //录入月1号之前 调整金为 0 分摊为 0
            contract.setIntervaIncomeShare(0L);
            contract.setAdjustmentFund(0L);
            contract.setIncomeShareAll(contract.getIntervaIncomeShare());
            contract.setClickFlow(0.0);
            contract.setIncomeGross(0L);
            contract.setStatus(ContractStatusEnum.LATE.getKey());
        } else {
            contract.setStatus(ContractStatusEnum.LATE.getKey());
            //合同晚录
            //所选时间范围内的分摊收入(录入月1号 即creatPoints[1] 开始计算)
            DateTime useStart = creatPoints[1].compareTo(selected[0]) >= 0 ? creatPoints[1] : selected[0];

            BigInteger clickNum = accountFlowRestrictService.getTotalNum(useStart.toString("yyyy-MM-dd"), usePart[1].toString("yyyy-MM-dd"), appkeyStr, "account_track_flow_restrict", "click_sum");
            long clickFlow = clickNum==null?0L:clickNum.longValue();
            BigDecimal clickTenThousand = new BigDecimal(0);

            if(clickFlow!=0){
                clickTenThousand = new BigDecimal(clickFlow / 10000.0 * 100);
                //区间点击数
                contract.setClickFlow(new BigDecimal(clickFlow / 10000.0).setScale(4,BigDecimal.ROUND_HALF_UP).doubleValue());
            }
            //区间分摊收入
            contract.setIntervaIncomeShare(unitPriceAccurate.multiply(clickTenThousand).setScale(0, BigDecimal.ROUND_HALF_UP).longValue());


            if (checkTwoTime(selected[0], creatPoints[1]) && checkTwoTime(creatPoints[1], selected[1])) {
                //所选时间范围包含 录入月 1 号 显示统计的调整金
                //合同开始日期，合同录入日期的一号，-1就是上个月最后一天
                //contractPart[0], creatPoints[1].plusDays(-1)
                clickNum = accountFlowRestrictService.getTotalNum(contractPart[0].toString("yyyy-MM-dd"),creatPoints[1].plusDays(-1).toString("yyyy-MM-dd"), appkeyStr, "account_track_flow_restrict", "click_sum");
                clickFlow = clickNum==null?0L:clickNum.longValue();
                clickTenThousand = new BigDecimal(0);
                if(clickFlow!=0){
                    clickTenThousand = new BigDecimal(clickFlow / 10000.0 * 100);
                    //区间点击数
                }
                contract.setAdjustmentFund(unitPriceAccurate.multiply(clickTenThousand).setScale(0, BigDecimal.ROUND_HALF_UP).longValue());
            } else {
                contract.setAdjustmentFund(0L);
            }

            if(checkTwoTime(selected[0],contractPart[1]) && checkTwoTime(contractPart[1],selected[1])){
                contract.setIncomeGross(contract.getIncomeExcludingTax());
            }else{
                //累计总收入
                clickNum = accountFlowRestrictService.getTotalNum(contractPart[0].toString("yyyy-MM-dd"), selected[1].toString("yyyy-MM-dd"), appkeyStr, "account_track_flow_restrict", "click_sum");
                clickFlow = clickNum==null?0L:clickNum.longValue();
                contract.setIncomeGross(unitPriceAccurate.multiply(new BigDecimal(clickFlow / 10000.0 * 100)).setScale(0, BigDecimal.ROUND_HALF_UP).longValue());
            }
        }

        if (checkTwoTime(contractPart[1], selected[1])) {
            //最后一日分摊收入计算处理(合同的最后一天，不管流量剩余多少，都算作做最后一天的收入)
            Long lastDay;
            DateTime lastDate[];
            if (isLater) {
                lastDate = new  DateTime[]{creatPoints[1],contractPart[1].plusDays(-1)};
            } else {
                lastDate = new  DateTime[]{contractPart[0],contractPart[1].plusDays(-1)};
            }
            //合同除去最后一天的流量
            BigInteger clickNum = accountFlowRestrictService.getTotalNum(lastDate[0].toString("yyyy-MM-dd"), lastDate[1].toString("yyyy-MM-dd"), appkeyStr, "account_track_flow_restrict", "click_sum");
            long clickFlow = clickNum==null?0L:clickNum.longValue();
            BigDecimal clickTenThousand = new BigDecimal(0);
            if(clickFlow!=0){
                clickTenThousand = new BigDecimal(clickFlow / 10000.0 * 100);
            }
            long beforeTheMoney = unitPriceAccurate.multiply(clickTenThousand).setScale(0, BigDecimal.ROUND_HALF_UP).longValue();

            //最后一天的流量
            clickNum = accountFlowRestrictService.getTotalNum(contractPart[1].toString("yyyy-MM-dd"), contractPart[1].toString("yyyy-MM-dd"), appkeyStr, "account_track_flow_restrict", "click_sum");
            clickFlow = clickNum==null?0L:clickNum.longValue();
            clickTenThousand = new BigDecimal(0);
            if(clickFlow!=0)clickTenThousand = new BigDecimal(clickFlow / 10000.0 * 100);
            long lastDayTheMoney = unitPriceAccurate.multiply(clickTenThousand).setScale(0, BigDecimal.ROUND_HALF_UP).longValue();
            //合同的税后总金额减去最后合同一日之前的钱和调整金
            lastDay = contract.getIncomeExcludingTax() - contract.getAdjustmentFund() - beforeTheMoney;
            //最后一日 或 包含最后一日 时
            contract.setIntervaIncomeShare(contract.getIntervaIncomeShare() - lastDayTheMoney + lastDay);
        }

        contract.setIncomeShareAll(contract.getIntervaIncomeShare() + contract.getAdjustmentFund());

    }

    private Contract suspendShareTKIO(Contract contract, String appkeys, BigDecimal unitPriceAccurate,DateTime[] contractPart, DateTime[] usePart,DateTime[] selected) {
        if (!ContractStatusEnum.SUSPEND.getKey().equals(contract.getStatus())) {
            return null;
        }
        ContractChange contractChange = contractChangeRepository.findByContentCode(ContractStatusEnum.SUSPEND.getValue(),
                contract.getContractCode());

        if (contractChange == null) {
            contract.setAdjustmentFund(0L);
            contract.setIntervaIncomeShare(0L);
            contract.setIncomeShareAll(0L);
            contract.setClickFlow(0.0);
            return contract;
        }
        // 合同中止日
        DateTime cancelDate = new DateTime(contractChange.getDs());

        //中止操作入库时间
        DateTime suspendDate = new DateTime(new DateTime(contractChange.getCreateTime()).toString("yyyy-MM-dd"));
        contract.setClickFlow(0.0);
        //调整金
        Long adjustmentFund = 0L;
        if (checkTwoTime(suspendDate, cancelDate)) {
            adjustmentFund = 0L;
        } else {
            //查询调整金的点击，日期开始结束时间注意不能颠倒
            BigInteger clickNum = accountFlowRestrictService.getTotalNum(cancelDate.toString("yyyy-MM-dd"), suspendDate.toString("yyyy-MM-dd"), appkeys, "account_track_flow_restrict", "click_sum");
            long clickFlow = clickNum==null?0L:clickNum.longValue();

            BigDecimal clickTenThousand = new BigDecimal(0);
            if(clickFlow!=0){
                clickTenThousand = new BigDecimal(clickFlow / 10000.0 * 100);
            }
            adjustmentFund = unitPriceAccurate.multiply(clickTenThousand.multiply(new BigDecimal(-1))).setScale(0, BigDecimal.ROUND_HALF_UP).longValue();
        }
        //调整金
        contract.setAdjustmentFund(adjustmentFund);
        DateTime usedEnd = usePart[1].compareTo(cancelDate) <= 0 ? usePart[1] : cancelDate;
        //查询开始->中止日期的点击(有收入的点击)，不包括调整金
        BigInteger clickNum = accountFlowRestrictService.getTotalNum(usePart[0].toString("yyyy-MM-dd"), usedEnd.toString("yyyy-MM-dd"), appkeys, "account_track_flow_restrict", "click_sum");
        long clickFlow = clickNum==null?0L:clickNum.longValue();
        BigDecimal clickTenThousand = new BigDecimal(0);
        if(clickFlow!=0){
            clickTenThousand = new BigDecimal(clickFlow / 10000.0 * 100);
            //区间点击数
            contract.setClickFlow(new BigDecimal(clickFlow / 10000.0).setScale(4,BigDecimal.ROUND_HALF_UP).doubleValue());
        }
        //区间分摊收入,乘以100，前端除以100
        long share = unitPriceAccurate.multiply(clickTenThousand).setScale(0, BigDecimal.ROUND_HALF_UP).longValue();
        contract.setIntervaIncomeShare(share);
        contract.setIncomeShareAll(share+adjustmentFund);

        if(checkTwoTime(selected[0],contractPart[1]) && checkTwoTime(contractPart[1],selected[1])){
            contract.setIncomeGross(contract.getIncomeExcludingTax());
        }else{
            //累计总收入
            clickNum = accountFlowRestrictService.getTotalNum(contractPart[0].toString("yyyy-MM-dd"), selected[1].toString("yyyy-MM-dd"), appkeys, "account_track_flow_restrict", "click_sum");
            clickFlow = clickNum==null?0L:clickNum.longValue();
            contract.setIncomeGross(unitPriceAccurate.multiply(new BigDecimal(clickFlow / 10000.0 * 100)).setScale(0, BigDecimal.ROUND_HALF_UP).longValue());
        }
        return contract;
    }

    private Contract cancledShareTKIO(Contract contract, String appkeys, BigDecimal unitPriceAccurate, DateTime[] usePart, DateTime[] selected) {
        if (!ContractStatusEnum.CANCEL.getKey().equals(contract.getStatus())) {
            return null;
        }
        ContractChange contractChange = contractChangeRepository.findByContentCode(ContractStatusEnum.CANCEL.getValue(), contract.getContractCode());
        if (contractChange == null) {
            contract.setAdjustmentFund(0L);
            contract.setIntervaIncomeShare(0L);
            contract.setIncomeShareAll(0L);
            contract.setClickFlow(0.0);
            return contract;
        }

        DateTime cancelDate = new DateTime(contractChange.getDs());//合同作废日
        DateTime usedEnd = usePart[1].compareTo(cancelDate) <= 0 ? usePart[1] : cancelDate;

        BigInteger clickNum = accountFlowRestrictService.getTotalNum(usePart[0].toString("yyyy-MM-dd"), usedEnd.toString("yyyy-MM-dd"), appkeys, "account_track_flow_restrict", "click_sum");
        long clickFlow = clickNum==null?0L:clickNum.longValue();
        //区间点击数
        contract.setClickFlow(0.0);
        BigDecimal clickTenThousand = new BigDecimal(0);
        if(clickFlow!=0){
            clickTenThousand = new BigDecimal(clickFlow / 10000.0 * 100);
            //区间点击数
            contract.setClickFlow(new BigDecimal(clickFlow / 10000.0).setScale(4,BigDecimal.ROUND_HALF_UP).doubleValue());
        }
        //区间分摊收入,乘以100，前端除以100
        long share = unitPriceAccurate.multiply(clickTenThousand).setScale(0, BigDecimal.ROUND_HALF_UP).longValue();
        contract.setIntervaIncomeShare(share);
        //调整金
        if (checkTwoTime(selected[0], cancelDate) && checkTwoTime(cancelDate, selected[1])) {
            contract.setAdjustmentFund(share*-1L);
        }else{
            contract.setAdjustmentFund(0L);
        }
        //分摊总收入
        contract.setIncomeShareAll(0L);
        contract.setIncomeGross(0L);
        return contract;
    }

    public void shareIncome4Contract(Contract contract, DateTime start, DateTime end) {

        DateTime[] selected = new DateTime[]{
                start,
                end};//用户筛选开始/结束日期
        DateTime[] contractPart = new DateTime[]{
                new DateTime(contract.getStartDate()),
                new DateTime(contract.getEndDate())};//合同开始结束 时间
        DateTime[] usePart = new DateTime[]{
                selected[0].compareTo(contractPart[0]) <= 0 ? contractPart[0] : selected[0],
                selected[1].compareTo(contractPart[1]) >= 0 ? contractPart[1] : selected[1]
        };

        usePart[0] = usePart[0].compareTo(usePart[1]) >= 0 ? usePart[1] : usePart[0];

        contract.setIntervalUseDays(getDayRange(contractPart[0], usePart[1]) + 1);

        Long excludTax = new BigDecimal(contract.getMoney() / 1.06)
                .setScale(2, BigDecimal.ROUND_HALF_UP).multiply(new BigDecimal(100L)).longValue();//不含税收入*100
        contract.setIncomeExcludingTax(excludTax);
        int contractAllDay = getDayRange(contractPart[0], contractPart[1]) + 1;//合同总天数

        //处理精度
        BigDecimal dayShareIncome = new BigDecimal(excludTax * 1.0 / contractAllDay);

        if("tkio".equals(contract.getPlatform())){//设置tkio无限流量的日单价
            contract.setUnitPrice(dayShareIncome.divide(new BigDecimal(100)).setScale(2,BigDecimal.ROUND_HALF_UP).doubleValue());
        }

        //作废合同处理
        Contract cancleContract = this.cancledShare(contract, contractAllDay, dayShareIncome, contractPart, usePart, selected);
        if (cancleContract != null) {
            return;
        }

        //中止合同处理
        Contract suspendContract = this.suspendShare(contract, contractAllDay, dayShareIncome, contractPart, usePart, selected);
        if (suspendContract != null) {
            return;
        }

        //特殊合同处理
        Contract specilContract = this.specilContract(contract, dayShareIncome, contractPart, usePart, selected);
        if (specilContract != null) {
            return;
        }

        //晚录合同处理
        DateTime create = new DateTime(new DateTime(contract.getCreateTime()).toString("yyyy-MM-dd")); //录入时间点
        DateTime[] creatPoints = new DateTime[]{
                create, //录入日
                create.dayOfMonth().withMinimumValue() //录入月1日
        };

        this.afterContract(contract, contractAllDay, dayShareIncome, contractPart, usePart, selected, creatPoints);

    }


    private Contract specilContract(Contract contract, BigDecimal dayShareIncome, DateTime[] contractPart, DateTime[] usePart, DateTime[] selected) {

        if (!"QQ-ADI-20190729-57".equals(contract.getContractCode())) {
            return null;
        }

        /*19年不含税金额:24268.88
        已摊销天数：161
        20不含税金额：31202.8181132075
        未摊销天数：205
        合同日期2019.7.24-2020.7.23，
        合同编号：QQ-ADI-20190729-57*/

        DateTime[] middlePoiont = new DateTime[]{new DateTime("2019-12-31"), new DateTime("2020-01-01")};

        contract.setAdjustmentFund(0L);
        contract.setIncomeExcludingTax(new BigDecimal(24268.88 * 100).add(new BigDecimal(31202.8181132075 * 100))
                .setScale(2, BigDecimal.ROUND_HALF_UP).longValue());

        BigDecimal dayShare_19 = new BigDecimal(24268.88).multiply(new BigDecimal(100))
                .divide(new BigDecimal(161), 15, BigDecimal.ROUND_HALF_UP);

        //选择时间范围内 20 年分摊天数 及每天分摊
        BigDecimal dayShare_20 = new BigDecimal(31202.8181132075).multiply(new BigDecimal(100))
                .divide(new BigDecimal(205), 15, BigDecimal.ROUND_HALF_UP);

        if (checkTwoTime(usePart[0], middlePoiont[0]) && checkTwoTime(middlePoiont[1], usePart[1])) {
            //选择时间范围内 19 + 20  年分摊天数 及每天分摊
            Long allDayShare = dayShare_19.multiply(new BigDecimal(getDayRange(usePart[0], middlePoiont[0]) + 1))
                    .add(dayShare_20.multiply(new BigDecimal(getDayRange(middlePoiont[1], usePart[1]) + 1)))
                    .setScale(2, BigDecimal.ROUND_HALF_UP).longValue();
            contract.setIntervaIncomeShare(allDayShare);

        } else {

            int days = getDayRange(usePart[0], usePart[1]) + 1;
            if (checkTwoTime(usePart[1], middlePoiont[0])) {
                //19 年
                contract.setIntervaIncomeShare(shareMultiply(dayShare_19, new BigDecimal(days), 2));

            } else {
                //20 年
                contract.setIntervaIncomeShare(shareMultiply(dayShare_20, new BigDecimal(days), 2));

            }
        }

        contract.setIncomeShareAll(contract.getIntervaIncomeShare());
        return contract;

    }

    private void afterContract(Contract contract, int contractAllDay, BigDecimal dayShareIncome,
                               DateTime[] contractPart, DateTime[] usePart, DateTime[] selected, DateTime[] creatPoints) {

        int betweenMonth = Months.monthsBetween(contractPart[0], creatPoints[0]).getMonths();
        //时间范围内用于计算分摊金额的天数
        int daysIncom = getDayRange(usePart[0], usePart[1]) + 1;
        //区间分摊总收入
        contract.setIntervaIncomeShare(shareMultiply(dayShareIncome, new BigDecimal(daysIncom), 0));

        Long adjustmentFund = 0L;//调整金

        boolean isLateContract = false; // 是否为晚录合同（为了兼容历史数据 此处做冗余判断）
        if (ContractStatusEnum.LATE.getKey().equals(contract.getStatus())) {
            isLateContract = true;
        } else if (checkLateContract(contractPart[0], creatPoints[0])) {
            isLateContract = true;
        }

        if (isLateContract) {
            contract.setStatus(ContractStatusEnum.LATE.getKey());
        }

        boolean isLater = true;
        if (!isLateContract || betweenMonth < 1) {
            //非合同晚录
            contract.setAdjustmentFund(0L);
            contract.setIncomeShareAll(contract.getIntervaIncomeShare());
            isLater = false;


        } else if (selected[1].isBefore(creatPoints[1])) {
            //录入月1号之前 调整金为 0 分摊为 0
            contract.setIntervaIncomeShare(0L);
            contract.setAdjustmentFund(0L);
            contract.setIncomeShareAll(contract.getIntervaIncomeShare());
            contract.setStatus(ContractStatusEnum.LATE.getKey());
        } else {
            contract.setStatus(ContractStatusEnum.LATE.getKey());
            //合同晚录
            //所选时间范围内的分摊收入(录入月1号 即creatPoints[1] 开始计算)
            DateTime useStart = creatPoints[1].compareTo(selected[0]) >= 0 ? creatPoints[1] : selected[0];
            daysIncom = getDayRange(useStart, usePart[1]) + 1;

            contract.setIntervaIncomeShare(shareMultiply(dayShareIncome, new BigDecimal(daysIncom), 0));
            adjustmentFund = shareMultiply(dayShareIncome, new BigDecimal(getDayRange(contractPart[0], creatPoints[1].plusDays(-1)) + 1), 0);

            if (checkTwoTime(selected[0], creatPoints[1]) && checkTwoTime(creatPoints[1], selected[1])) {
                //所选时间范围包含 录入月 1 号 显示统计的调整金
                contract.setAdjustmentFund(adjustmentFund);
            } else {
                contract.setAdjustmentFund(0L);
            }
        }

        if (checkTwoTime(selected[0], contractPart[1]) && checkTwoTime(contractPart[1], selected[1])) {
            contract.setIncomeGross(shareMultiply(new BigDecimal(getDayRange(contractPart[0], contractPart[1]) + 1), dayShareIncome, 0));
        } else {
            contract.setIncomeGross(shareMultiply(new BigDecimal(getDayRange(contractPart[0], selected[1]) + 1), dayShareIncome, 0));
        }

        if (checkTwoTime(contractPart[1], selected[1])) {
            //最后一日分摊金计算处理
            Long lastDay;
            if (isLater) {


                lastDay = contract.getIncomeExcludingTax() - adjustmentFund
                        - shareMultiply(dayShareIncome, new BigDecimal(getDayRange(creatPoints[1], contractPart[1])), 0);
            } else {
                lastDay = contract.getIncomeExcludingTax() - adjustmentFund
                        - shareMultiply(dayShareIncome, new BigDecimal(getDayRange(contractPart[0], contractPart[1])), 0);
            }

            //最后一日 或 包含最后一日 时
            contract.setIntervaIncomeShare(contract.getIntervaIncomeShare() -
                    dayShareIncome.setScale(0, BigDecimal.ROUND_HALF_UP).longValue() + lastDay);

        }

        contract.setIncomeShareAll(contract.getIntervaIncomeShare() + contract.getAdjustmentFund());

    }

    private Contract suspendShare(Contract contract, int contractAllDay, BigDecimal dayShareIncome,
                                  DateTime[] contractPart, DateTime[] usePart, DateTime[] selected) {
        if (!ContractStatusEnum.SUSPEND.getKey().equals(contract.getStatus())) {
            return null;
        }

        ContractChange contractChange = contractChangeRepository.findByContentCode(ContractStatusEnum.SUSPEND.getValue(),
                contract.getContractCode());

        if (contractChange == null) {
            contract.setAdjustmentFund(0L);
            contract.setIntervaIncomeShare(0L);
            contract.setIncomeShareAll(0L);
            return contract;
        }
        // 合同终止日 或 作废日
        DateTime cancelDate = new DateTime(contractChange.getDs());

        //中止操作入库时间
        DateTime suspendDate = new DateTime(new DateTime(contractChange.getCreateTime()).toString("yyyy-MM-dd"));

        Long adjustmentFund = 0L;
        if (checkTwoTime(suspendDate, cancelDate)) {
            adjustmentFund = 0L;
        } else {
            adjustmentFund = shareMultiply(new BigDecimal((getDayRange(cancelDate, suspendDate) + 1) * -1), dayShareIncome, 0);
        }

        DateTime usedEnd = usePart[1].compareTo(cancelDate) <= 0 ? usePart[1] : cancelDate;
        int daysIncom = Days.daysBetween(usePart[0], usedEnd).getDays() + 1;
        daysIncom = daysIncom < 0 ? 0 : daysIncom;

        //区间分摊总收入
        contract.setIntervaIncomeShare(shareMultiply(dayShareIncome, new BigDecimal(daysIncom), 0));

        if (checkTwoTime(selected[0], cancelDate) && checkTwoTime(cancelDate, selected[1])) {
            contract.setAdjustmentFund(adjustmentFund);
            contract.setIncomeGross(shareMultiply(new BigDecimal(getDayRange(contractPart[0], cancelDate) + 1), dayShareIncome, 0));
        } else {
            contract.setAdjustmentFund(0L);
            contract.setIncomeGross(shareMultiply(new BigDecimal(getDayRange(contractPart[0], selected[1]) + 1), dayShareIncome, 0));
        }

        contract.setIncomeShareAll(contract.getIntervaIncomeShare() + contract.getAdjustmentFund());

        return contract;
    }

    private Contract cancledShare(Contract contract, int contractAllDay, BigDecimal dayShareIncome,
                                  DateTime[] contractPart, DateTime[] usePart, DateTime[] selected) {

        if (!ContractStatusEnum.CANCEL.getKey().equals(contract.getStatus())) {
            return null;
        }

        ContractChange contractChange = contractChangeRepository.findByContentCode(ContractStatusEnum.CANCEL.getValue(), contract.getContractCode());

        if (contractChange == null) {
            contract.setAdjustmentFund(0L);
            contract.setIntervaIncomeShare(0L);
            contract.setIncomeShareAll(0L);
            return contract;
        }

        // 合同终止日 或 作废日
        DateTime cancelDate = new DateTime(contractChange.getDs());
        Long adjustmentFund = shareMultiply(new BigDecimal((getDayRange(contractPart[0], cancelDate) + 1) * -1), dayShareIncome, 0);
        DateTime usedEnd = usePart[1].compareTo(cancelDate) <= 0 ? usePart[1] : cancelDate;

        int daysIncom = Days.daysBetween(usePart[0], usedEnd).getDays() + 1;
        daysIncom = daysIncom < 0 ? 0 : daysIncom;

        contract.setIntervalUseDays(getDayRange(contractPart[0], usedEnd) + 1);
        //区间分摊总收入

        contract.setIntervaIncomeShare(shareMultiply(dayShareIncome, new BigDecimal(daysIncom), 0));

        if (checkTwoTime(selected[0], cancelDate) && checkTwoTime(cancelDate, selected[1])) {
            contract.setAdjustmentFund(adjustmentFund);
        } else {
            contract.setAdjustmentFund(0L);
        }
        contract.setIncomeGross(0L);
        contract.setIncomeShareAll(contract.getIntervaIncomeShare() + contract.getAdjustmentFund());
        return contract;
    }

    private Long shareMultiply(BigDecimal one, BigDecimal two, int scale) {
        return one.multiply(two).setScale(scale, BigDecimal.ROUND_HALF_UP).longValue();
    }

    @Override
    public boolean checkLateContract(DateTime dateTime, DateTime creatTime) {
        int aferDays = dateTime.monthOfYear().get() == 12 ? 29 : 9;
        return dateTime.dayOfMonth().withMaximumValue().plusDays(aferDays).isBefore(creatTime);

    }

    private int getDayRange(DateTime range1, DateTime range2) {
        return Days.daysBetween(range1, range2).getDays();
    }

    public boolean checkTwoTime(DateTime dateTime1, DateTime dateTime2) {
        return dateTime1.isBefore(dateTime2) || dateTime1.isEqual(dateTime2);
    }


    @Override
    public List<TrackFlowVO> trialFlow(User loginAccount, String startDate, String endDate, String platform, String email) {
        //离线数据值
        Map<String, Double> offlineResult = tkioOfflineRepository.findOfflineResult(startDate, endDate);

        //查询主账号
        List<Map<String,String>> list = null;
        if(StringUtil.isEmpty(email)){
            list = accountRepository.findAllAccountAppKeys();
        }else{
            list = accountRepository.findAccountAppKeysByEmail(email);
        }
        JSONArray jsonObject = JSONArray.fromObject(list);
        Iterator it= jsonObject.iterator();
        List<AccountVO> avs = new ArrayList<>();
        while (it.hasNext()){
            JSONArray array = JSONArray.fromObject(it.next());
            String e = array.getString(0);
            String k = array.getString(1);
            AccountVO vo = new AccountVO();
            vo.setEmail(e);
            vo.setAppKey(k);
            avs.add(vo);
        }
        //汇总计算
        List<TrackFlowVO> result = new ArrayList<>();
        for(AccountVO ac:avs){
            TrackFlowVO tf = new TrackFlowVO(ac.getEmail());
            String appKeys = ac.getAppKey();
            //如果appKey为空，流量为0
            if("".equals(appKeys.trim())){
                tf.setTrackFlow(0.0);
                result.add(tf);
                continue;
            }
            Double sum = 0.0;
            String[] keyArr = appKeys.split(",");
            for(String k:keyArr){
                Double v = offlineResult.get(k);
                if(v==null){
                    v = 0.0;
                }
                sum +=v;
            }
            tf.setTrackFlow(new BigDecimal(sum/10000).setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue());
            result.add(tf);
        }
        return result;
    }


    public static void main(String[] args) {
        DateTime dateTime = new DateTime("2020-10-30");
        DateTime creatTime = new DateTime("2020-11-9");
        int aferDays = dateTime.monthOfYear().get() == 12 ? 29 : 9;
        System.out.println(dateTime.monthOfYear().get());
        System.out.println(dateTime.dayOfMonth().withMaximumValue());
        System.out.println(dateTime.dayOfMonth().withMaximumValue().plusDays(aferDays));
        System.out.println(dateTime.dayOfMonth().withMaximumValue().plusDays(aferDays).isBefore(creatTime));
        dateTime.dayOfMonth().withMaximumValue().plusDays(aferDays).isBefore(creatTime);

    }

    public static void main2(String[] args) {
        DateTime contractStart = new DateTime("2020-05-15");
        DateTime create = new DateTime("2020-06-15");
        System.out.println(contractStart.monthOfYear().getDateTime());
        System.out.println(contractStart.dayOfMonth().withMaximumValue().plusDays(1));
        System.out.println(contractStart.dayOfMonth().withMaximumValue().plusDays(9).isBefore(create));
        System.out.println(contractStart.compareTo(create));

        long ss = new BigDecimal(94000 * 1.0 / 52)
                .setScale(0, BigDecimal.ROUND_HALF_UP).longValue();
        System.out.println(ss);

        DateTime[][] times = new DateTime[][]{
                {new DateTime(), new DateTime()},
                {new DateTime(), new DateTime()}
        };
        System.out.println(times[1][0].toString());
    }
}
