service-fee/src/main/java/com/java110/fee/cmd/fee/PayFeeCmd.java
@@ -13,10 +13,7 @@
import com.java110.core.smo.IComputeFeeSMO;
import com.java110.dto.account.AccountDto;
import com.java110.dto.account.AccountDetailDto;
import com.java110.dto.fee.FeeAttrDto;
import com.java110.dto.fee.FeeConfigDto;
import com.java110.dto.fee.FeeDto;
import com.java110.dto.fee.FeeReceiptDetailDto;
import com.java110.dto.fee.*;
import com.java110.dto.owner.OwnerCarDto;
import com.java110.dto.parking.ParkingSpaceDto;
import com.java110.dto.repair.RepairDto;
@@ -32,6 +29,7 @@
import com.java110.intf.user.IOwnerCarInnerServiceSMO;
import com.java110.intf.user.IUserV1InnerServiceSMO;
import com.java110.po.account.AccountDetailPo;
import com.java110.po.fee.FeeAttrPo;
import com.java110.po.room.ApplyRoomDiscountPo;
import com.java110.po.car.OwnerCarPo;
import com.java110.po.fee.PayFeeDetailPo;
@@ -41,6 +39,7 @@
import com.java110.po.owner.RepairUserPo;
import com.java110.po.payFee.PayFeeDetailDiscountPo;
import com.java110.utils.cache.CommonCache;
import com.java110.utils.constant.CommonConstant;
import com.java110.utils.constant.FeeFlagTypeConstant;
import com.java110.utils.constant.ResponseConstant;
import com.java110.utils.exception.CmdException;
@@ -176,11 +175,17 @@
        if (feeConfigDtos == null || feeConfigDtos.size() != 1) {
            throw new IllegalArgumentException("费用项不存在");
        }
        //一次性费用 和间接性费用
        /*//一次性费用 和间接性费用
        Date maxEndTime = feeDtos.get(0).getDeadlineTime();
        //周期性费用
        if (maxEndTime == null || FeeDto.FEE_FLAG_CYCLE.equals(feeConfigDtos.get(0).getFeeFlag())) {
            maxEndTime = DateUtil.getDateFromStringA(feeConfigDtos.get(0).getEndTime());
        }*/
        Date maxEndTime = null;
        if (!StringUtil.isEmpty(feeDto.getFeeFlag()) && feeDto.getFeeFlag().equals(FeeDto.FEE_FLAG_CYCLE)) { //周期性费用
            maxEndTime = DateUtil.getDateFromStringA(feeConfigDtos.get(0).getEndTime());
        } else { //一次性费用 和间接性费用
            maxEndTime = feeDtos.get(0).getDeadlineTime();
        }
        if (maxEndTime != null && endTime != null && !FeeDto.FEE_FLAG_ONCE.equals(feeConfigDtos.get(0).getFeeFlag())) {
@@ -196,6 +201,9 @@
            JSONObject param = params.getJSONObject(paramIndex);
            String maximumNumber = param.getString("maximumNumber");
        }
        //todo 是否按缴费时间段缴费
        validateIfPayFeeStartEndDate(reqJson, feeConfigDtos.get(0));
    }
@@ -210,13 +218,20 @@
        List<UserDto> userDtos = userV1InnerServiceSMOImpl.queryUsers(userDto);
        Assert.listOnlyOne(userDtos, "用户未登录");
        String cycles = paramObj.getString("cycles");
        Date endTime = null;
        PayFeePo payFeePo = null;
        String requestId = DistributedLock.getLockUUID();
        String key = this.getClass().getSimpleName() + paramObj.get("feeId");
        try {
            DistributedLock.waitGetDistributedLock(key, requestId);
            //todo 封装 缴费记录报文
            JSONObject feeDetail = addFeeDetail(paramObj);
            FeeDto feeInfo = (FeeDto) paramObj.get("feeInfo");
            endTime = feeInfo.getEndTime();
            feeDetail.put("payableAmount", feeDetail.getString("receivableAmount"));
            //todo 封装 修改费用时间报文
            JSONObject fee = modifyFee(paramObj);
            payFeePo = BeanConvertUtil.covertBean(fee, PayFeePo.class);
            PayFeeDetailPo payFeeDetailPo = BeanConvertUtil.covertBean(feeDetail, PayFeeDetailPo.class);
@@ -244,10 +259,12 @@
            if (flag < 1) {
                throw new CmdException("缴费失败");
            }
            // todo 如果是按 自定义时间段缴费,这里补一条缴费记录 和 欠费费用
            ifCustomStartEndTimePayFee(cycles, endTime, payFeeDetailPo, payFeePo, paramObj);
        } catch (ParseException e) {
            e.printStackTrace();
        } finally {
            DistributedLock.releaseDistributedLock(requestId, key);
            DistributedLock.releaseDistributedLock(key, requestId);
        }
        //账户处理
        dealAccount(paramObj);
