瀏覽代碼

付款计划更新

zhangyao 1 月之前
父節點
當前提交
41ccae7132

+ 19 - 0
com.awspaas.user.apps.donenow_ivt/src/com/awspaas/user/apps/donenow_ivt/controller/ivtOrderController.java

@@ -18,6 +18,7 @@ import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.awspaas.user.apps.donenow_ivt.cache.formStatusCache;
 import com.awspaas.user.apps.donenow_ivt.constant.IVTConstant;
+import com.awspaas.user.apps.donenow_ivt.service.PaymentPlanService;
 import org.apache.commons.lang3.StringUtils;
 
 import java.math.BigDecimal;
@@ -927,4 +928,22 @@ public class ivtOrderController {
         return ResponseObject.newOkResponse();
     }
 
+
+    /**
+     * 创建付款计划
+     * @param uc
+     * @param orderId
+     * @return
+     */
+    @Mapping("com.awspaas.user.apps.donenow_ivt.createPaymentPlan")
+    public ResponseObject createPaymentPlan(UserContext uc, String orderId) {
+
+        PaymentPlanService.getInstance().createPaymentPlan(uc, orderId);
+
+        return ResponseObject.newOkResponse();
+    }
+
+
+
+
 }

+ 2 - 2
com.awspaas.user.apps.donenow_ivt/src/com/awspaas/user/apps/donenow_ivt/event/ivtOrderFormAfter.java

