|
|
@@ -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;
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+}
|