@@ -288,6 +305,7 @@
        cmdDataFlowContext.setResponseEntity(ResultVo.createResponseEntity(feeReceiptDetailDto));
    }
    private void dealUserAccount(JSONObject paramObj, PayFeeDetailPo payFeeDetailPo) {
        //判断选择的账号
@@ -693,7 +711,7 @@
        BigDecimal cycles = null;
        Map feePriceAll = computeFeeSMOImpl.getFeePrice(feeDto);
        BigDecimal feePrice = new BigDecimal(feePriceAll.get("feePrice").toString());
        if ("-101".equals(paramInJson.getString("cycles"))) {
        if ("-101".equals(paramInJson.getString("cycles"))) { // 自定义金额交费
            Date endTime = feeDto.getEndTime();
            Calendar endCalender = Calendar.getInstance();
            endCalender.setTime(endTime);
@@ -707,6 +725,10 @@
            if (paramInJson.containsKey("receivableAmount") && !StringUtil.isEmpty(paramInJson.getString("receivableAmount"))) {
                businessFeeDetail.put("receivableAmount", paramInJson.getString("receivableAmount"));
            } else {
                businessFeeDetail.put("receivableAmount", receivedAmount.doubleValue());
            }
            //todo 如果应收小于实收,将应收刷为 实收
            if (businessFeeDetail.getDoubleValue("receivableAmount") < receivedAmount.doubleValue()) {
                businessFeeDetail.put("receivableAmount", receivedAmount.doubleValue());
            }
        } else if ("-103".equals(paramInJson.getString("cycles"))) { //这里按缴费结束时间缴费
@@ -728,7 +750,36 @@
            } else {
                businessFeeDetail.put("receivableAmount", receivedAmount.doubleValue());
            }
        } else {
            //todo 如果应收小于实收,将应收刷为 实收
            if (businessFeeDetail.getDoubleValue("receivableAmount") < receivedAmount.doubleValue()) {
                businessFeeDetail.put("receivableAmount", receivedAmount.doubleValue());
            }
        } else if ("-105".equals(paramInJson.getString("cycles"))) { //这里按缴费结束时间缴费
            String customEndTime = paramInJson.getString("customEndTime");
            Date endDates = DateUtil.getDateFromStringB(customEndTime);
            Calendar c = Calendar.getInstance();
            c.setTime(endDates);
            c.add(Calendar.DAY_OF_MONTH, 1);
            endDates = c.getTime();//这是明天
            targetEndTime = endDates;
            BigDecimal receivedAmount1 = new BigDecimal(Double.parseDouble(paramInJson.getString("receivedAmount")));
            cycles = receivedAmount1.divide(feePrice, 4, BigDecimal.ROUND_HALF_EVEN);
            paramInJson.put("tmpCycles", cycles.doubleValue());
            businessFeeDetail.put("cycles", cycles.doubleValue());
            BigDecimal receivedAmount = new BigDecimal(Double.parseDouble(paramInJson.getString("receivedAmount")));
            //处理 可能还存在 实收手工减免的情况
            if (paramInJson.containsKey("receivableAmount") && !StringUtil.isEmpty(paramInJson.getString("receivableAmount"))) {
                businessFeeDetail.put("receivableAmount", paramInJson.getString("receivableAmount"));
            } else {
                businessFeeDetail.put("receivableAmount", receivedAmount.doubleValue());
            }
            //todo 如果应收小于实收,将应收刷为 实收
            if (businessFeeDetail.getDoubleValue("receivableAmount") < receivedAmount.doubleValue()) {
                businessFeeDetail.put("receivableAmount", receivedAmount.doubleValue());
            }
            //todo 改写开始时间
            businessFeeDetail.put("startTime", paramInJson.getString("customStartTime"));
        } else { //自定义周期
            targetEndTime = computeFeeSMOImpl.getFeeEndTimeByCycles(feeDto, paramInJson.getString("cycles"));//根据缴费周期计算 结束时间
            cycles = new BigDecimal(Double.parseDouble(paramInJson.getString("cycles")));
            double tmpReceivableAmount = cycles.multiply(feePrice).setScale(2, BigDecimal.ROUND_HALF_EVEN).doubleValue();
@@ -741,6 +792,7 @@
                }
            }
        }
        businessFeeDetail.put("endTime", DateUtil.getFormatTimeString(targetEndTime, DateUtil.DATE_FORMATE_STRING_A));
        paramInJson.put("feeInfo", feeDto);
