xiaogang
2023-07-19 0ed29a9b6e7cdeeea5f736d5cbe196849b4f22f7
service-fee/src/main/java/com/java110/fee/feeMonth/PayFeeMonthHelp.java
@@ -1,15 +1,16 @@
package com.java110.fee.feeMonth;
import com.java110.core.factory.GenerateCodeFactory;
import com.java110.core.smo.IComputeFeeSMO;
import com.java110.dto.fee.FeeAttrDto;
import com.java110.dto.fee.FeeDetailDto;
import com.java110.dto.fee.FeeDto;
import com.java110.dto.fee.MonthFeeDetailDto;
import com.java110.dto.payFeeDetailMonth.PayFeeMonthOwnerDto;
import com.java110.dto.payFee.PayFeeDetailMonthDto;
import com.java110.dto.payFee.PayFeeMonthOwnerDto;
import com.java110.intf.community.IRoomInnerServiceSMO;
import com.java110.utils.util.BeanConvertUtil;
import com.java110.intf.fee.IPayFeeDetailMonthInnerServiceSMO;
import com.java110.po.payFee.PayFeeDetailMonthPo;
import com.java110.utils.util.DateUtil;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -24,6 +25,9 @@
    @Autowired
    private IComputeFeeSMO computeFeeSMOImpl;
    @Autowired
    private IPayFeeDetailMonthInnerServiceSMO payFeeDetailMonthInnerServiceSMOImpl;
    public PayFeeMonthOwnerDto generatorOwnerRoom(FeeDto feeDto) {
@@ -48,38 +52,19 @@
        Double feePrice = Double.parseDouble(feePriceAll.get("feePrice").toString());
        //todo 如果是一次性费用 除以
        if (!FeeDto.FEE_FLAG_ONCE.equals(feeDto.getPayerObjType())) {
            return feePrice;
        }
        List<String> months = DateUtil.getMonthBetweenDate(feeDto.getStartTime(), feeDto.getEndTime());
        //double maxMonth = Math.ceil(computeFeeSMOImpl.dayCompare(feeDto.getStartTime(), feeDto.getEndTime()));
        if (months == null || months.size() <= 0) {
            return feePrice;
        }
        BigDecimal feePriceDec = new BigDecimal(feePrice).divide(new BigDecimal(months.size()), 4, BigDecimal.ROUND_HALF_UP);
        feePrice = feePriceDec.doubleValue();
//        if (!FeeDto.FEE_FLAG_ONCE.equals(feeDto.getPayerObjType())) {
//            return feePrice;
//        }
//        double maxMonth = Math.ceil(computeFeeSMOImpl.dayCompare(feeDto.getStartTime(), feeDto.getEndTime()));
//        if (maxMonth <= 0) {
//            return feePrice;
//
//        }
//        BigDecimal feePriceDec = new BigDecimal(feePrice).divide(new BigDecimal(maxMonth), 2, BigDecimal.ROUND_HALF_UP);
//        feePrice = feePriceDec.doubleValue();
        return feePrice;
    }
    public Double getReceivableAmount(List<FeeDetailDto> feeDetailDtos, Map<String, MonthFeeDetailDto> monthFeeDetailDtos, Double feePrice, Date curDate, FeeDto feeDto) {
        MonthFeeDetailDto monthFeeDetailDto = getCurMonthFeeDetail(monthFeeDetailDtos, curDate);
        if (monthFeeDetailDto == null && curDate.getTime() < feeDto.getEndTime().getTime()) {
            return 0.00;
        }
        return feePrice;
    }
    @Override
    public Double getReceivedAmount(List<FeeDetailDto> feeDetailDtos, Map<String, MonthFeeDetailDto> monthFeeDetailDtos, Double feePrice, Date curDate, FeeDto feeDto) {
        MonthFeeDetailDto monthFeeDetailDto = getCurMonthFeeDetail(monthFeeDetailDtos, curDate);
        if (monthFeeDetailDto == null) {
            return 0.0;
        }
        return monthFeeDetailDto.getReceivedAmount();
    }
    @Override
    public Double getDiscountAmount(Double feePrice, double receivedAmount, Date curDate, FeeDto feeDto) {
@@ -93,152 +78,260 @@
        return discountAmountDec.doubleValue();
    }
    @Override
    public String getFeeDetailId(List<FeeDetailDto> feeDetailDtos, Date curDate) {
        FeeDetailDto feeDetailDto = getCurFeeDetail(feeDetailDtos, curDate);
        if (feeDetailDto == null) {
            return "-1";
        }
        return feeDetailDto.getDetailId();
    }
    @Override
    public String getFeeFeeTime(List<FeeDetailDto> feeDetailDtos, String detailId) {
        if (feeDetailDtos == null || feeDetailDtos.size() < 1) {
            return null;
        }
        for (FeeDetailDto feeDetailDto : feeDetailDtos) {
            if (feeDetailDto.getDetailId().equals(detailId)) {
                return DateUtil.getFormatTimeStringA(feeDetailDto.getCreateTime());
            }
        }
        return null;
    }
    /**
     * 获取当前缴费记录
     * 处理已经交过费的记录处理
     *
     * @param feeDetailDtos
     * @param curDate
     * @return
     * @param feeDto
     * @param payFeeMonthOwnerDto
     */
    private FeeDetailDto getCurFeeDetail(List<FeeDetailDto> feeDetailDtos, Date curDate) {
        if (feeDetailDtos == null || feeDetailDtos.size() < 1) {
            return null;
        }
        List<FeeDetailDto> tFeeDetailDtos = new ArrayList<>();
        for (FeeDetailDto feeDetailDto : feeDetailDtos) {
            if (feeDetailDto.getStartTime().getTime() <= curDate.getTime() && feeDetailDto.getEndTime().getTime() > curDate.getTime()) {
                tFeeDetailDtos.add(BeanConvertUtil.covertBean(feeDetailDto, FeeDetailDto.class));
            }
        }
        if (tFeeDetailDtos.size() < 1) {
            return null;
        }
        if (tFeeDetailDtos.size() == 1) {
            return tFeeDetailDtos.get(0);
        }
        //todo 这种应该是数据异常 也就是一个月费用变更后重复缴费
        BigDecimal cReceivedAmount = new BigDecimal(0.00);
        for (FeeDetailDto feeDetailDto : tFeeDetailDtos) {
            cReceivedAmount = cReceivedAmount.add(new BigDecimal(Double.parseDouble(feeDetailDto.getReceivedAmount()))).setScale(4, BigDecimal.ROUND_HALF_UP);
        }
        tFeeDetailDtos.get(0).setReceivedAmount(cReceivedAmount.doubleValue() + "");
        return tFeeDetailDtos.get(0);
    }
    @Override
    public Map<String, MonthFeeDetailDto> analysisMonthFeeDetail(List<FeeDetailDto> feeDetailDtos) {
    public void waitDispersedFeeDetail(FeeDto feeDto, PayFeeMonthOwnerDto payFeeMonthOwnerDto) {
        PayFeeDetailMonthDto payFeeDetailMonthDto = new PayFeeDetailMonthDto();
        payFeeDetailMonthDto.setCommunityId(feeDto.getCommunityId());
        payFeeDetailMonthDto.setFeeId(feeDto.getFeeId());
        List<FeeDetailDto> feeDetailDtos = payFeeDetailMonthInnerServiceSMOImpl.getWaitDispersedFeeDetail(payFeeDetailMonthDto);
        if (feeDetailDtos == null || feeDetailDtos.size() < 1) {
            return null;
        }
        Map<String, MonthFeeDetailDto> monthFeeDetailDtos = new HashMap<>();
        for (FeeDetailDto feeDetailDto : feeDetailDtos) {
            Date endTime =  feeDetailDto.getEndTime();
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(endTime);
            calendar.add(Calendar.DAY_OF_MONTH,-1);
            if(feeDetailDto.getStartTime().getTime()< calendar.getTime().getTime()){
                endTime = calendar.getTime();
            }
            //计算两个日期包含的月份
            List<String> months = DateUtil.getMonthBetweenDate(feeDetailDto.getStartTime(), endTime);
            if (months == null || months.size() < 1) {
                putReceivedAmountToMonthFeeDetailDtos(monthFeeDetailDtos,
                        DateUtil.getFormatTimeString(feeDetailDto.getStartTime(), DateUtil.DATE_FORMATE_STRING_Q),
                        Double.parseDouble(feeDetailDto.getReceivedAmount()),
                        feeDetailDto);
                continue;
            }
            BigDecimal totalRecDec = new BigDecimal(feeDetailDto.getReceivedAmount());
            //每月平均值
            BigDecimal priRecDec = totalRecDec.divide(new BigDecimal(months.size()), 4, BigDecimal.ROUND_HALF_UP);
            for (String month : months) {
                putReceivedAmountToMonthFeeDetailDtos(monthFeeDetailDtos,
                        month,
                        priRecDec.doubleValue(),
                        feeDetailDto);
            }
        }
        return monthFeeDetailDtos;
    }
    /**
     * 月份存放起来
     *
     * @param monthFeeDetailDtos
     * @param month
     * @param receivedAmount
     */
    private void putReceivedAmountToMonthFeeDetailDtos(Map<String, MonthFeeDetailDto> monthFeeDetailDtos,
                                                       String month,
                                                       double receivedAmount,
                                                       FeeDetailDto feeDetailDto) {
        if (!monthFeeDetailDtos.containsKey(month)) {
            monthFeeDetailDtos.put(month, new MonthFeeDetailDto(receivedAmount, feeDetailDto));
            return;
        }
        MonthFeeDetailDto monthFeeDetailDto = monthFeeDetailDtos.get(month);
        BigDecimal recDec = new BigDecimal(monthFeeDetailDto.getReceivedAmount()).add(new BigDecimal(receivedAmount)).setScale(4, BigDecimal.ROUND_HALF_UP);
        monthFeeDetailDto.setReceivedAmount(recDec.doubleValue());
        monthFeeDetailDto.getFeeDetailDtos().add(feeDetailDto);
        monthFeeDetailDtos.put(month, monthFeeDetailDto);
        for (FeeDetailDto feeDetailDto : feeDetailDtos) {
            // todo 逐条去离散
            doDispersedFeeDetail(feeDetailDto, feeDto, payFeeMonthOwnerDto);
        }
    }
    /**
     * 处理 欠费 离散
     *
     * @param feeDto
     * @param payFeeMonthOwnerDto
     * @param feePrice
     * @param deadlineTime
     */
    @Override
    public void waitDispersedOweFee(FeeDto feeDto, PayFeeMonthOwnerDto payFeeMonthOwnerDto, Double feePrice, Date deadlineTime) {
        // todo 费用已经结束
        if (FeeDto.STATE_FINISH.equals(feeDto.getState())) {
            return;
        }
        // todo 清理 detailId 为-1 的数据
        PayFeeDetailMonthPo payFeeDetailMonthPo = new PayFeeDetailMonthPo();
        payFeeDetailMonthPo.setCommunityId(feeDto.getCommunityId());
        payFeeDetailMonthPo.setFeeId(feeDto.getFeeId());
        payFeeDetailMonthPo.setDetailId("-1");
        payFeeDetailMonthInnerServiceSMOImpl.deletePayFeeDetailMonth(payFeeDetailMonthPo);
        List<PayFeeDetailMonthPo> payFeeDetailMonthPos = new ArrayList<>();
        // todo 处理 开始时间和结束时间
        Date startTime = DateUtil.timeToDate(feeDto.getEndTime());
        Date endTime = DateUtil.timeToDate(deadlineTime);
        BigDecimal receivableAmount = new BigDecimal(feePrice);
        BigDecimal dayReceivableAmount = null;
        //todo 一次性费用 日应收计算
        if (FeeDto.FEE_FLAG_ONCE.equals(feeDto.getFeeFlag())) {
            int day = DateUtil.daysBetween(endTime, startTime);
            if (day < 1) {
                day = 1;
            }
            dayReceivableAmount = receivableAmount.divide(new BigDecimal(day), 8, BigDecimal.ROUND_HALF_UP);// 日 应收
        }
        // todo 寻找第一个自然月 一日
        Calendar firstMonthDayCal = Calendar.getInstance();
        firstMonthDayCal.setTime(startTime);
        firstMonthDayCal.add(Calendar.MONTH, 1);
        firstMonthDayCal.set(Calendar.DAY_OF_MONTH, 1);
        Date firstMonthDayTime = firstMonthDayCal.getTime();
        Date startMonthDayTime = startTime;
        // todo  循环,只到 firstMonthDayTime 大于 endTime
        int curDay = 0;
        int curMonthMaxDay = 30;
        BigDecimal curMonthReceivableAmount = null;
        while (firstMonthDayTime.getTime() < endTime.getTime()) {
            curDay = DateUtil.daysBetween(firstMonthDayTime, startMonthDayTime);
            // todo 计算当月天数
            Calendar calendar = Calendar.getInstance();
            calendar.setTime(startMonthDayTime);
            curMonthMaxDay = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
            // todo 如果不是整月,则转换为按天计算
//            if (curDay != curMonthMaxDay) {
                //todo 周期性费用 日应收重新算
                if (!FeeDto.FEE_FLAG_ONCE.equals(feeDto.getFeeFlag())) {
                    dayReceivableAmount = receivableAmount.divide(new BigDecimal(curMonthMaxDay), 8, BigDecimal.ROUND_HALF_UP);// 日 实收
                }
                // todo 计算 应收
                curMonthReceivableAmount = new BigDecimal(curDay).multiply(dayReceivableAmount).setScale(4, BigDecimal.ROUND_HALF_UP);
//            } else { // todo 如果是整月 那就按月计算,以免 转换成天再 乘以天数后的误差
//                curMonthReceivableAmount = receivableAmount;
//            }
            // todo 保存数据到pay_fee_detail_month
            toSavePayFeeDetailMonth(curMonthReceivableAmount.doubleValue(), 0, null, feeDto, payFeeMonthOwnerDto, payFeeDetailMonthPos, startMonthDayTime, deadlineTime);
            // todo 将startTime 修改为 下月1日时间
            startMonthDayTime = firstMonthDayTime;
            firstMonthDayCal.add(Calendar.MONTH, 1);
            firstMonthDayTime = firstMonthDayCal.getTime();
        }
        //todo 最后处理 最后 startMonthDayTime 到endTime 的
        if (startMonthDayTime.getTime() >= endTime.getTime()) {
            payFeeDetailMonthInnerServiceSMOImpl.savePayFeeDetailMonths(payFeeDetailMonthPos);
            return;
        }
        curDay = DateUtil.daysBetween(endTime, startMonthDayTime);
        // todo 计算当月天数
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(startMonthDayTime);
        curMonthMaxDay = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
        // todo 如果不是整月,则转换为按天计算
        if (curDay != curMonthMaxDay) {
            //todo 周期性费用 日应收重新算
            if (!FeeDto.FEE_FLAG_ONCE.equals(feeDto.getFeeFlag())) {
                dayReceivableAmount = receivableAmount.divide(new BigDecimal(curMonthMaxDay), 4, BigDecimal.ROUND_HALF_UP);// 日 实收
            }
            // todo 计算 应收
            curMonthReceivableAmount = new BigDecimal(curDay).multiply(dayReceivableAmount).setScale(4, BigDecimal.ROUND_HALF_UP);
        } else { // todo 如果是整月 那就按月计算,以免 转换成天再 乘以天数后的误差
            curMonthReceivableAmount = receivableAmount;
        }
        // todo 保存数据到pay_fee_detail_month
        toSavePayFeeDetailMonth(curMonthReceivableAmount.doubleValue(), 0, null, feeDto, payFeeMonthOwnerDto, payFeeDetailMonthPos, startMonthDayTime, deadlineTime);
        payFeeDetailMonthInnerServiceSMOImpl.savePayFeeDetailMonths(payFeeDetailMonthPos);
    }
    private void doDispersedFeeDetail(FeeDetailDto feeDetailDto, FeeDto feeDto, PayFeeMonthOwnerDto
            payFeeMonthOwnerDto) {
        List<PayFeeDetailMonthPo> payFeeDetailMonthPos = new ArrayList<>();
        // todo 去除 开始时间和 结束时间的 小时 分钟 秒
        Date startTime = DateUtil.timeToDate(feeDetailDto.getStartTime());
        Date endTime = DateUtil.timeToDate(feeDetailDto.getEndTime());
        int day = DateUtil.daysBetween(endTime, startTime);
        if (day < 1) {
            day = 1;
        }
        BigDecimal receivableAmount = new BigDecimal(Double.parseDouble(feeDetailDto.getReceivableAmount()));
        BigDecimal receivedAmount = new BigDecimal(Double.parseDouble(feeDetailDto.getReceivedAmount()));
        BigDecimal dayReceivableAmount = receivableAmount.divide(new BigDecimal(day), 8, BigDecimal.ROUND_HALF_UP);// 日 应收
        BigDecimal dayReceivedAmount = receivedAmount.divide(new BigDecimal(day), 8, BigDecimal.ROUND_HALF_UP);// 日 实收
        // todo 寻找第一个自然月 一日
        Calendar firstMonthDayCal = Calendar.getInstance();
        firstMonthDayCal.setTime(startTime);
        firstMonthDayCal.add(Calendar.MONTH, 1);
        firstMonthDayCal.set(Calendar.DAY_OF_MONTH, 1);
        Date firstMonthDayTime = firstMonthDayCal.getTime();
        Date startMonthDayTime = startTime;
        // todo  循环,只到 firstMonthDayTime 大于 endTime
        int curDay = 0;
        BigDecimal curMonthReceivableAmount = null;
        BigDecimal curMonthReceivedAmount = null;
        while (firstMonthDayTime.getTime() < endTime.getTime()) {
            curDay = DateUtil.daysBetween(firstMonthDayTime, startMonthDayTime);
            // todo 计算 应收
            curMonthReceivableAmount = new BigDecimal(curDay).multiply(dayReceivableAmount).setScale(4, BigDecimal.ROUND_HALF_UP);
            // todo 计算 实收
            curMonthReceivedAmount = new BigDecimal(curDay).multiply(dayReceivedAmount).setScale(4, BigDecimal.ROUND_HALF_UP);
            // todo 保存数据到pay_fee_detail_month
            toSavePayFeeDetailMonth(curMonthReceivableAmount.doubleValue(), curMonthReceivedAmount.doubleValue(), feeDetailDto, feeDto, payFeeMonthOwnerDto, payFeeDetailMonthPos, startMonthDayTime, endTime);
            // todo 将startTime 修改为 下月1日时间
            startMonthDayTime = firstMonthDayTime;
            firstMonthDayCal.add(Calendar.MONTH, 1);
            firstMonthDayTime = firstMonthDayCal.getTime();
        }
        //todo 最后处理 最后 startMonthDayTime 到endTime 的
        if (startMonthDayTime.getTime() >= endTime.getTime()) {
            payFeeDetailMonthInnerServiceSMOImpl.savePayFeeDetailMonths(payFeeDetailMonthPos);
            return;
        }
        curDay = DateUtil.daysBetween(endTime, startMonthDayTime);
        // todo 计算 应收
        curMonthReceivableAmount = new BigDecimal(curDay).multiply(dayReceivableAmount).setScale(4, BigDecimal.ROUND_HALF_UP);
        // todo 计算 实收
        curMonthReceivedAmount = new BigDecimal(curDay).multiply(dayReceivedAmount).setScale(4, BigDecimal.ROUND_HALF_UP);
        // todo 保存数据到pay_fee_detail_month
        toSavePayFeeDetailMonth(curMonthReceivableAmount.doubleValue(), curMonthReceivedAmount.doubleValue(), feeDetailDto, feeDto, payFeeMonthOwnerDto, payFeeDetailMonthPos, startMonthDayTime, endTime);
        payFeeDetailMonthInnerServiceSMOImpl.savePayFeeDetailMonths(payFeeDetailMonthPos);
    }
    /**
     * 月离散数据
     * 保存数据
     *
     * @param monthFeeDetailDtos
     * @param curDate
     * @return
     * @param receivableAmount
     * @param receivedAmount
     * @param feeDetailDto
     * @param feeDto
     */
    private MonthFeeDetailDto getCurMonthFeeDetail(Map<String, MonthFeeDetailDto> monthFeeDetailDtos, Date curDate) {
        String month = DateUtil.getFormatTimeString(curDate, DateUtil.DATE_FORMATE_STRING_M);
        if (monthFeeDetailDtos == null) {
            return null;
    private void toSavePayFeeDetailMonth(double receivableAmount,
                                         double receivedAmount,
                                         FeeDetailDto feeDetailDto,
                                         FeeDto feeDto,
                                         PayFeeMonthOwnerDto payFeeMonthOwnerDto,
                                         List<PayFeeDetailMonthPo> payFeeDetailMonthPos,
                                         Date curTime,
                                         Date deadlineTime) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(curTime);
        PayFeeDetailMonthPo tmpPayFeeDetailMonthPo = new PayFeeDetailMonthPo();
        tmpPayFeeDetailMonthPo.setFeeId(feeDto.getFeeId());
        tmpPayFeeDetailMonthPo.setCommunityId(feeDto.getCommunityId());
        if (feeDetailDto == null) {
            tmpPayFeeDetailMonthPo.setDetailId("-1");
        } else { // todo 交费记录 保存时
            tmpPayFeeDetailMonthPo.setDetailId(feeDetailDto.getDetailId());
        }
        if (!monthFeeDetailDtos.containsKey(month)) {
            return null;
        tmpPayFeeDetailMonthPo.setDetailYear(calendar.get(Calendar.YEAR) + "");
        tmpPayFeeDetailMonthPo.setDetailMonth((calendar.get(Calendar.MONTH) + 1) + "");
        tmpPayFeeDetailMonthPo.setReceivableAmount(receivableAmount + "");
        tmpPayFeeDetailMonthPo.setReceivedAmount(receivedAmount + "");
        tmpPayFeeDetailMonthPo.setDiscountAmount(
                getDiscountAmount(Double.parseDouble(tmpPayFeeDetailMonthPo.getReceivableAmount()),
                        Double.parseDouble(tmpPayFeeDetailMonthPo.getReceivedAmount()),
                        calendar.getTime(), feeDto) + "");
        tmpPayFeeDetailMonthPo.setMonthId(GenerateCodeFactory.getGeneratorId(GenerateCodeFactory.CODE_PREFIX_monthId, true));
        tmpPayFeeDetailMonthPo.setRemark("程序计算生成");
        tmpPayFeeDetailMonthPo.setObjName(payFeeMonthOwnerDto.getObjName());
        tmpPayFeeDetailMonthPo.setObjId(payFeeMonthOwnerDto.getObjId());
        tmpPayFeeDetailMonthPo.setOwnerId(payFeeMonthOwnerDto.getOwnerId());
        tmpPayFeeDetailMonthPo.setOwnerName(payFeeMonthOwnerDto.getOwnerName());
        tmpPayFeeDetailMonthPo.setLink(payFeeMonthOwnerDto.getLink());
        tmpPayFeeDetailMonthPo.setCurMonthTime(DateUtil.getFormatTimeStringB(calendar.getTime()));
        tmpPayFeeDetailMonthPo.setDeadlineTime(DateUtil.getFormatTimeStringA(deadlineTime));
        if (feeDetailDto == null) {
            tmpPayFeeDetailMonthPo.setPayFeeTime(null);
        } else { // todo 交费记录 保存时
            tmpPayFeeDetailMonthPo.setPayFeeTime(DateUtil.getFormatTimeStringA(feeDetailDto.getCreateTime()));
        }
        MonthFeeDetailDto monthFeeDetailDto = monthFeeDetailDtos.get(month);
        return monthFeeDetailDto;
        tmpPayFeeDetailMonthPo.setState("W"); // todo 这里暂时写死,目前用不到,算是预留字段
        tmpPayFeeDetailMonthPo.setFeeName(feeDto.getFeeName());
        tmpPayFeeDetailMonthPo.setConfigId(feeDto.getConfigId());
        payFeeDetailMonthPos.add(tmpPayFeeDetailMonthPo);
    }