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())) {
					//2021年7月19日21:01:20 补充:可能会出现补充协议套娃(B1,B2两个补充协议,但是其中B1补充协议因为主体权限原因没有查出来,B2要依赖B1计算单价,这时候要查出B1),所以需要重新查询一遍
					//不管主账号在不在,按照现有条件无法判断该补充协议是否被其他合同关联
					//只判断补充协议是因为,如果只有首签/续签的权限合同,对于后面的补充协议是不影响的
					//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) {
						if (StringUtils.isEmpty(map.get(contract1.getContractCode()))) {
							map.put(contract1.getContractCode(), contract1);
						}
					}
					groupContracts = map.values();//只要不加入传进来的那个list里面就不会影响查询的列表
					break;
				} else if ((groupContracts.size() == 1 && !StringUtils.isEmpty(groupContract.getNextSignedDate())) || (!"2".equals(groupContract.getContractType()) && map.get(groupContract.getNextSignedContractCode()) == null)) {
					List<Contract> contractList = contractRepository.findByRelationCode(groupContract.getContractCode());
					for (Contract contract1 : contractList) {
						if (StringUtils.isEmpty(map.get(contract1.getContractCode()))) {
							map.put(contract1.getContractCode(), contract1);
						}
					}
					groupContracts = map.values();
					break;
				}
			}


			//再次进行合同的关系分组--->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;
		//修改晚录判断逻辑
		int aferDays = dateTime.monthOfYear().get() == 12 ? 29 : 1;
		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-02");
		int aferDays = dateTime.monthOfYear().get() == 12 ? 29 : 1;
		System.out.println("合同开始时间" + dateTime);
		System.out.println("合同录入时间" + creatTime);
		System.out.println("合同开始时间在第" + dateTime.monthOfYear().get() + "月");
		System.out.println("合同录入当月的最后一天日期:" + dateTime.dayOfMonth().withMaximumValue());
		System.out.println("合同录入当月的最后一天日期后第" + aferDays + "天" + 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());
	}
}