@@ -761,6 +813,14 @@
        } else if ("-103".equals(paramInJson.getString("cycles"))) {
            String custEndTime = paramInJson.getString("custEndTime");
            Date endDates = DateUtil.getDateFromStringB(custEndTime);
            Calendar c = Calendar.getInstance();
            c.setTime(endDates);
            c.add(Calendar.DAY_OF_MONTH, 1);
            endDates = c.getTime();//这是明天
            endCalender.setTime(endDates);
        } else if ("-105".equals(paramInJson.getString("cycles"))) {
            String customEndTime = paramInJson.getString("customEndTime");
            Date endDates = DateUtil.getDateFromStringB(customEndTime);
            Calendar c = Calendar.getInstance();
            c.setTime(endDates);
            c.add(Calendar.DAY_OF_MONTH, 1);
@@ -960,6 +1020,151 @@
        }
    }
    /**
     * 校验是否按缴费时间段缴费
     *
     * @param reqJson
     * @param feeConfigDto
     */
    private void validateIfPayFeeStartEndDate(JSONObject reqJson, FeeConfigDto feeConfigDto) {
        if (!"-105".equals(reqJson.getString("cycles"))) {
            return;
        }
        // todo 自己是间接性费用
        if (FeeDto.FEE_FLAG_CYCLE_ONCE.equals(feeConfigDto.getFeeFlag())) {
            return;
        }
        FeeConfigDto tmpFeeConfigDto = new FeeConfigDto();
        tmpFeeConfigDto.setFeeNameEq(feeConfigDto.getFeeName() + "欠费");
        tmpFeeConfigDto.setFeeFlag(FeeDto.FEE_FLAG_CYCLE_ONCE);
        tmpFeeConfigDto.setComputingFormula(feeConfigDto.getComputingFormula());
        List<FeeConfigDto> feeConfigDtos = feeConfigInnerServiceSMOImpl.queryFeeConfigs(tmpFeeConfigDto);
        Assert.listOnlyOne(feeConfigDtos, "按自定义时间段缴费时,费用必须为间接性费用,或者存在名称为 " + feeConfigDto.getFeeName() + "欠费 的间接性费用,它的公式计算必须要和" + feeConfigDto.getFeeName() + "一致");
    }
    /**
     * 自定义时间段 缴费
     *
     * @param cycles
     * @param endTime
     * @param payFeeDetailPo
     * @param payFeePo
     */
    private void ifCustomStartEndTimePayFee(String cycles, Date endTime, PayFeeDetailPo payFeeDetailPo, PayFeePo payFeePo, JSONObject reqJson) {
        if (!"-105".equals(cycles)) {
            return;
        }
        FeeDto feeInfo = (FeeDto) reqJson.get("feeInfo");
        String payObjNameRemark = "房屋";
        if (FeeDto.PAYER_OBJ_TYPE_CAR.equals(feeInfo.getPayerObjType())) {
            payObjNameRemark = "车辆";
        } else if (FeeDto.PAYER_OBJ_TYPE_CONTRACT.equals(feeInfo.getPayerObjType())) {
            payObjNameRemark = "合同";
        }
        //todo 补充一条 缴费记录数据
        PayFeeDetailPo tmpPayFeeDetailPo = BeanConvertUtil.covertBean(payFeeDetailPo, PayFeeDetailPo.class);
        tmpPayFeeDetailPo.setDetailId(GenerateCodeFactory.getGeneratorId(GenerateCodeFactory.CODE_PREFIX_detailId));
        tmpPayFeeDetailPo.setCycles("0");
        tmpPayFeeDetailPo.setReceivableAmount("0");
        tmpPayFeeDetailPo.setReceivedAmount("0");
        tmpPayFeeDetailPo.setPayableAmount("0");
        tmpPayFeeDetailPo.setStartTime(DateUtil.getFormatTimeStringB(endTime));
        tmpPayFeeDetailPo.setEndTime(reqJson.getString("customStartTime"));
        tmpPayFeeDetailPo.setState(FeeDetailDto.STATE_OWE);
        tmpPayFeeDetailPo.setRemark("按缴费时间段缴费,这部分费用按欠费的方式重新生成,请在" + payObjNameRemark + "上查看");
        int flag = payFeeDetailNewV1InnerServiceSMOImpl.savePayFeeDetailNew(tmpPayFeeDetailPo);
        if (flag < 1) {
            throw new CmdException("生成欠费失败");
        }
        //todo 生成费用
        PayFeePo tmpPayFeePo = BeanConvertUtil.covertBean(feeInfo, PayFeePo.class);
        tmpPayFeePo.setFeeId(GenerateCodeFactory.getGeneratorId(GenerateCodeFactory.CODE_PREFIX_feeId));
        tmpPayFeePo.setEndTime(DateUtil.getFormatTimeStringB(endTime));
        tmpPayFeePo.setState(FeeDto.STATE_DOING);
        // todo 处理configId
        doChangeConfigId(tmpPayFeePo, feeInfo);
        flag = payFeeV1InnerServiceSMOImpl.savePayFee(tmpPayFeePo);
        if (flag < 1) {
            throw new CmdException("生成欠费失败");
        }
        //todo 补充 费用属性
        FeeAttrDto feeAttrDto = new FeeAttrDto();
        feeAttrDto.setFeeId(payFeePo.getFeeId());
        feeAttrDto.setCommunityId(payFeePo.getCommunityId());
        List<FeeAttrDto> feeAttrDtos = feeAttrInnerServiceSMOImpl.queryFeeAttrs(feeAttrDto);
        if (feeAttrDtos == null || feeAttrDtos.size() < 1) {
            return;
        }
        List<FeeAttrPo> tmpFeeAttrPos = new ArrayList<>();
        FeeAttrPo tmpFeeAttrPo = null;
        boolean hasDeadLineTime = false;
        for (FeeAttrDto tmpFeeAttrDto : feeAttrDtos) {
            tmpFeeAttrDto.setFeeId(tmpPayFeePo.getFeeId());
            tmpFeeAttrDto.setAttrId(GenerateCodeFactory.getGeneratorId(GenerateCodeFactory.CODE_PREFIX_attrId, true));
            if (FeeAttrDto.SPEC_CD_ONCE_FEE_DEADLINE_TIME.equals(tmpFeeAttrDto.getSpecCd())) {
                tmpFeeAttrDto.setValue(reqJson.getString("customStartTime"));
                hasDeadLineTime = true;
            }
            tmpFeeAttrPo = BeanConvertUtil.covertBean(tmpFeeAttrDto, FeeAttrPo.class);
            tmpFeeAttrPos.add(tmpFeeAttrPo);
        }
        //todo 没有结束时间时
        if(!hasDeadLineTime){
            tmpFeeAttrPo = new FeeAttrPo();
            tmpFeeAttrPo.setAttrId(GenerateCodeFactory.getGeneratorId(GenerateCodeFactory.CODE_PREFIX_attrId, true));
            tmpFeeAttrPo.setFeeId(tmpPayFeePo.getFeeId());
            tmpFeeAttrPo.setCommunityId(tmpFeeAttrPo.getCommunityId());
            tmpFeeAttrPo.setSpecCd(FeeAttrDto.SPEC_CD_ONCE_FEE_DEADLINE_TIME);
            tmpFeeAttrPo.setValue(reqJson.getString("customStartTime"));
            tmpFeeAttrPos.add(tmpFeeAttrPo);
        }
        feeAttrInnerServiceSMOImpl.saveFeeAttrs(tmpFeeAttrPos);
    }
    /**
     * 处理费用项ID
     *
     * @param tmpPayFeePo
     * @param feeInfo
     */
    private void doChangeConfigId(PayFeePo tmpPayFeePo, FeeDto feeInfo) {
        FeeConfigDto feeConfigDto = new FeeConfigDto();
        feeConfigDto.setConfigId(feeInfo.getConfigId());
        feeConfigDto.setCommunityId(feeInfo.getCommunityId());
        List<FeeConfigDto> feeConfigDtos = feeConfigInnerServiceSMOImpl.queryFeeConfigs(feeConfigDto);
        Assert.listOnlyOne(feeConfigDtos, "费用项不存在");
        if (FeeDto.FEE_FLAG_CYCLE_ONCE.equals(feeConfigDtos.get(0).getFeeFlag())) {
            return;
        }
        FeeConfigDto tmpFeeConfigDto = new FeeConfigDto();
        tmpFeeConfigDto.setFeeNameEq(feeConfigDtos.get(0).getFeeName() + "欠费");
        tmpFeeConfigDto.setFeeFlag(FeeDto.FEE_FLAG_CYCLE_ONCE);
        tmpFeeConfigDto.setComputingFormula(feeConfigDto.getComputingFormula());
        //todo 校验的时候校验过了 所以这里不可能为空
        feeConfigDtos = feeConfigInnerServiceSMOImpl.queryFeeConfigs(tmpFeeConfigDto);
        tmpPayFeePo.setConfigId(feeConfigDtos.get(0).getConfigId());
    }
    private static Calendar getTargetEndTime(Calendar endCalender, Double cycles) {
        if (StringUtil.isInteger(cycles.toString())) {
            endCalender.add(Calendar.MONTH, new Double(cycles).intValue());