@@ -33,7 +33,7 @@ public class ivtOrderFormAfter extends ExecuteListener {
         logger.info("采购订单表单保存后,数据处理事件");
         BO orderBO = SDK.getBOAPI().getByProcess("BO_EU_DNIVT_ORDER", processExecutionContext.getProcessInstance().getId());
         List<BO> orderProducts = SDK.getBOAPI().query("BO_EU_DNIVT_ORDER_PRODUCT").bindId(orderBO.getBindId()).list();
-        List<BO> costProducts = SDK.getBOAPI().query("BO_EU_DNCTT_CONTRACT_COST_PRODUCT").addQuery("ORDER_ID=", orderBO.getId()).list();
+        List<BO> costProducts = SDK.getBOAPI().query("BO_EU_DNCTT_CONTRACT_COST_PRODUCT").addQuery("ORDER_ID =", orderBO.getId()).list();
 
         for (BO costProduct : costProducts) {
 
@@ -54,7 +54,7 @@ public class ivtOrderFormAfter extends ExecuteListener {
         //采购订单编号
         String purchaseOrderNo = orderBO.getString("PURCHASE_ORDER_NO");
         logger.info("采购订单编号:" + purchaseOrderNo);
-        if (StringUtils.isBlank(purchaseOrderNo)) {
+        if (StringUtils.isBlank(purchaseOrderNo) || purchaseOrderNo.indexOf("CHT") != 0) {
 
             purchaseOrderNo = SDK.getRuleAPI().executeAtScript("@sequenceYear(@companyId_purchase_order,4,0,130)", processExecutionContext.getUserContext());
 

+ 3 - 469
com.awspaas.user.apps.donenow_ivt/src/com/awspaas/user/apps/donenow_ivt/event/ivtOrderProcessAfterComplete.java

@@ -11,6 +11,7 @@ import com.actionsoft.bpms.util.TypeUtil;
 import com.actionsoft.sdk.local.SDK;
 import com.actionsoft.sdk.local.api.Logger;
 import com.awspaas.user.apps.donenow_ivt.constant.IVTConstant;
+import com.awspaas.user.apps.donenow_ivt.service.PaymentPlanService;
 import org.apache.commons.lang3.StringUtils;
 
 import java.math.BigDecimal;
@@ -21,6 +22,7 @@ import java.time.format.DateTimeFormatter;
 import java.time.temporal.ChronoUnit;
 import java.time.temporal.TemporalAdjusters;
 import java.util.*;
+import java.util.stream.Collectors;
 
 public class ivtOrderProcessAfterComplete extends ExecuteListener {
     public String getDescription() {
@@ -164,78 +166,10 @@ public class ivtOrderProcessAfterComplete extends ExecuteListener {
 
 /*****************************************2025年10月24日  张耀 生成付款计划********************************************/
         logger.info("生成付款计划");
-        int total = 0;
-        for (BO orderProduct : orderProducts) {
-            if (StringUtils.isNotBlank(orderProduct.getString("CONTRACT_COST_ID"))) {
-                String SERVICE_ID = DBSql.getString("select SERVICE_ID from BO_EU_DNCTT_CONTRACT_COST where ID=?", new Object[]{orderProduct.getString("CONTRACT_COST_ID")});
-                if (StringUtils.isNotBlank(SERVICE_ID)) {
-
-                    if (DBSql.getInt("select count(1) as cnt from  BO_EU_DNIVT_ORDER_PAYMENT_PLAN where ORDER_ID = ? and CONTRACT_COST_ID=? and CONTRACT_SERVICE_ID=?  AND PAY_AMOUNT is NOT null AND PAY_AMOUNT<>0", new Object[]{orderId, orderProduct.getString("CONTRACT_COST_ID"), SERVICE_ID}) > 0) {
-                        continue;
-                    }
-                    String sql = "delete from BO_EU_DNIVT_ORDER_PAYMENT_PLAN where ORDER_ID = ? and CONTRACT_COST_ID=? and CONTRACT_SERVICE_ID=? and (PAY_AMOUNT is null or PAY_AMOUNT = 0)";
-                    DBSql.update(sql, new Object[]{orderId, orderProduct.getString("CONTRACT_COST_ID"), SERVICE_ID});
-
-                    logger.info("生成付款计划SERVICE_ID--" + SERVICE_ID);
-
-                    BO service = SDK.getBOAPI().get("BO_EU_DNCTT_CONTRACT_SERVICE", SERVICE_ID);
-                    String BILL_METHOD_ID = null;//计费方式  4601:自然月  4602:实际月
-                    if (service.getString("OBJECT_TYPE").equals("2"))//服务包
-                    {
-                        BILL_METHOD_ID = DBSql.getString("select BILL_METHOD_ID from BO_EU_DNIVT_SERVICE_BUNDLE where ID=?", new Object[]{service.getString("OBJECT_ID")});
-                    } else {
-                        BILL_METHOD_ID = DBSql.getString("select BILL_METHOD_ID from BO_EU_DNIVT_SERVICE where ID=?", new Object[]{service.getString("OBJECT_ID")});
-                    }
-
-                    String RULE_CATE = service.getString("PURCHASE_PERIOD_TYPE");//采购周期
-                    LocalDate PERIOD_BEGIN_DATE = service.get("EFFECTIVE_DATE", LocalDate.class);
-
-                    LocalDate START_DATE = TypeUtil.convert(DBSql.getString("select START_DATE from BO_EU_DNCTT_CONTRACT where ID=?", new Object[]{service.getString("CONTRACT_ID")}).substring(0, 10), LocalDate.class);
-
-                    LocalDate PERIOD_END_DATE = TypeUtil.convert(DBSql.getString("select END_DATE from BO_EU_DNCTT_CONTRACT where ID=?", new Object[]{service.getString("CONTRACT_ID")}).substring(0, 10), LocalDate.class);
-
-                    //采购单开始日期
-                    if (service.get("PURCHASE_START_DATE") != null) {
-                        START_DATE = TypeUtil.convert(service.get("PURCHASE_START_DATE").toString().substring(0, 10), LocalDate.class);
-                    }
-
-                    List<PERIOD> periods = getPeriodList(RULE_CATE, PERIOD_BEGIN_DATE, START_DATE, PERIOD_END_DATE, StringUtils.isNotBlank(BILL_METHOD_ID) && BILL_METHOD_ID.equals("4601"));
-
-                    if (periods.isEmpty())
-                        continue;
-
-                    BigDecimal COST_TOTAL = orderProduct.get("COST_TOTAL", BigDecimal.class);//总金额
-
-                    BigDecimal RATE_TOTAL = periods.stream().map(period -> period.getRate()).reduce(BigDecimal.ZERO, BigDecimal::add);
-
-                    if (RATE_TOTAL.equals(BigDecimal.ZERO) || COST_TOTAL == null || COST_TOTAL.equals(BigDecimal.ZERO))
-                        continue;
-
-                    BigDecimal UNIT_COST = COST_TOTAL.divide(RATE_TOTAL, 10, RoundingMode.HALF_UP);
-                    for (PERIOD period : periods) {
-                        total++;
-                        ProcessInstance processInstance = SDK.getProcessAPI().createProcessInstance("obj_5cb4ae4a42944fd0a9a284ff4c64c65d", uc.getUID(), "付款计划");
-
-                        BO paymentPlan = new BO();
-                        paymentPlan.setBindId(processInstance.getId());
-                        paymentPlan.set("ORDER_ID", orderId);
-                        paymentPlan.set("PLAN_DATE", period.getPeriodBeginDateStr());
-                        paymentPlan.set("PLAN_AMOUNT", UNIT_COST.multiply(period.getRate()));
-                        paymentPlan.set("REMAIN_AMOUNT", paymentPlan.get("PLAN_AMOUNT"));
-                        paymentPlan.set("CONTRACT_COST_ID", orderProduct.getString("CONTRACT_COST_ID"));
-                        paymentPlan.set("CONTRACT_SERVICE_ID", service.getId());
-                        paymentPlan.set("PAY_DESC", orderProduct.getString("NAME"));
 
-                        paymentPlan.set("ACCOUNT_PAYEE", VENDOR_ACCOUNT_ID);//收款单位
+        PaymentPlanService.getInstance().createPaymentPlan(uc, orderId);
 
-                        SDK.getBOAPI().create("BO_EU_DNIVT_ORDER_PAYMENT_PLAN", paymentPlan, processInstance, uc);
 
-                        System.out.println("==== 创建付款计划:" + paymentPlan.get("PLAN_DATE") + ",金额:" + paymentPlan.get("PLAN_AMOUNT") + " ====");
-                    }
-                }
-            }
-        }
-        logger.info("付款计划生成完成,生成付款计划数量:" + total);
     }
 
     /**
@@ -464,405 +398,5 @@ public class ivtOrderProcessAfterComplete extends ExecuteListener {
 
     /*************************************2025年10月23日**************************************************/
 
-    /**
-     * 获取周期列表
-     * @param RULE_CATE
-     * @param CONTRACT_START_DATE
-     * @param PERIOD_BEGIN_DATE
-     * @param PERIOD_END_DATE
-     * @param isNaturalMonth //自然月和实际月
-     * @return
-     */
-    private List<PERIOD> getPeriodList(String RULE_CATE, LocalDate CONTRACT_START_DATE, LocalDate PERIOD_BEGIN_DATE, LocalDate PERIOD_END_DATE, boolean isNaturalMonth) {
-
-        logger.info("获取周期列表");
-        logger.info("RULE_CATE:" + RULE_CATE);
-        logger.info("CONTRACT_START_DATE:" + CONTRACT_START_DATE);
-        logger.info("PERIOD_BEGIN_DATE:" + PERIOD_BEGIN_DATE);
-        logger.info("PERIOD_END_DATE:" + PERIOD_END_DATE);
-        logger.info("isNaturalMonth:" + isNaturalMonth);
-
-        List<PERIOD> periodList = new ArrayList<>();
-        //一次性收费
-        if (RULE_CATE.equals(IVTConstant.PERIOD_TYPE_ONE_TIME)) {
-            PERIOD period = new PERIOD();
-            period.setPeriodBeginDate(PERIOD_BEGIN_DATE);
-            period.setPeriodEndDate(PERIOD_END_DATE);
-            period.setRate(BigDecimal.ONE);
-            periodList.add(period);
-        } else {
-            LocalDate START_DATE = null;
-            LocalDate currLastDay = null;//当前周期的结束日
-            int periodDays = 0;//当前周期天数
-            switch (RULE_CATE) {
-                case IVTConstant.PERIOD_TYPE_MONTH://按月支付
-                {
-                    if (isNaturalMonth) {
-                        //自然月
-                        if (PERIOD_BEGIN_DATE.getDayOfMonth() != 1) {
-                            currLastDay = PERIOD_BEGIN_DATE.with(TemporalAdjusters.lastDayOfMonth());
-                            periodDays = PERIOD_BEGIN_DATE.lengthOfMonth();
-                        }
-                    } else {
-                        //实际月
-                        if (CONTRACT_START_DATE.isAfter(PERIOD_BEGIN_DATE))//合同开始日期在 服务开始日期之后
-                        {
-                            currLastDay = CONTRACT_START_DATE.minusDays(1);//获取合同开始日期的前一日
-                            periodDays = GetPeriodDays(CONTRACT_START_DATE.minusMonths(1), currLastDay);
-
-                        } else if (CONTRACT_START_DATE.isBefore(PERIOD_BEGIN_DATE)) {//合同开始日期在 服务开始日期之前
-                            currLastDay = CONTRACT_START_DATE.plusMonths(1).minusDays(1);
-
-                            periodDays = GetPeriodDays(CONTRACT_START_DATE, currLastDay);
-
-                            if (currLastDay.isAfter(PERIOD_END_DATE))//如果当前周期结束日大于服务结束日
-                            {
-                                currLastDay = PERIOD_END_DATE;
-                            }
-
-                        } else {
-
-
-                        }
-                    }
-                }
-                break;
-                case IVTConstant.PERIOD_TYPE_QUARTER://按季支付
-                {
-                    if (isNaturalMonth) {
-                        //如果不是季度第一天
-                        if (PERIOD_BEGIN_DATE.getDayOfMonth() != 1 || (PERIOD_BEGIN_DATE.getMonthValue() - 1) % 3 != 0) {
-                            Month endMonth = getQuarterEndMonth(PERIOD_BEGIN_DATE.getMonth());
-                            currLastDay = LocalDate.of(PERIOD_BEGIN_DATE.getYear(), endMonth, endMonth.length(PERIOD_BEGIN_DATE.isLeapYear()) // 考虑闰年2月的天数
-                            );
-                            periodDays = getDaysInCurrentQuarter(PERIOD_BEGIN_DATE);
-                        }
-                    } else {
-                        //实际月
-                        if (CONTRACT_START_DATE.isAfter(PERIOD_BEGIN_DATE))//合同开始日期在 服务开始日期之后
-                        {
-                            currLastDay = CONTRACT_START_DATE.minusDays(1);//获取合同开始日期的前一日
-                            periodDays = GetPeriodDays(CONTRACT_START_DATE.minusMonths(3), currLastDay);
-
-                        } else if (CONTRACT_START_DATE.isBefore(PERIOD_BEGIN_DATE)) {//合同开始日期在 服务开始日期之前
-                            currLastDay = CONTRACT_START_DATE.plusMonths(3).minusDays(1);
-
-                            periodDays = GetPeriodDays(CONTRACT_START_DATE, currLastDay);
-
-                            if (currLastDay.isAfter(PERIOD_END_DATE))//如果当前周期结束日大于服务结束日
-                            {
-                                currLastDay = PERIOD_END_DATE;
-                            }
-
-                        } else {
-
-
-                        }
-                    }
-
-                }
-                break;
-                case IVTConstant.PERIOD_TYPE_HALFYEAR://按半年支付
-                    if (isNaturalMonth) {
-                        // 若不是半年第一天,计算本半年剩余天数作为首个周期
-                        if (PERIOD_BEGIN_DATE.getDayOfMonth() != 1 || (PERIOD_BEGIN_DATE.getMonthValue() - 1) % 6 != 0) {
-                            Month endMonth = getHalfYearEndMonth(PERIOD_BEGIN_DATE.getMonth());
-                            currLastDay = LocalDate.of(PERIOD_BEGIN_DATE.getYear(), endMonth, endMonth.length(PERIOD_BEGIN_DATE.isLeapYear()));
-                            periodDays = getDaysInCurrentHalfYear(PERIOD_BEGIN_DATE);
-                        }
-                    } else {
-                        //实际月
-                        if (CONTRACT_START_DATE.isAfter(PERIOD_BEGIN_DATE))//合同开始日期在 服务开始日期之后
-                        {
-                            currLastDay = CONTRACT_START_DATE.minusDays(1);//获取合同开始日期的前一日
-                            periodDays = GetPeriodDays(CONTRACT_START_DATE.minusMonths(6), currLastDay);
-
-                        } else if (CONTRACT_START_DATE.isBefore(PERIOD_BEGIN_DATE)) {//合同开始日期在 服务开始日期之前
-                            currLastDay = CONTRACT_START_DATE.plusMonths(6).minusDays(1);
-
-                            periodDays = GetPeriodDays(CONTRACT_START_DATE, currLastDay);
-
-                            if (currLastDay.isAfter(PERIOD_END_DATE))//如果当前周期结束日大于服务结束日
-                            {
-                                currLastDay = PERIOD_END_DATE;
-                            }
-
-                        } else {
-
-
-                        }
-                    }
-                    break;
-                case IVTConstant.PERIOD_TYPE_YEAR://按年支付
-                {
-                    if (isNaturalMonth) {
-                        //如果不是年第一天
-                        if (PERIOD_BEGIN_DATE.getDayOfMonth() != 1 || PERIOD_BEGIN_DATE.getMonthValue() != 1) {
-                            //所在年最后一天
-                            currLastDay = LocalDate.of(PERIOD_BEGIN_DATE.getYear(), 12, 31);
-                            periodDays = PERIOD_BEGIN_DATE.lengthOfYear();
-                        }
-
-                    } else {
-                        //实际月
-                        if (CONTRACT_START_DATE.isAfter(PERIOD_BEGIN_DATE))//合同开始日期在 服务开始日期之后
-                        {
-                            currLastDay = CONTRACT_START_DATE.minusDays(1);//获取合同开始日期的前一日
-                            periodDays = GetPeriodDays(CONTRACT_START_DATE.minusMonths(12), currLastDay);
-
-                        } else if (CONTRACT_START_DATE.isBefore(PERIOD_BEGIN_DATE)) {//合同开始日期在 服务开始日期之前
-                            currLastDay = CONTRACT_START_DATE.plusMonths(12).minusDays(1);
-
-                            periodDays = GetPeriodDays(CONTRACT_START_DATE, currLastDay);
-
-                            if (currLastDay.isAfter(PERIOD_END_DATE))//如果当前周期结束日大于服务结束日
-                            {
-                                currLastDay = PERIOD_END_DATE;
-                            }
-                        } else {
-
-
-                        }
-                    }
-                }
-                break;
-                default: {
-                    //报错,类型异常
-                    return null;
-                }
-            }
-            logger.info("currLastDay:" + currLastDay);
-            logger.info("periodDays:" + periodDays);
-
-            if (currLastDay != null) {
-                if (currLastDay.isBefore(PERIOD_END_DATE)) {
-                    PERIOD period = new PERIOD();
-                    period.setPeriodBeginDate(PERIOD_BEGIN_DATE);
-                    period.setPeriodEndDate(currLastDay);
-
-                    BigDecimal periodRate = divideToBigDecimal(GetPeriodDays(PERIOD_BEGIN_DATE, currLastDay), periodDays);
-                    period.setRate(periodRate);
-
-                    periodList.add(period);
-
-                    START_DATE = currLastDay.plusDays(1);//周期开始日期
-                } else {
-                    PERIOD period = new PERIOD();
-                    period.setPeriodBeginDate(PERIOD_BEGIN_DATE);
-                    period.setPeriodEndDate(PERIOD_END_DATE);
-
-                    BigDecimal periodRate = divideToBigDecimal(GetPeriodDays(PERIOD_BEGIN_DATE, PERIOD_END_DATE), periodDays);
-                    period.setRate(periodRate);
-
-                    periodList.add(period);
-                }
-            } else {
-                START_DATE = PERIOD_BEGIN_DATE;
-            }
-
-            logger.info("START_DATE:" + START_DATE);
-
-            //循环
-            if (START_DATE != null && START_DATE.isBefore(PERIOD_END_DATE)) {
-
-                while (!START_DATE.isAfter(PERIOD_END_DATE)) {
-                    LocalDate periodEnd = getNextPeriodStart(START_DATE, RULE_CATE).minusDays(1);//本周期结束时间
-
-                    BigDecimal periodRate = BigDecimal.ONE;
-
-                    if (periodEnd.isAfter(PERIOD_END_DATE)) {//如果结束日期大于合同结束日期,则计算结束日期和合同结束日期的差值,并计算该差值占整周期的比例
-                        periodRate = divideToBigDecimal(GetPeriodDays(START_DATE, PERIOD_END_DATE), GetPeriodDays(START_DATE, periodEnd));
-                        periodEnd = PERIOD_END_DATE;
-                    }
-
-                    PERIOD period = new PERIOD();
-                    period.setPeriodBeginDate(START_DATE);
-                    period.setPeriodEndDate(periodEnd);
-                    period.setRate(periodRate);
-                    periodList.add(period);
-
-                    if (periodEnd != null) {
-                        START_DATE = periodEnd.plusDays(1);
-                    }
-                }
-            }
-        }
-        return periodList;
-    }
-
-    /**
-     * 获取下一周期开始时间
-     * @param start 当前周期开始时间
-     * @param periodType 周期类型
-     * @return 下一周期开始时间
-     */
-    public static LocalDate getNextPeriodStart(LocalDate start, String periodType) {
-        // 根据不同的周期类型计算下一周期的开始时间
-        switch (periodType) {
-            case IVTConstant.PERIOD_TYPE_MONTH:
-                // 如果是月周期,则在当前时间基础上增加1个月
-                return start.plus(1, ChronoUnit.MONTHS);
-            case IVTConstant.PERIOD_TYPE_QUARTER:
-                // 如果是季度周期,则在当前时间基础上增加3个月
-                return start.plus(3, ChronoUnit.MONTHS);
-            case IVTConstant.PERIOD_TYPE_HALFYEAR:
-                // 如果是半年周期,则在当前时间基础上增加6个月
-                return start.plus(6, ChronoUnit.MONTHS);
-            case IVTConstant.PERIOD_TYPE_YEAR:
-                // 如果是年周期,则在当前时间基础上增加1年
-                return start.plus(1, ChronoUnit.YEARS);
-            default:
-                // 如果周期类型不匹配任何已知类型,则返回原始开始时间
-                return start;
-        }
-    }
-
-    /**
-     * 获取当前季度的结束月份
-     */
-    private static Month getQuarterEndMonth(Month month) {
-        int monthValue = month.getValue();
-        if (monthValue <= 3) {
-            return Month.MARCH;   // 第一季度结束月
-        } else if (monthValue <= 6) {
-            return Month.JUNE;    // 第二季度结束月
-        } else if (monthValue <= 9) {
-            return Month.SEPTEMBER; // 第三季度结束月
-        } else {
-            return Month.DECEMBER;  // 第四季度结束月
-        }
-    }
-
-    /**
-     * 计算当前季度的总天数
-     */
-    private static int getDaysInCurrentQuarter(LocalDate date) {
-        // 获取当前月份
-        Month currentMonth = date.getMonth();
-        // 确定当前季度的起始月份和结束月份
-        Month startMonth = getQuarterStartMonth(currentMonth);
-        Month endMonth = getQuarterEndMonth(currentMonth);
-
-        // 构建季度的第一天(当月第一天)
-        LocalDate quarterStart = LocalDate.of(date.getYear(), startMonth, 1);
-
-        // 构建季度的最后一天(当月最后一天)
-        LocalDate quarterEnd = LocalDate.of(date.getYear(), endMonth, endMonth.length(date.isLeapYear()) // 考虑闰年2月的天数
-        );
-
-        // 计算两个日期之间的天数(包含首尾两天)
-        return (int) ChronoUnit.DAYS.between(quarterStart, quarterEnd) + 1;
-    }
-
-    /**
-     * 获取当前季度的起始月份
-     */
-    private static Month getQuarterStartMonth(Month month) {
-        int monthValue = month.getValue();
-        if (monthValue <= 3) {
-            return Month.JANUARY; // 第一季度:1-3月
-        } else if (monthValue <= 6) {
-            return Month.APRIL;   // 第二季度:4-6月
-        } else if (monthValue <= 9) {
-            return Month.JULY;    // 第三季度:7-9月
-        } else {
-            return Month.OCTOBER; // 第四季度:10-12月
-        }
-    }
-
-    /**
-     * 获取当前半年的结束月份
-     */
-    private static Month getHalfYearEndMonth(Month month) {
-        int monthValue = month.getValue();
-        return monthValue <= 6 ? Month.JUNE : Month.DECEMBER;
-    }
-
-    /**
-     * 获取当前半年的起始月份
-     */
-    private static Month getHalfYearStartMonth(Month month) {
-        int monthValue = month.getValue();
-        return monthValue <= 6 ? Month.JANUARY : Month.JULY;
-    }
-
-    /**
-     * 计算当前半年的总天数
-     */
-    private static int getDaysInCurrentHalfYear(LocalDate date) {
-        Month currentMonth = date.getMonth();
-        Month startMonth = getHalfYearStartMonth(currentMonth);
-        Month endMonth = getHalfYearEndMonth(currentMonth);
-
-        LocalDate halfYearStart = LocalDate.of(date.getYear(), startMonth, 1);
-        LocalDate halfYearEnd = LocalDate.of(date.getYear(), endMonth, endMonth.length(date.isLeapYear()));
-
-        return GetPeriodDays(halfYearStart, halfYearEnd);
-    }
-
-    private static int GetPeriodDays(LocalDate start, LocalDate end) {
-        return (int) ChronoUnit.DAYS.between(start, end) + 1;
-    }
-
-    // 定义一个方法,将两个 int 相除并返回 BigDecimal
-    public static BigDecimal divideToBigDecimal(int numerator, int denominator) {
-        if (denominator == 0) {
-            throw new ArithmeticException("分母不能为零");
-        }
-
-        // 使用 BigDecimal 进行精确计算
-        BigDecimal num = new BigDecimal(numerator);
-        BigDecimal den = new BigDecimal(denominator);
-
-        // 设置小数点后的位数和舍入模式
-        return num.divide(den, 10, RoundingMode.HALF_UP); // 保留 10 位小数
-    }
-
-    /**
-     * 周期
-     */
-    private class PERIOD {
-        private LocalDate PERIOD_BEGIN_DATE;
-        private LocalDate PERIOD_END_DATE;
-        private BigDecimal RATE;
-
-        public void setPeriodBeginDate(LocalDate periodBeginDate) {
-            this.PERIOD_BEGIN_DATE = periodBeginDate;
-        }
-
-        public void setPeriodEndDate(LocalDate periodEndDate) {
-            this.PERIOD_END_DATE = periodEndDate;
-        }
-
-        public void setRate(BigDecimal rate) {
-            this.RATE = rate;
-        }
-
-        public LocalDate getPeriodBeginDate() {
-            return PERIOD_BEGIN_DATE;
-        }
-
-        public LocalDate getPeriodEndDate() {
-            return PERIOD_END_DATE;
-        }
-
-        public String getPeriodBeginDateStr() {
-            return PERIOD_BEGIN_DATE.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
-        }
-
-        public String getPeriodMonthStr() {
-            return PERIOD_BEGIN_DATE.format(DateTimeFormatter.ofPattern("yyyyMM"));
-        }
-
-        public String getPeriodEndDateStr() {
-            return PERIOD_END_DATE.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
-        }
-
-        public BigDecimal getRate() {
-            return RATE;
-        }
-
-    }
-
 
 }

+ 25 - 0
com.awspaas.user.apps.donenow_ivt/src/com/awspaas/user/apps/donenow_ivt/job/paymentReminderJob.java

@@ -0,0 +1,25 @@
+package com.awspaas.user.apps.donenow_ivt.job;
+
+import org.quartz.Job;
+import org.quartz.JobExecutionContext;
+import org.quartz.JobExecutionException;
+
+/**
+ * 付款提醒任务
+ */
+public class paymentReminderJob implements Job {
+    @Override
+    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
+
+        /**
+         *     1)预付:提前1个月,一般月初付掉: 提前30天、23天、15天,10天 提醒四次
+         *     2)后付费:账期结束后,1天、7天、15天、20天
+         *     3)当月付:参照预付
+         */
+
+
+
+
+
+    }
+}

+ 574 - 0
com.awspaas.user.apps.donenow_ivt/src/com/awspaas/user/apps/donenow_ivt/service/PaymentPlanService.java

@@ -0,0 +1,574 @@
+package com.awspaas.user.apps.donenow_ivt.service;
+
+import com.actionsoft.bpms.bo.engine.BO;
+import com.actionsoft.bpms.bpmn.engine.model.run.delegate.ProcessInstance;
+import com.actionsoft.bpms.server.UserContext;
+import com.actionsoft.bpms.util.DBSql;
+import com.actionsoft.bpms.util.TypeUtil;
+import com.actionsoft.sdk.local.SDK;
+import com.actionsoft.sdk.local.api.Logger;
+import com.awspaas.user.apps.donenow_ivt.constant.IVTConstant;
+import org.apache.commons.lang3.StringUtils;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.time.LocalDate;
+import java.time.Month;
+import java.time.format.DateTimeFormatter;
+import java.time.temporal.ChronoUnit;
+import java.time.temporal.TemporalAdjusters;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * 付款计划服务
+ */
+public class PaymentPlanService {
+    // 常量定义
+    private static final Logger logger = SDK.getLogAPI().getLogger(PaymentPlanService.class);
+
+    // 单例模式
+    private static volatile PaymentPlanService instance;
+
+    private PaymentPlanService() {
+    }
+
+    public static PaymentPlanService getInstance() {
+        if (instance == null) {
+            synchronized (PaymentPlanService.class) {
+                if (instance == null) {
+                    instance = new PaymentPlanService();
+                }
+            }
+        }
+        return instance;
+    }
+
+
+    /**
+     * 创建付款计划
+     * @param uc
+     * @param orderId
+     */
+    public void createPaymentPlan(UserContext uc, String orderId) {
+        BO purchaseOrder = SDK.getBOAPI().get("BO_EU_DNIVT_ORDER", orderId);
+        List<BO> orderProducts = SDK.getBOAPI().query("BO_EU_DNIVT_ORDER_PRODUCT").bindId(purchaseOrder.getBindId()).list();
+        String VENDOR_ACCOUNT_ID = purchaseOrder.getString("VENDOR_ACCOUNT_ID");//供应商账户ID
+
+        int total = 0;
+        boolean isOnlyOne = true;
+        for (BO orderProduct : orderProducts) {
+            if (StringUtils.isNotBlank(orderProduct.getString("CONTRACT_COST_ID"))) {
+                String SERVICE_ID = DBSql.getString("select SERVICE_ID from BO_EU_DNCTT_CONTRACT_COST where ID=?", new Object[]{orderProduct.getString("CONTRACT_COST_ID")});
+                //关联服务
+                if (StringUtils.isNotBlank(SERVICE_ID)) {
+                    isOnlyOne = false;
+                    if (DBSql.getInt("select count(1) as cnt from  BO_EU_DNIVT_ORDER_PAYMENT_PLAN where ORDER_ID = ? and CONTRACT_COST_ID=? and CONTRACT_SERVICE_ID=?  AND PAY_AMOUNT is NOT null AND PAY_AMOUNT<>0", new Object[]{orderId, orderProduct.getString("CONTRACT_COST_ID"), SERVICE_ID}) > 0) {
+                        continue;
+                    }
+                    String sql = "delete from BO_EU_DNIVT_ORDER_PAYMENT_PLAN where ORDER_ID = ? and CONTRACT_COST_ID=? and CONTRACT_SERVICE_ID=? and (PAY_AMOUNT is null or PAY_AMOUNT = 0)";
+                    DBSql.update(sql, new Object[]{orderId, orderProduct.getString("CONTRACT_COST_ID"), SERVICE_ID});
+
+                    logger.info("生成付款计划SERVICE_ID--" + SERVICE_ID);
+
+                    BO service = SDK.getBOAPI().get("BO_EU_DNCTT_CONTRACT_SERVICE", SERVICE_ID);
+                    String BILL_METHOD_ID = null;//计费方式  4601:自然月  4602:实际月
+                    if (service.getString("OBJECT_TYPE").equals("2"))//服务包
+                    {
+                        BILL_METHOD_ID = DBSql.getString("select BILL_METHOD_ID from BO_EU_DNIVT_SERVICE_BUNDLE where ID=?", new Object[]{service.getString("OBJECT_ID")});
+                    } else {
+                        BILL_METHOD_ID = DBSql.getString("select BILL_METHOD_ID from BO_EU_DNIVT_SERVICE where ID=?", new Object[]{service.getString("OBJECT_ID")});
+                    }
+
+                    String RULE_CATE = service.getString("PURCHASE_PERIOD_TYPE");//采购周期
+                    LocalDate PERIOD_BEGIN_DATE = service.get("EFFECTIVE_DATE", LocalDate.class);
+
+                    LocalDate START_DATE = TypeUtil.convert(DBSql.getString("select START_DATE from BO_EU_DNCTT_CONTRACT where ID=?", new Object[]{service.getString("CONTRACT_ID")}).substring(0, 10), LocalDate.class);
+
+                    LocalDate PERIOD_END_DATE = TypeUtil.convert(DBSql.getString("select END_DATE from BO_EU_DNCTT_CONTRACT where ID=?", new Object[]{service.getString("CONTRACT_ID")}).substring(0, 10), LocalDate.class);
+
+                    //采购单开始日期
+                    if (service.get("PURCHASE_START_DATE") != null) {
+                        START_DATE = TypeUtil.convert(service.get("PURCHASE_START_DATE").toString().substring(0, 10), LocalDate.class);
+                    }
+
+                    List<PERIOD> periods = getPeriodList(RULE_CATE, PERIOD_BEGIN_DATE, START_DATE, PERIOD_END_DATE, StringUtils.isNotBlank(BILL_METHOD_ID) && BILL_METHOD_ID.equals("4601"));
+
+                    if (periods.isEmpty())
+                        continue;
+
+                    BigDecimal COST_TOTAL = orderProduct.get("COST_TOTAL", BigDecimal.class);//总金额
+
+                    BigDecimal RATE_TOTAL = periods.stream().map(period -> period.getRate()).reduce(BigDecimal.ZERO, BigDecimal::add);
+
+                    if (RATE_TOTAL.equals(BigDecimal.ZERO) || COST_TOTAL == null || COST_TOTAL.equals(BigDecimal.ZERO))
+                        continue;
+
+                    BigDecimal UNIT_COST = COST_TOTAL.divide(RATE_TOTAL, 10, RoundingMode.HALF_UP);
+                    for (PERIOD period : periods) {
+                        total++;
+                        ProcessInstance processInstance = SDK.getProcessAPI().createProcessInstance("obj_5cb4ae4a42944fd0a9a284ff4c64c65d", uc.getUID(), "付款计划");
+
+                        BO paymentPlan = new BO();
+                        paymentPlan.setBindId(processInstance.getId());
+                        paymentPlan.set("ORDER_ID", orderId);
+                        paymentPlan.set("PLAN_DATE", period.getPeriodBeginDateStr());
+                        paymentPlan.set("PLAN_AMOUNT", UNIT_COST.multiply(period.getRate()));
+                        paymentPlan.set("REMAIN_AMOUNT", paymentPlan.get("PLAN_AMOUNT"));
+                        paymentPlan.set("CONTRACT_COST_ID", orderProduct.getString("CONTRACT_COST_ID"));
+                        paymentPlan.set("CONTRACT_SERVICE_ID", service.getId());
+                        paymentPlan.set("PAY_DESC", orderProduct.getString("NAME"));
+
+                        paymentPlan.set("ACCOUNT_PAYEE", VENDOR_ACCOUNT_ID);//收款单位
+
+                        SDK.getBOAPI().create("BO_EU_DNIVT_ORDER_PAYMENT_PLAN", paymentPlan, processInstance, uc);
+
+                        System.out.println("==== 创建付款计划:" + paymentPlan.get("PLAN_DATE") + ",金额:" + paymentPlan.get("PLAN_AMOUNT") + " ====");
+                    }
+                }
+            }
+        }
+
+        if (isOnlyOne) {
+            total += 1;
+            String sql = "delete from BO_EU_DNIVT_ORDER_PAYMENT_PLAN where ORDER_ID = ? and (PAY_AMOUNT is null or PAY_AMOUNT = 0)";
+            DBSql.update(sql, new Object[]{orderId});
+
+            //全部采购项 合并生成一条采购计划
+            ProcessInstance processInstance = SDK.getProcessAPI().createProcessInstance("obj_5cb4ae4a42944fd0a9a284ff4c64c65d", uc.getUID(), "付款计划");
+
+            String PLAN_DATE = null;
+            if (purchaseOrder.get("EXPECTED_SHIP_DATE") != null)
+                PLAN_DATE = purchaseOrder.get("EXPECTED_SHIP_DATE").toString().substring(0, 10);
+            else
+                PLAN_DATE = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
+
+            BigDecimal PLAN_AMOUNT = orderProducts.stream().map(orderProduct -> orderProduct.get("COST_TOTAL", BigDecimal.class)).reduce(BigDecimal.ZERO, BigDecimal::add);
+
+            String PAY_DESC = orderProducts.stream().map(orderProduct -> orderProduct.getString("NAME")).collect(Collectors.joining(","));
+
+            if (StringUtils.isNotBlank(PAY_DESC) && PAY_DESC.length() > 300)
+                PAY_DESC = PAY_DESC.substring(0, 300);
+
+            BO paymentPlan = new BO();
+            paymentPlan.setBindId(processInstance.getId());
+            paymentPlan.set("ORDER_ID", orderId);
+            paymentPlan.set("PLAN_DATE", PLAN_DATE);
+            paymentPlan.set("PLAN_AMOUNT", PLAN_AMOUNT);
+            paymentPlan.set("REMAIN_AMOUNT", PLAN_AMOUNT);
+            paymentPlan.set("PAY_DESC", PAY_DESC);
+            paymentPlan.set("ACCOUNT_PAYEE", VENDOR_ACCOUNT_ID);//收款单位
+            SDK.getBOAPI().create("BO_EU_DNIVT_ORDER_PAYMENT_PLAN", paymentPlan, processInstance, uc);
+            System.out.println("==== 创建付款计划:" + paymentPlan.get("PLAN_DATE") + ",金额:" + paymentPlan.get("PLAN_AMOUNT") + " ====");
+
+        }
+        logger.info("付款计划生成完成,生成付款计划数量:" + total);
+    }
+
+    /**
+     * 获取周期列表
+     * @param RULE_CATE
+     * @param CONTRACT_START_DATE
+     * @param PERIOD_BEGIN_DATE
+     * @param PERIOD_END_DATE
+     * @param isNaturalMonth //自然月和实际月
+     * @return
+     */
+    private List<PERIOD> getPeriodList(String RULE_CATE, LocalDate CONTRACT_START_DATE, LocalDate PERIOD_BEGIN_DATE, LocalDate PERIOD_END_DATE, boolean isNaturalMonth) {
+
+        logger.info("获取周期列表");
+        logger.info("RULE_CATE:" + RULE_CATE);
+        logger.info("CONTRACT_START_DATE:" + CONTRACT_START_DATE);
+        logger.info("PERIOD_BEGIN_DATE:" + PERIOD_BEGIN_DATE);
+        logger.info("PERIOD_END_DATE:" + PERIOD_END_DATE);
+        logger.info("isNaturalMonth:" + isNaturalMonth);
+
+        if (RULE_CATE.equals(IVTConstant.PERIOD_TYPE_MONTH)) {
+            isNaturalMonth = true;
+        } else {
+            isNaturalMonth = false;
+        }
+
+        List<PERIOD> periodList = new ArrayList<>();
+        //一次性收费
+        if (RULE_CATE.equals(IVTConstant.PERIOD_TYPE_ONE_TIME)) {
+            PERIOD period = new PERIOD();
+            period.setPeriodBeginDate(PERIOD_BEGIN_DATE);
+            period.setPeriodEndDate(PERIOD_END_DATE);
+            period.setRate(BigDecimal.ONE);
+            periodList.add(period);
+        } else {
+            LocalDate START_DATE = null;
+            LocalDate currLastDay = null;//当前周期的结束日
+            int periodDays = 0;//当前周期天数
+            switch (RULE_CATE) {
+                case IVTConstant.PERIOD_TYPE_MONTH://按月支付
+                {
+                    if (isNaturalMonth) {
+                        //自然月
+                        if (PERIOD_BEGIN_DATE.getDayOfMonth() != 1) {
+                            currLastDay = PERIOD_BEGIN_DATE.with(TemporalAdjusters.lastDayOfMonth());
+                            periodDays = PERIOD_BEGIN_DATE.lengthOfMonth();
+                        }
+                    } else {
+                        //实际月
+                        if (CONTRACT_START_DATE.isAfter(PERIOD_BEGIN_DATE))//合同开始日期在 服务开始日期之后
+                        {
+                            currLastDay = CONTRACT_START_DATE.minusDays(1);//获取合同开始日期的前一日
+                            periodDays = GetPeriodDays(CONTRACT_START_DATE.minusMonths(1), currLastDay);
+
+                        } else if (CONTRACT_START_DATE.isBefore(PERIOD_BEGIN_DATE)) {//合同开始日期在 服务开始日期之前
+                            currLastDay = CONTRACT_START_DATE.plusMonths(1).minusDays(1);
+
+                            periodDays = GetPeriodDays(CONTRACT_START_DATE, currLastDay);
+
+                            if (currLastDay.isAfter(PERIOD_END_DATE))//如果当前周期结束日大于服务结束日
+                            {
+                                currLastDay = PERIOD_END_DATE;
+                            }
+
+                        } else {
+
+
+                        }
+                    }
+                }
+                break;
+                case IVTConstant.PERIOD_TYPE_QUARTER://按季支付
+                {
+                    if (isNaturalMonth) {
+                        //如果不是季度第一天
+                        if (PERIOD_BEGIN_DATE.getDayOfMonth() != 1 || (PERIOD_BEGIN_DATE.getMonthValue() - 1) % 3 != 0) {
+                            Month endMonth = getQuarterEndMonth(PERIOD_BEGIN_DATE.getMonth());
+                            currLastDay = LocalDate.of(PERIOD_BEGIN_DATE.getYear(), endMonth, endMonth.length(PERIOD_BEGIN_DATE.isLeapYear()) // 考虑闰年2月的天数
+                            );
+                            periodDays = getDaysInCurrentQuarter(PERIOD_BEGIN_DATE);
+                        }
+                    } else {
+                        //实际月
+                        if (CONTRACT_START_DATE.isAfter(PERIOD_BEGIN_DATE))//合同开始日期在 服务开始日期之后
+                        {
+                            currLastDay = CONTRACT_START_DATE.minusDays(1);//获取合同开始日期的前一日
+                            periodDays = GetPeriodDays(CONTRACT_START_DATE.minusMonths(3), currLastDay);
+
+                        } else if (CONTRACT_START_DATE.isBefore(PERIOD_BEGIN_DATE)) {//合同开始日期在 服务开始日期之前
+                            currLastDay = CONTRACT_START_DATE.plusMonths(3).minusDays(1);
+
+                            periodDays = GetPeriodDays(CONTRACT_START_DATE, currLastDay);
+
+                            if (currLastDay.isAfter(PERIOD_END_DATE))//如果当前周期结束日大于服务结束日
+                            {
+                                currLastDay = PERIOD_END_DATE;
+                            }
+
+                        } else {
+
+
+                        }
+                    }
+
+                }
+                break;
+                case IVTConstant.PERIOD_TYPE_HALFYEAR://按半年支付
+                    if (isNaturalMonth) {
+                        // 若不是半年第一天,计算本半年剩余天数作为首个周期
+                        if (PERIOD_BEGIN_DATE.getDayOfMonth() != 1 || (PERIOD_BEGIN_DATE.getMonthValue() - 1) % 6 != 0) {
+                            Month endMonth = getHalfYearEndMonth(PERIOD_BEGIN_DATE.getMonth());
+                            currLastDay = LocalDate.of(PERIOD_BEGIN_DATE.getYear(), endMonth, endMonth.length(PERIOD_BEGIN_DATE.isLeapYear()));
+                            periodDays = getDaysInCurrentHalfYear(PERIOD_BEGIN_DATE);
+                        }
+                    } else {
+                        //实际月
+                        if (CONTRACT_START_DATE.isAfter(PERIOD_BEGIN_DATE))//合同开始日期在 服务开始日期之后
+                        {
+                            currLastDay = CONTRACT_START_DATE.minusDays(1);//获取合同开始日期的前一日
+                            periodDays = GetPeriodDays(CONTRACT_START_DATE.minusMonths(6), currLastDay);
+
+                        } else if (CONTRACT_START_DATE.isBefore(PERIOD_BEGIN_DATE)) {//合同开始日期在 服务开始日期之前
+                            currLastDay = CONTRACT_START_DATE.plusMonths(6).minusDays(1);
+
+                            periodDays = GetPeriodDays(CONTRACT_START_DATE, currLastDay);
+
+                            if (currLastDay.isAfter(PERIOD_END_DATE))//如果当前周期结束日大于服务结束日
+                            {
+                                currLastDay = PERIOD_END_DATE;
+                            }
+
+                        } else {
+
+
+                        }
+                    }
+                    break;
+                case IVTConstant.PERIOD_TYPE_YEAR://按年支付
+                {
+                    if (isNaturalMonth) {
+                        //如果不是年第一天
+                        if (PERIOD_BEGIN_DATE.getDayOfMonth() != 1 || PERIOD_BEGIN_DATE.getMonthValue() != 1) {
+                            //所在年最后一天
+                            currLastDay = LocalDate.of(PERIOD_BEGIN_DATE.getYear(), 12, 31);
+                            periodDays = PERIOD_BEGIN_DATE.lengthOfYear();
+                        }
+
+                    } else {
+                        //实际月
+                        if (CONTRACT_START_DATE.isAfter(PERIOD_BEGIN_DATE))//合同开始日期在 服务开始日期之后
+                        {
+                            currLastDay = CONTRACT_START_DATE.minusDays(1);//获取合同开始日期的前一日
+                            periodDays = GetPeriodDays(CONTRACT_START_DATE.minusMonths(12), currLastDay);
+
+                        } else if (CONTRACT_START_DATE.isBefore(PERIOD_BEGIN_DATE)) {//合同开始日期在 服务开始日期之前
+                            currLastDay = CONTRACT_START_DATE.plusMonths(12).minusDays(1);
+
+                            periodDays = GetPeriodDays(CONTRACT_START_DATE, currLastDay);
+
+                            if (currLastDay.isAfter(PERIOD_END_DATE))//如果当前周期结束日大于服务结束日
+                            {
+                                currLastDay = PERIOD_END_DATE;
+                            }
+                        } else {
+
+
+                        }
+                    }
+                }
+                break;
+                default: {
+                    //报错,类型异常
+                    return null;
+                }
+            }
+            logger.info("currLastDay:" + currLastDay);
+            logger.info("periodDays:" + periodDays);
+
+            if (currLastDay != null) {
+                if (currLastDay.isBefore(PERIOD_END_DATE)) {
+                    PERIOD period = new PERIOD();
+                    period.setPeriodBeginDate(PERIOD_BEGIN_DATE);
+                    period.setPeriodEndDate(currLastDay);
+
+                    BigDecimal periodRate = divideToBigDecimal(GetPeriodDays(PERIOD_BEGIN_DATE, currLastDay), periodDays);
+                    period.setRate(periodRate);
+
+                    periodList.add(period);
+
+                    START_DATE = currLastDay.plusDays(1);//周期开始日期
+                } else {
+                    PERIOD period = new PERIOD();
+                    period.setPeriodBeginDate(PERIOD_BEGIN_DATE);
+                    period.setPeriodEndDate(PERIOD_END_DATE);
+
+                    BigDecimal periodRate = divideToBigDecimal(GetPeriodDays(PERIOD_BEGIN_DATE, PERIOD_END_DATE), periodDays);
+                    period.setRate(periodRate);
+
+                    periodList.add(period);
+                }
+            } else {
+                START_DATE = PERIOD_BEGIN_DATE;
+            }
+
+            logger.info("START_DATE:" + START_DATE);
+
+            //循环
+            if (START_DATE != null && START_DATE.isBefore(PERIOD_END_DATE)) {
+
+                while (!START_DATE.isAfter(PERIOD_END_DATE)) {
+                    LocalDate periodEnd = getNextPeriodStart(START_DATE, RULE_CATE).minusDays(1);//本周期结束时间
+
+                    BigDecimal periodRate = BigDecimal.ONE;
+
+                    if (periodEnd.isAfter(PERIOD_END_DATE)) {//如果结束日期大于合同结束日期,则计算结束日期和合同结束日期的差值,并计算该差值占整周期的比例
+                        periodRate = divideToBigDecimal(GetPeriodDays(START_DATE, PERIOD_END_DATE), GetPeriodDays(START_DATE, periodEnd));
+                        periodEnd = PERIOD_END_DATE;
+                    }
+
+                    PERIOD period = new PERIOD();
+                    period.setPeriodBeginDate(START_DATE);
+                    period.setPeriodEndDate(periodEnd);
+                    period.setRate(periodRate);
+                    periodList.add(period);
+
+                    if (periodEnd != null) {
+                        START_DATE = periodEnd.plusDays(1);
+                    }
+                }
+            }
+        }
+        return periodList;
+    }
+
+    /**
+     * 获取下一周期开始时间
+     * @param start 当前周期开始时间
+     * @param periodType 周期类型
+     * @return 下一周期开始时间
+     */
+    public static LocalDate getNextPeriodStart(LocalDate start, String periodType) {
+        // 根据不同的周期类型计算下一周期的开始时间
+        switch (periodType) {
+            case IVTConstant.PERIOD_TYPE_MONTH:
+                // 如果是月周期,则在当前时间基础上增加1个月
+                return start.plus(1, ChronoUnit.MONTHS);
+            case IVTConstant.PERIOD_TYPE_QUARTER:
+                // 如果是季度周期,则在当前时间基础上增加3个月
+                return start.plus(3, ChronoUnit.MONTHS);
+            case IVTConstant.PERIOD_TYPE_HALFYEAR:
+                // 如果是半年周期,则在当前时间基础上增加6个月
+                return start.plus(6, ChronoUnit.MONTHS);
+            case IVTConstant.PERIOD_TYPE_YEAR:
+                // 如果是年周期,则在当前时间基础上增加1年
+                return start.plus(1, ChronoUnit.YEARS);
+            default:
+                // 如果周期类型不匹配任何已知类型,则返回原始开始时间
+                return start;
+        }
+    }
+
+    /**
+     * 获取当前季度的结束月份
+     */
+    private static Month getQuarterEndMonth(Month month) {
+        int monthValue = month.getValue();
+        if (monthValue <= 3) {
+            return Month.MARCH;   // 第一季度结束月
+        } else if (monthValue <= 6) {
+            return Month.JUNE;    // 第二季度结束月
+        } else if (monthValue <= 9) {
+            return Month.SEPTEMBER; // 第三季度结束月
+        } else {
+            return Month.DECEMBER;  // 第四季度结束月
+        }
+    }
+
+    /**
+     * 计算当前季度的总天数
+     */
+    private static int getDaysInCurrentQuarter(LocalDate date) {
+        // 获取当前月份
+        Month currentMonth = date.getMonth();
+        // 确定当前季度的起始月份和结束月份
+        Month startMonth = getQuarterStartMonth(currentMonth);
+        Month endMonth = getQuarterEndMonth(currentMonth);
+
+        // 构建季度的第一天(当月第一天)
+        LocalDate quarterStart = LocalDate.of(date.getYear(), startMonth, 1);
+
+        // 构建季度的最后一天(当月最后一天)
+        LocalDate quarterEnd = LocalDate.of(date.getYear(), endMonth, endMonth.length(date.isLeapYear()) // 考虑闰年2月的天数
+        );
+
+        // 计算两个日期之间的天数(包含首尾两天)
+        return (int) ChronoUnit.DAYS.between(quarterStart, quarterEnd) + 1;
+    }
+
+    /**
+     * 获取当前季度的起始月份
+     */
+    private static Month getQuarterStartMonth(Month month) {
+        int monthValue = month.getValue();
+        if (monthValue <= 3) {
+            return Month.JANUARY; // 第一季度:1-3月
+        } else if (monthValue <= 6) {
+            return Month.APRIL;   // 第二季度:4-6月
+        } else if (monthValue <= 9) {
+            return Month.JULY;    // 第三季度:7-9月
+        } else {
+            return Month.OCTOBER; // 第四季度:10-12月
+        }
+    }
+
+    /**
+     * 获取当前半年的结束月份
+     */
+    private static Month getHalfYearEndMonth(Month month) {
+        int monthValue = month.getValue();
+        return monthValue <= 6 ? Month.JUNE : Month.DECEMBER;
+    }
+
+    /**
+     * 获取当前半年的起始月份
+     */
+    private static Month getHalfYearStartMonth(Month month) {
+        int monthValue = month.getValue();
+        return monthValue <= 6 ? Month.JANUARY : Month.JULY;
+    }
+
+    /**
+     * 计算当前半年的总天数
+     */
+    private static int getDaysInCurrentHalfYear(LocalDate date) {
+        Month currentMonth = date.getMonth();
+        Month startMonth = getHalfYearStartMonth(currentMonth);
+        Month endMonth = getHalfYearEndMonth(currentMonth);
+
+        LocalDate halfYearStart = LocalDate.of(date.getYear(), startMonth, 1);
+        LocalDate halfYearEnd = LocalDate.of(date.getYear(), endMonth, endMonth.length(date.isLeapYear()));
+
+        return GetPeriodDays(halfYearStart, halfYearEnd);
+    }
+
+    private static int GetPeriodDays(LocalDate start, LocalDate end) {
+        return (int) ChronoUnit.DAYS.between(start, end) + 1;
+    }
+
+    // 定义一个方法,将两个 int 相除并返回 BigDecimal
+    public static BigDecimal divideToBigDecimal(int numerator, int denominator) {
+        if (denominator == 0) {
+            throw new ArithmeticException("分母不能为零");
+        }
+
+        // 使用 BigDecimal 进行精确计算
+        BigDecimal num = new BigDecimal(numerator);
+        BigDecimal den = new BigDecimal(denominator);
+
+        // 设置小数点后的位数和舍入模式
+        return num.divide(den, 10, RoundingMode.HALF_UP); // 保留 10 位小数
+    }
+
+    /**
+     * 周期
+     */
+    private class PERIOD {
+        private LocalDate PERIOD_BEGIN_DATE;
+        private LocalDate PERIOD_END_DATE;
+        private BigDecimal RATE;
+
+        public void setPeriodBeginDate(LocalDate periodBeginDate) {
+            this.PERIOD_BEGIN_DATE = periodBeginDate;
+        }
+
+        public void setPeriodEndDate(LocalDate periodEndDate) {
+            this.PERIOD_END_DATE = periodEndDate;
+        }
+
+        public void setRate(BigDecimal rate) {
+            this.RATE = rate;
+        }
+
+        public LocalDate getPeriodBeginDate() {
+            return PERIOD_BEGIN_DATE;
+        }
+
+        public LocalDate getPeriodEndDate() {
+            return PERIOD_END_DATE;
+        }
+
+        public String getPeriodBeginDateStr() {
+            return PERIOD_BEGIN_DATE.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
+        }
+
+        public String getPeriodMonthStr() {
+            return PERIOD_BEGIN_DATE.format(DateTimeFormatter.ofPattern("yyyyMM"));
+        }
+
+        public String getPeriodEndDateStr() {
+            return PERIOD_END_DATE.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
+        }
+
+        public BigDecimal getRate() {
+            return RATE;
+        }
+
+    }
+}