Ver código fonte

Merge branch 'master' of http://210.51.45.41:3000/itcat_admin/aws_donenow

HULEI 1 mês atrás
pai
commit
35c24fb2d2

+ 1 - 1
com.awspaas.user.apps.donenow_ctt/src/com/awspaas/user/apps/donenow_ctt/PeriodCalculationUtil.java

@@ -829,7 +829,7 @@ public class PeriodCalculationUtil {
      * @param period 周期类型字符串,表示不同的周期类型
      * @return 对应的月数如果输入的周期类型不匹配已知类型,则返回0
      */
-    private static int GetPeriodMonth(String period) {
+    public static int GetPeriodMonth(String period) {
         switch (period) {
             case PERIOD_TYPE_MONTH:
                 // 当周期类型为月时,返回1个月

+ 14 - 2
com.awspaas.user.apps.donenow_ctt/src/com/awspaas/user/apps/donenow_ctt/controller/contractCreateController.java

@@ -372,8 +372,10 @@ public class contractCreateController {
     @Mapping(value = "com.awspaas.user.apps.donenow_ctt.contract_service_period")
     public ResponseObject servicePeriod(UserContext uc, String contractId, String serviceIds) {
 
-        if (StringUtils.isBlank(contractId)) return ResponseObject.newErrResponse("请选择合同");
-        if (StringUtils.isBlank(serviceIds)) return ResponseObject.newErrResponse("请选择合同服务");
+        if (StringUtils.isBlank(contractId))
+            return ResponseObject.newErrResponse("请选择合同");
+        if (StringUtils.isBlank(serviceIds))
+            return ResponseObject.newErrResponse("请选择合同服务");
 
         BO contractBO = SDK.getBOAPI().get("BO_EU_DNCTT_CONTRACT", contractId);
 
@@ -400,9 +402,19 @@ public class contractCreateController {
             if (EFFECTIVE_DATE.isBefore(START_DATE) || EFFECTIVE_DATE.isAfter(END_DATE)) {
                 return ResponseObject.newErrResponse("服务生效日期必须在合同计费开始日期和结束日期之间");
             }
+
+            //如果已经做了服务调整,则不能重新生成服务周期, 跳过就行
+
+            if (DBSql.getInt("SELECT COUNT(1) CNT FROM BO_EU_DNCTT_CONTRACT_SERVICE_SALE_ADJUST WHERE CONTRACT_SERVICE_ID=? ", new Object[]{serviceId}) > 0) {
+                continue;
+            }
             services.add(contraService);
         }
 
+        if (services.size() == 0) {
+            return ResponseObject.newOkResponse();
+        }
+
         StringBuilder errMsg = new StringBuilder();
         StringBuilder succMsg = new StringBuilder();
         Connection conn = null;

+ 144 - 0
com.awspaas.user.apps.donenow_ctt/src/com/awspaas/user/apps/donenow_ctt/controller/contractServiceController.java

@@ -0,0 +1,144 @@
+package com.awspaas.user.apps.donenow_ctt.controller;
+
+import com.actionsoft.bpms.bo.engine.BO;
+import com.actionsoft.bpms.commons.mvc.view.ResponseObject;
+import com.actionsoft.bpms.server.UserContext;
+import com.actionsoft.bpms.server.bind.annotation.Controller;
+import com.actionsoft.bpms.server.bind.annotation.Mapping;
+import com.actionsoft.bpms.util.DBSql;
+import com.actionsoft.sdk.local.SDK;
+import com.actionsoft.sdk.local.api.Logger;
+import com.awspaas.user.apps.donenow_ctt.cttConstant;
+import com.awspaas.user.apps.donenow_ctt.service.contractServiceAdj;
+
+import java.time.LocalDate;
+
+import static com.awspaas.user.apps.donenow_ctt.service.contractService.LocalDateYYYYMMDD;
+import static com.awspaas.user.apps.donenow_ctt.service.contractService.getLocalDate;
+
+@Controller
+public class contractServiceController {
+    private static final Logger contractLogger = SDK.getLogAPI().getLogger(contractServiceController.class);//记录日志
+
+    /**
+     * 合同服务调整--销售
+     * @param uc
+     * @param serviceId
+     * @return
+     */
+    @Mapping(value = "com.awspaas.user.apps.donenow_ctt.service_sale_adjust")
+    public ResponseObject editServiceSale(UserContext uc, String serviceId) {
+        if (DBSql.getInt("SELECT count(1) CNT FROM BO_EU_DNCTT_CONTRACT_SERVICE_PERIOD WHERE CONTRACT_SERVICE_ID=?", new Object[]{serviceId}) == 0)
+            return ResponseObject.newErrResponse("请先完成未完成的合同服务");
+
+        //服务调整销售的表单地址
+        String processUrl = SDK.getFormAPI().getFormURL(SDK.getPortalAPI().getPortalUrl(), uc.getSessionId(), contractServiceAdj.getInstance().editServiceSale(uc, serviceId, null), null, 1, null, null, null, true);
+
+        ResponseObject responseObject = ResponseObject.newOkResponse();
+        responseObject.setData(processUrl);
+
+        return responseObject;
+    }
+
+    /**
+     * 执行合同服务调整--销售
+     * @param uc
+     * @param serviceId
+     * @return
+     */
+    @Mapping(value = "com.awspaas.user.apps.donenow_ctt.service_sale_execAdjust")
+    public ResponseObject execServiceSaleAdj(UserContext uc, String boId, String serviceId) {
+
+        //调整 服务
+        BO contractService = SDK.getBOAPI().get("BO_EU_DNCTT_CONTRACT_SERVICE_SALE_ADJUST", boId);
+
+        if (contractService.getString("IS_EFFECTIVE").equals("未执行") == false)
+            return ResponseObject.newErrResponse("请先完成未完成的调整单");
+
+
+        LocalDate EFFECTIVE_DATE = getLocalDate(contractService.get("EFFECTIVE_DATE"));//服务生效日期
+
+
+        //2025年10月15日 一次性收费服务
+        if (contractService.getString("PERIOD_TYPE").equals(cttConstant.PERIOD_TYPE_ONE_TIME)) {
+
+            //有审批通过的;
+            if (DBSql.getInt("SELECT count(1) FROM BO_EU_DNCTT_CONTRACT_SERVICE_PERIOD WHERE APPROVE_AND_POST_USER_ID IS NOT NULL AND LENGTH(APPROVE_AND_POST_USER_ID)>1 AND APPROVE_AND_POST_DATE IS NOT NULL and CONTRACT_SERVICE_ID=? ", new Object[]{serviceId}) > 0) {
+                return ResponseObject.newErrResponse("服务已审批不能再进行调整");
+            }
+
+        } else {
+            //生效日期之后有审批通过的;
+            if (DBSql.getInt("SELECT count(1) FROM BO_EU_DNCTT_CONTRACT_SERVICE_PERIOD WHERE APPROVE_AND_POST_USER_ID IS NOT NULL AND LENGTH(APPROVE_AND_POST_USER_ID)>1 AND APPROVE_AND_POST_DATE IS NOT NULL and CONTRACT_SERVICE_ID=? AND  PERIOD_END_DATE>=?", new Object[]{serviceId, LocalDateYYYYMMDD(EFFECTIVE_DATE)}) > 0) {
+                return ResponseObject.newErrResponse("生效日期之后的合同服务已经进行审批!");
+            }
+
+            //服务生效日期 不能大于合同服务上的生效日期
+            /*
+            if (DBSql.getInt("select count(1) CNT from BO_EU_DNCTT_CONTRACT_SERVICE where  ID =? and EFFECTIVE_DATE <=?", new Object[]{serviceId, LocalDateYYYYMMDD(EFFECTIVE_DATE)}) == 0) {
+                return ResponseObject.newErrResponse("调整服务生效日期不能大于合同服务上的生效日期");
+            }
+
+             */
+        }
+
+
+        if (contractServiceAdj.getInstance().execServiceSaleAdj(uc, boId))
+
+            return ResponseObject.newOkResponse();
+
+        return ResponseObject.newErrResponse("失败");
+    }
+
+    /**
+     * 合同服务调整--采购
+     * @param uc
+     * @param serviceId
+     * @return
+     */
+    @Mapping(value = "com.awspaas.user.apps.donenow_ctt.service_purchase_adjust")
+    public ResponseObject editServicePurchase(UserContext uc, String serviceId) {
+        if (DBSql.getInt("select count(1) CNT from BO_EU_DNIVT_ORDER_PAYMENT_PLAN where  CONTRACT_SERVICE_ID=? ", new Object[]{serviceId}) == 0) {
+            return ResponseObject.newErrResponse("请先生成该合同服务下的所有付款计划");
+        }
+
+        String processUrl = SDK.getFormAPI().getFormURL(SDK.getPortalAPI().getPortalUrl(), uc.getSessionId(), contractServiceAdj.getInstance().editServicePurchase(uc, serviceId, null), null, 1, null, null, null, true);
+
+        ResponseObject responseObject = ResponseObject.newOkResponse();
+        responseObject.setData(processUrl);
+
+        return responseObject;
+    }
+
+
+    /**
+     * 执行合同服务调整--采购
+     * @param uc
+     * @param serviceId
+     * @return
+     */
+    @Mapping(value = "com.awspaas.user.apps.donenow_ctt.service_purchase_execAdjust")
+    public ResponseObject execServicePurchaseAdj(UserContext uc, String boId, String serviceId) {
+        contractLogger.info("执行合同服务调整--采购");
+        contractLogger.info("boId:" + boId);
+        contractLogger.info("serviceId:" + serviceId);
+
+        //调整 服务
+        BO contractService = SDK.getBOAPI().get("BO_EU_DNCTT_CONTRACT_SERVICE_PURCHASE_ADJUST", boId);
+
+        if (contractService.getString("IS_EFFECTIVE").equals("未执行") == false)
+            return ResponseObject.newErrResponse("请先完成未完成的调整单");
+
+        LocalDate EFFECTIVE_DATE = getLocalDate(contractService.get("PURCHASE_START_DATE"));//服务生效日期
+
+        if (DBSql.getInt("select count(1) CNT from BO_EU_DNIVT_ORDER_PAYMENT_PLAN where  CONTRACT_SERVICE_ID=? and PERIOD_END_DATE >=?  and PAY_AMOUNT<>0 and PAY_AMOUNT is not NULL ", new Object[]{contractService.get("CONTRACT_SERVICE_ID"), LocalDateYYYYMMDD(EFFECTIVE_DATE)}) > 0) {
+            return ResponseObject.newErrResponse("生效日期之后,已经进行支付,不能改到当前日期");
+        }
+
+
+        if (contractServiceAdj.getInstance().execServicePurchaseAdj(uc, boId)) {
+            return ResponseObject.newOkResponse();
+        }
+        return ResponseObject.newOkResponse();
+    }
+}

+ 2 - 5
com.awspaas.user.apps.donenow_ctt/src/com/awspaas/user/apps/donenow_ctt/job/AutoRenewJob.java

@@ -31,6 +31,7 @@ public class AutoRenewJob implements Job {
      */
     @Override
     public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
+
         /*
         定期服务合同上加了自动续约功能,如果勾选,则其下的定期服务(不是一次性服务),需要自动修改计费结束时间,延长一年。触发时机:最后一个完整周期的开始日期
          */
@@ -40,7 +41,7 @@ public class AutoRenewJob implements Job {
 
         LocalDate next2Year = LocalDate.now().plusYears(2);//两年后
 
-        List<RowMap> list = DBSql.getMaps("SELECT a.ID, a.BINDID, a.START_DATE, a.END_DATE, b.EFFECTIVE_DATE, c.CONTRACT_SERVICE_ID, MIN(c.PERIOD_BEGIN_DATE) AS PERIOD_BEGIN_DATE, MIN(c.PERIOD_END_DATE) AS PERIOD_END_DATE, COUNT(c.ID) AS CNT FROM bo_eu_dnctt_contract a JOIN bo_eu_dnctt_contract_service b ON a.ID = b.CONTRACT_ID JOIN bo_eu_dnctt_contract_service_period c ON b.ID = c.CONTRACT_SERVICE_ID WHERE c.PERIOD_END_DATE>='" + nowDate + "' GROUP BY a.ID, a.BINDID, a.START_DATE, a.END_DATE, b.EFFECTIVE_DATE, c.CONTRACT_SERVICE_ID HAVING COUNT(c.ID)<=2 ORDER BY PERIOD_BEGIN_DATE DESC");
+        List<RowMap> list = DBSql.getMaps("SELECT a.ID, a.BINDID, a.START_DATE, a.END_DATE, b.EFFECTIVE_DATE, c.CONTRACT_SERVICE_ID, MIN(c.PERIOD_BEGIN_DATE) AS PERIOD_BEGIN_DATE, MIN(c.PERIOD_END_DATE) AS PERIOD_END_DATE, COUNT(c.ID) AS CNT FROM bo_eu_dnctt_contract a JOIN bo_eu_dnctt_contract_service b ON a.ID = b.CONTRACT_ID JOIN bo_eu_dnctt_contract_service_period c ON b.ID = c.CONTRACT_SERVICE_ID WHERE a.AUTO_RENEW=1 AND c.PERIOD_END_DATE>='" + nowDate + "' GROUP BY a.ID, a.BINDID, a.START_DATE, a.END_DATE, b.EFFECTIVE_DATE, c.CONTRACT_SERVICE_ID HAVING COUNT(c.ID)<=1 ORDER BY PERIOD_BEGIN_DATE DESC");
 
         UserContext uc = UserContext.fromUID("admin");
         contractService serviceOp = contractService.getInstance();
@@ -80,7 +81,6 @@ public class AutoRenewJob implements Job {
                         List<BO> serviceList = SDK.getBOAPI().query("BO_EU_DNCTT_CONTRACT_SERVICE").connection(conn).addQuery("CONTRACT_ID =", contract.get("ID")).list();
 
                         for (BO service : serviceList) {
-
                             //   boolean isAutoRenew = serviceOp.ServiceAutoRenew(uc, service, END_DATE, conn);
                             serviceOp.ServiceAdjustEndDate(uc, service, END_DATE, conn);
                         }
@@ -105,10 +105,7 @@ public class AutoRenewJob implements Job {
                     jobLogger.info("合同:" + contract.getString("NAME") + "[" + contract.getString("NO") + "]结束续约");
                 }
             }
-
-
         }
 
-
     }
 }

+ 45 - 0
com.awspaas.user.apps.donenow_ctt/src/com/awspaas/user/apps/donenow_ctt/job/ServiceAutoRenewJob.java

@@ -0,0 +1,45 @@
+package com.awspaas.user.apps.donenow_ctt.job;
+
+import com.actionsoft.bpms.commons.database.RowMap;
+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_ctt.service.contractServiceAdj;
+import org.quartz.Job;
+import org.quartz.JobExecutionContext;
+import org.quartz.JobExecutionException;
+
+import java.time.LocalDate;
+import java.util.List;
+
+public class ServiceAutoRenewJob implements Job {
+    private static final Logger jobLogger = SDK.getLogAPI().getLogger(ServiceAutoRenewJob.class);//记录日志
+
+    /**
+     * 合同服务定数续约
+     * @param jobExecutionContext
+     * @throws JobExecutionException
+     */
+    @Override
+    public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
+        //当前日期
+        UserContext uc = UserContext.fromUID("admin");
+
+        List<RowMap> sales = DBSql.getMaps("SELECT c.CONTRACT_SERVICE_ID, MAX( c.PERIOD_BEGIN_DATE) AS PERIOD_BEGIN_DATE, MAX( c.PERIOD_END_DATE) AS  PERIOD_END_DATE FROM bo_eu_dnctt_contract a JOIN bo_eu_dnctt_contract_service b ON a.ID = b.CONTRACT_ID JOIN bo_eu_dnctt_contract_service_period c ON b.ID = c.CONTRACT_SERVICE_ID WHERE a.AUTO_RENEW = 1  AND b.PERIOD_TYPE<>'609'  GROUP BY c.CONTRACT_SERVICE_ID HAVING MAX( c.PERIOD_BEGIN_DATE)<=DATE_ADD(NOW(), INTERVAL 1 MONTH)");
+        for (RowMap sale : sales) {
+            String contractServiceId = sale.getString("CONTRACT_SERVICE_ID");
+            LocalDate EFFECTIVE_DATE = TypeUtil.convert(sale.getDate("PERIOD_END_DATE"), LocalDate.class);
+            contractServiceAdj.getInstance().editServiceSaleEndDate(uc, contractServiceId, EFFECTIVE_DATE.plusYears(1).plusDays(1));
+        }
+
+        List<RowMap> purchs = DBSql.getMaps("SELECT c.CONTRACT_SERVICE_ID, MAX( c.PERIOD_BEGIN_DATE) AS PERIOD_BEGIN_DATE, MAX( c.PERIOD_END_DATE) AS  PERIOD_END_DATE FROM bo_eu_dnctt_contract a JOIN bo_eu_dnctt_contract_service b ON a.ID = b.CONTRACT_ID JOIN BO_EU_DNIVT_ORDER_PAYMENT_PLAN c ON b.ID = c.CONTRACT_SERVICE_ID WHERE a.AUTO_RENEW = 1   AND b.PURCHASE_PERIOD_TYPE<>'609' GROUP BY c.CONTRACT_SERVICE_ID HAVING MAX( c.PERIOD_BEGIN_DATE)<=DATE_ADD(NOW(), INTERVAL 1 MONTH)");
+        for (RowMap purch : purchs) {
+            String contractServiceId = purch.getString("CONTRACT_SERVICE_ID");
+            LocalDate EFFECTIVE_DATE = TypeUtil.convert(purch.getDate("PERIOD_END_DATE"), LocalDate.class);
+            contractServiceAdj.getInstance().editServicePurchaseEndDate(uc, contractServiceId, EFFECTIVE_DATE.plusYears(1).plusDays(1));
+        }
+    }
+
+}

+ 48 - 98
com.awspaas.user.apps.donenow_ctt/src/com/awspaas/user/apps/donenow_ctt/service/contractService.java

@@ -201,16 +201,14 @@ public class contractService {
             //更新合同产品上面的客户ID
             DBSql.update("update BO_EU_DNCTT_CONTRACT_COST set ACCOUNT_ID=?,BILL_ACCOUNT_ID=? where CONTRACT_ID=?", new Object[]{dto.getString("ACCOUNT_ID"), dto.getString("BILL_ACCOUNT_ID"), dto.getString("ID")});
 
-//2025年11月3日 新增服务后,不再自动生成服务周期
-/*
+            DBSql.update("UPDATE BO_EU_DNCTT_CONTRACT A JOIN BO_EU_DNCTT_CONTRACT_SERVICE B ON A.ID=B.CONTRACT_ID SET B.END_DATE=A.END_DATE WHERE A.ID=?   AND A.END_DATE IS NOT NULL", new Object[]{dto.getString("ID")});
+
+
             if (TYPE_ID.equals(cttConstant.CONTRACT_TYPE_SERVICE)) // 如果是服务合同
             {
                 try {
-
                     contractServiceLogger.info("服务---服务");
-
                     boolean flag = AddServiceServiceBundle(uc, dto);//新增服务或者服务包
-
                     contractServiceLogger.info("服务产品---服务产品");
                     AddContractServiceProduct(uc, dto);//新增服务或者服务包--关联产品
                     //更新服务产品价格
@@ -219,19 +217,12 @@ public class contractService {
                         resultDto.put("msg", "新增服务或服务包失败!");
                         return resultDto;
                     }
-
                 } catch (Exception e) {
-
                     e.printStackTrace();
-
                     contractServiceLogger.info("新增服务--info--失败。。。" + e.getMessage());
-
-                    resultDto.put("success", false);
-                    resultDto.put("msg", e.getMessage());
-                    return resultDto;
                 }
             }
-*/
+
             resultDto.put("success", true);
 
             return resultDto;
@@ -354,14 +345,12 @@ public class contractService {
      */
     public boolean AddServiceServiceBundle(UserContext uc, RowMap contract) throws SQLException {
         contractServiceLogger.info("新增服务或服务包");
+        LocalDate START_DATE = getLocalDate(contract.get("START_DATE"));//服务开始日期
+        LocalDate END_DATE = getLocalDate(contract.get("END_DATE"));//合同结束日期
         Connection conn = null;
         try {
             conn = DBSql.open();
             conn.setAutoCommit(false);
-
-            LocalDate START_DATE = getLocalDate(contract.get("START_DATE"));//服务开始日期
-            LocalDate END_DATE = getLocalDate(contract.get("END_DATE"));//合同结束日期
-
             //获取服务列表
             List<BO> serviceList = SDK.getBOAPI().query("BO_EU_DNCTT_CONTRACT_SERVICE").connection(conn).addQuery("CONTRACT_ID =", contract.get("ID")).list();
 
@@ -374,11 +363,11 @@ public class contractService {
                 // ServiceAutoRenew(uc, service, END_DATE, conn);
 
                 //修改合同结束日期
-                ServiceAdjustEndDate(uc, service, END_DATE, conn);
-            }
+                //ServiceAdjustEndDate(uc, service, END_DATE, conn);
 
+            }
             conn.commit();
-            return true;
+
         } catch (SQLException e) {
 
             contractServiceLogger.info("AddServiceServiceBundle--error--失败。。。" + e.getMessage());
@@ -388,9 +377,22 @@ public class contractService {
             conn.rollback();
 
         } finally {
-            if (conn != null) DBSql.close(conn);
+            if (conn != null)
+                DBSql.close(conn);
         }
-        return false;
+
+        try {
+            List<String> serviceIdList = DBSql.getList("select ID from BO_EU_DNCTT_CONTRACT_SERVICE where CONTRACT_ID=?", String.class, new Object[]{contract.get("ID")});
+
+            for (String contractServiceId : serviceIdList) {
+                contractServiceAdj.getInstance().editServiceSaleEndDate(uc, contractServiceId, END_DATE);
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+            contractServiceLogger.info("调整服务结束日期失败" + e.getMessage());
+        }
+
+        return true;
     }
 
 
@@ -1110,9 +1112,12 @@ public class contractService {
         LocalDate START_DATE = getLocalDate(contract.get("START_DATE"));//服务开始日期
         LocalDate END_DATE = getLocalDate(contract.get("END_DATE"));//合同结束日期
         LocalDate EFFECTIVE_DATE = getLocalDate(service.get("EFFECTIVE_DATE"));//服务生效日期
-        if (END_DATE == null) {
+        LocalDate EFFECTIVE_END_DATE = getLocalDate(service.get("END_DATE"));//服务结束日期
+        if (END_DATE == null && EFFECTIVE_END_DATE == null) {
             return false;
         }
+        if (EFFECTIVE_END_DATE != null)
+            END_DATE = EFFECTIVE_END_DATE;
 
         //已经审批并提交则不能重新生成服务
         if (DBSql.getInt("SELECT count(1) FROM BO_EU_DNCTT_CONTRACT_SERVICE_PERIOD WHERE APPROVE_AND_POST_USER_ID IS NOT NULL AND LENGTH(APPROVE_AND_POST_USER_ID)>1 AND APPROVE_AND_POST_DATE IS NOT NULL AND  BINDID=? and CONTRACT_ID=? and CONTRACT_SERVICE_ID=? ", new Object[]{service.get("BINDID"), contract.get("ID"), service.get("ID")}) > 0) {
@@ -1149,98 +1154,40 @@ public class contractService {
 
         //获取服务周期
         //List<PeriodCalculationUtil.Period> periodList = PeriodCalculationUtil.getPeriodList(PERIOD_TYPE, START_DATE, EFFECTIVE_DATE, END_DATE, true, true, -1);
-
-        List<PeriodCalculationUtil.Period> periodList = PeriodCalculationUtil.getPeriodListByConfig(PERIOD_TYPE, START_DATE, EFFECTIVE_DATE, END_DATE, service.getString("CALC_METHOD_1STPERIOD"), service.getString("CALC_METHOD_1STYEAR"), service.getString("MONTH_1STQUARTER"));
+        String CALC_METHOD_1STPERIOD = service.getString("CALC_METHOD_1STPERIOD");
+        List<PeriodCalculationUtil.Period> periodList = PeriodCalculationUtil.getPeriodListByConfig(PERIOD_TYPE, EFFECTIVE_DATE, EFFECTIVE_DATE, END_DATE, CALC_METHOD_1STPERIOD, service.getString("CALC_METHOD_1STYEAR"), service.getString("MONTH_1STQUARTER"));
 
         if (periodList != null && periodList.size() > 0) {
             String PERIOD = periodList.get(0).getPeriodBeginDateStr() + "~" + periodList.get(periodList.size() - 1).getPeriodEndDateStr();
 
-            BigDecimal UNIT_PRICE_1STMONTH = BigDecimal.ZERO;
-            BigDecimal UNIT_COST_1STMONTH = BigDecimal.ZERO;
-
-            //首月总价需要单独计算   613	按年支付	4591	开通日期所在月
-            if (periodList.size() > 0 && service.get("CALC_METHOD_1STPERIOD").equals("4591")) {
-                //firstRate<1
-                PeriodCalculationUtil.Period period = periodList.get(0);
-                if (period.getRate().compareTo(BigDecimal.ONE) < 0) {
-                    //首月成本需要单独计算
-                    UNIT_PRICE_1STMONTH = toBigDecimal(service.get("UNIT_PRICE_1STMONTH"));
-                    UNIT_PRICE_1STMONTH = period.getRate().multiply(BigDecimal.valueOf(12)).multiply(UNIT_PRICE_1STMONTH);
-
-                    //首期成本怎么算?  在同一个月 和不在 同一个月
-                    LocalDate PURCHASE_START_DATE = service.get("PURCHASE_START_DATE", LocalDate.class);
-
-                    if (EFFECTIVE_DATE.format(DateTimeFormatter.ofPattern("yyyyMM")).equals(PURCHASE_START_DATE.format(DateTimeFormatter.ofPattern("yyyyMM")))) {
-                        UNIT_COST_1STMONTH = toBigDecimal(service.get("UNIT_COST_1STMONTH"));
-                        UNIT_COST_1STMONTH = period.getRate().multiply(BigDecimal.valueOf(12)).multiply(UNIT_COST_1STMONTH);
-                        UNIT_COST_1STMONTH = period.getRate().multiply(UNIT_COST_1STMONTH);
-                    } else {
-                        UNIT_COST_1STMONTH = period.getRate().multiply(SERVICE_TOTAL_COST);
+            //首月+3个月、首月+6个月、首月+12个月 的情况,需要把前两条 合并成一条
+            if (periodList.size() > 1) {
+                if (CALC_METHOD_1STPERIOD.equals("4597") || CALC_METHOD_1STPERIOD.equals("4594") || CALC_METHOD_1STPERIOD.equals("4591")) {
+                    PeriodCalculationUtil.Period period1 = periodList.get(0);
+                    PeriodCalculationUtil.Period period2 = periodList.get(1);
+                    //小于1
+                    if (period1.getRate().compareTo(BigDecimal.ONE) < 1) {
+                        //合并
+                        period2.setRate(period1.getRate().add(period2.getRate()));
+                        period2.setPeriodBeginDate(period1.getPeriodBeginDate());
+                        //移除第一条
+                        periodList.remove(0);
                     }
                 }
             }
 
 
-            int i = 0;
             for (PeriodCalculationUtil.Period period : periodList) {
-
-                i++;
                 BO csp = new BO();//服务周期
                 csp.set("CONTRACT_ID", contract.get("ID"));
                 csp.set("OBJECT_ID", service.get("OBJECT_ID"));
                 csp.set("OBJECT_TYPE", service.get("OBJECT_TYPE"));
                 csp.set("CONTRACT_SERVICE_ID", service.get("ID"));
-
                 csp.set("PERIOD_BEGIN_DATE", period.getPeriodBeginDateStr());
                 csp.set("PERIOD_END_DATE", period.getPeriodEndDateStr());
-
                 csp.set("QUANTITY", service.get("QUANTITY"));
-
-                //首月总价需要单独计算   613	按年支付	4591	开通日期所在月
-                if (i == 1 && service.get("CALC_METHOD_1STPERIOD").equals("4591")) {
-                    //firstRate<1
-                    if (period.getRate().compareTo(BigDecimal.ONE) < 0) {
-
-                        //跳过
-                        //首月成本需要单独计算
-                        /*
-                        BigDecimal UNIT_PRICE_1STMONTH = toBigDecimal(service.get("UNIT_PRICE_1STMONTH"));
-                        UNIT_PRICE_1STMONTH = period.getRate().multiply(BigDecimal.valueOf(12)).multiply(UNIT_PRICE_1STMONTH);
-                        csp.set("PERIOD_PRICE", UNIT_PRICE_1STMONTH);
-
-                        //首期成本怎么算?  在同一个月 和不在 同一个月
-                        LocalDate PURCHASE_START_DATE = service.get("PURCHASE_START_DATE", LocalDate.class);
-
-                        if (EFFECTIVE_DATE.format(DateTimeFormatter.ofPattern("yyyyMM")).equals(PURCHASE_START_DATE.format(DateTimeFormatter.ofPattern("yyyyMM")))) {
-                            BigDecimal UNIT_COST_1STMONTH = toBigDecimal(service.get("UNIT_COST_1STMONTH"));
-                            UNIT_COST_1STMONTH = period.getRate().multiply(BigDecimal.valueOf(12)).multiply(UNIT_COST_1STMONTH);
-                            csp.set("PERIOD_COST", period.getRate().multiply(UNIT_COST_1STMONTH));
-                        } else {
-                            csp.set("PERIOD_COST", period.getRate().multiply(SERVICE_TOTAL_COST));
-                        }
-
-                        */
-
-                        if (periodList.size() == 1) {
-                            csp.set("PERIOD_PRICE", UNIT_PRICE_1STMONTH);
-                            csp.set("PERIOD_COST", UNIT_COST_1STMONTH);
-                        } else {
-                            continue;
-                        }
-                    } else {
-                        csp.set("PERIOD_PRICE", period.getRate().multiply(SERVICE_TOTAL_PRICE));
-                        csp.set("PERIOD_COST", period.getRate().multiply(SERVICE_TOTAL_COST));
-                    }
-
-                } else {
-                    if (i == 2 && UNIT_PRICE_1STMONTH.compareTo(BigDecimal.ZERO) > 0) {
-                        csp.set("PERIOD_PRICE", period.getRate().multiply(SERVICE_TOTAL_PRICE).add(UNIT_PRICE_1STMONTH));
-                        csp.set("PERIOD_COST", period.getRate().multiply(SERVICE_TOTAL_COST).add(UNIT_COST_1STMONTH));
-                    } else {
-                        csp.set("PERIOD_PRICE", period.getRate().multiply(SERVICE_TOTAL_PRICE));
-                        csp.set("PERIOD_COST", period.getRate().multiply(SERVICE_TOTAL_COST));
-                    }
-                }
+                csp.set("PERIOD_PRICE", period.getRate().multiply(SERVICE_TOTAL_PRICE));
+                csp.set("PERIOD_COST", period.getRate().multiply(SERVICE_TOTAL_COST));
 
                 csp.set("PERIOD_ADJUSTED_PRICE", csp.get("PERIOD_PRICE"));
 
@@ -1287,7 +1234,8 @@ public class contractService {
      * @return
      */
     public boolean ServiceAdjustEndDate(UserContext uc, BO service, LocalDate END_DATE, Connection conn) {
-        if (END_DATE == null) return true;
+        if (END_DATE == null)
+            return true;
 
         String PERIOD_TYPE = service.getString("PERIOD_TYPE");//服务周期类型
         //已经审批并提交则不能重新生成服务
@@ -2100,6 +2048,8 @@ public class contractService {
         contractCost.set("EXTENDED_COST", multiply(service.get("UNIT_COST"), service.get("QUANTITY")));//总成本
         contractCost.set("EXTENDED_PRICE", multiply(service.get("UNIT_PRICE"), service.get("QUANTITY")));//总价
 
+        //计费客户
+        contractCost.set("BILL_ACCOUNT_ID", serviceBO.get("BILL_TO_ACCOUNT_ID"));
 
         // contractServiceLogger.info("计算合同成本周期:" + service);
         // 需要通过采购计算总成本

+ 683 - 0
com.awspaas.user.apps.donenow_ctt/src/com/awspaas/user/apps/donenow_ctt/service/contractServiceAdj.java

@@ -0,0 +1,683 @@
+package com.awspaas.user.apps.donenow_ctt.service;
+
+import com.actionsoft.bpms.bo.engine.BO;
+import com.actionsoft.bpms.bpmn.engine.model.run.delegate.ProcessInstance;
+import com.actionsoft.bpms.commons.database.RowMap;
+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_ctt.PeriodCalculationUtil;
+import org.apache.commons.lang3.StringUtils;
+
+import java.math.BigDecimal;
+import java.sql.Connection;
+import java.sql.SQLException;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Arrays;
+import java.util.List;
+
+import static com.awspaas.user.apps.donenow_ctt.PeriodCalculationUtil.GetPeriodMonth;
+import static com.awspaas.user.apps.donenow_ctt.PeriodCalculationUtil.getDateRate;
+import static com.awspaas.user.apps.donenow_ctt.service.contractService.*;
+import static com.awspaas.user.apps.donenow_ctt.service.contractService.LocalDateYYYYMMDD;
+
+public class contractServiceAdj {
+    private static final Logger contractServiceLogger = SDK.getLogAPI().getLogger(contractServiceAdj.class);//记录日志
+    private final String[] excludesArray = new String[]{"ID", "ORGID", "BINDID", "CREATEDATE", "CREATEUSER", "UPDATEDATE", "UPDATEUSER", "PROCESSDEFID", "ISEND"};
+
+
+    private static volatile contractServiceAdj instance;
+
+    private contractServiceAdj() {
+        // Constructor logic here, if any.
+    }
+
+    public static contractServiceAdj getInstance() {
+        if (instance == null) {
+            synchronized (contractServiceAdj.class) {
+                if (instance == null) {
+                    instance = new contractServiceAdj();
+                }
+            }
+        }
+        return instance;
+    }
+
+
+    /**
+     * 服务调整销售
+     * @param uc
+     * @param serviceId
+     * @param remark
+     * @return
+     */
+    public String editServiceSale(UserContext uc, String serviceId, String remark) {
+        RowMap contractService = DBSql.getMap("SELECT * FROM BO_EU_DNCTT_CONTRACT_SERVICE_SALE_ADJUST WHERE CONTRACT_SERVICE_ID=? AND IS_EFFECTIVE='未执行' ", new Object[]{serviceId});
+
+        //存在未完成的调整单,继续编辑
+        if (contractService != null) {
+            return contractService.getString("BINDID");
+        }
+
+        contractService = DBSql.getMap("SELECT * FROM BO_EU_DNCTT_CONTRACT_SERVICE_SALE_ADJUST WHERE CONTRACT_SERVICE_ID=? AND IS_EFFECTIVE='已执行' ORDER BY  CREATEDATE DESC ", new Object[]{serviceId});
+
+        String processDefId = "obj_e65c7e68c00544afb66a27848a5cba14";//销售
+
+        if (contractService == null) {
+            //初始化
+            contractService = DBSql.getMap("SELECT * FROM BO_EU_DNCTT_CONTRACT_SERVICE WHERE ID=?", new Object[]{serviceId});
+            contractService.remove("ID");
+            contractService.remove("BINDID");
+            ProcessInstance contractInstance = SDK.getProcessAPI().createBOProcessInstance(processDefId, uc.getUID(), "服务调整-" + contractService.getString("NAME") + "-初始");
+            BO editBO = new BO();
+            contractService.remove("CREATEDATE");
+            contractService.remove("CREATEUSER");
+            editBO.setAll(contractService);
+            editBO.setBindId(contractInstance.getId());
+            editBO.set("CONTRACT_SERVICE_ID", serviceId);
+            editBO.set("IS_EFFECTIVE", "已执行");
+            SDK.getBOAPI().create("BO_EU_DNCTT_CONTRACT_SERVICE_SALE_ADJUST", editBO, contractInstance, uc);
+        }
+
+        contractService.remove("ID");
+        contractService.remove("BINDID");
+
+        //新的调整单
+        ProcessInstance contractInstance = SDK.getProcessAPI().createBOProcessInstance(processDefId, uc.getUID(), "服务调整-" + contractService.getString("NAME") + "-" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")));
+        BO editBO = new BO();
+        contractService.remove("CREATEDATE");
+        contractService.remove("CREATEUSER");
+        editBO.setAll(contractService);
+        editBO.set("CONTRACT_SERVICE_ID", serviceId);
+        editBO.setBindId(contractInstance.getId());
+        editBO.set("IS_EFFECTIVE", "未执行");
+        editBO.set("REMARK", remark);
+
+        SDK.getBOAPI().create("BO_EU_DNCTT_CONTRACT_SERVICE_SALE_ADJUST", editBO, contractInstance, uc);
+
+        return contractInstance.getId();
+
+    }
+
+
+    /**
+     * 执行服务调整销售
+     * @param uc
+     * @param boId
+     * @return
+     */
+    public boolean execServiceSaleAdj(UserContext uc, String boId) {
+        BO contractService = SDK.getBOAPI().get("BO_EU_DNCTT_CONTRACT_SERVICE_SALE_ADJUST", boId);
+        LocalDate EFFECTIVE_DATE = getLocalDate(contractService.get("EFFECTIVE_DATE"));//服务生效日期
+        LocalDate EFFECTIVE_END_DATE = getLocalDate(contractService.get("END_DATE"));//服务结束日期
+
+        //合同服务
+        BO orgContractService = SDK.getBOAPI().get("BO_EU_DNCTT_CONTRACT_SERVICE", contractService.getString("CONTRACT_SERVICE_ID"));
+
+        //生效日期之前的一次调整
+        RowMap lastContractService = DBSql.getMap("select * from BO_EU_DNCTT_CONTRACT_SERVICE_SALE_ADJUST where  CONTRACT_SERVICE_ID=? and EFFECTIVE_DATE <=? and IS_EFFECTIVE='已执行' order by EFFECTIVE_DATE desc", new Object[]{contractService.get("CONTRACT_SERVICE_ID"), LocalDateYYYYMMDD(EFFECTIVE_DATE)});
+
+        String PERIOD_TYPE = contractService.getString("PERIOD_TYPE");
+
+        Connection conn = null;
+        try {
+            conn = DBSql.open();
+            conn.setAutoCommit(false);
+
+            //生效日期之后的服务周期删除
+            DBSql.update(conn, "DELETE FROM BO_EU_DNCTT_CONTRACT_SERVICE_PERIOD_BUNDLE_SERVICE WHERE CONTRACT_SERVICE_PERIOD_ID IN (SELECT ID FROM BO_EU_DNCTT_CONTRACT_SERVICE_PERIOD WHERE CONTRACT_SERVICE_ID =? AND PERIOD_BEGIN_DATE >=?)", new Object[]{contractService.get("CONTRACT_SERVICE_ID"), LocalDateYYYYMMDD(EFFECTIVE_DATE)});
+
+            DBSql.update(conn, "DELETE FROM BO_EU_DNCTT_CONTRACT_SERVICE_PERIOD WHERE CONTRACT_SERVICE_ID=? AND PERIOD_BEGIN_DATE>=?", new Object[]{contractService.get("CONTRACT_SERVICE_ID"), LocalDateYYYYMMDD(EFFECTIVE_DATE)});
+
+            //如果生效日期之后有服务周期
+            String lastPeriodId = DBSql.getString(conn, "SELECT ID FROM BO_EU_DNCTT_CONTRACT_SERVICE_PERIOD WHERE CONTRACT_SERVICE_ID=? AND PERIOD_END_DATE >=? ORDER BY PERIOD_BEGIN_DATE ASC ", new Object[]{contractService.get("CONTRACT_SERVICE_ID"), LocalDateYYYYMMDD(EFFECTIVE_DATE)});
+
+            BigDecimal SERVICE_UNIT_PRICE = null;
+            BigDecimal SERVICE_TOTAL_PRICE = null;
+
+            if (StringUtils.isNotBlank(lastPeriodId)) {
+                SERVICE_UNIT_PRICE = TypeUtil.convert(lastContractService.get("UNIT_PRICE"), BigDecimal.class);
+                SERVICE_TOTAL_PRICE = multiply(SERVICE_UNIT_PRICE, lastContractService.get("QUANTITY"));
+
+                BO lastServicePeriod = SDK.getBOAPI().get("BO_EU_DNCTT_CONTRACT_SERVICE_PERIOD", lastPeriodId);
+
+                LocalDate last_period_begin_date = getLocalDate(lastServicePeriod.get("PERIOD_BEGIN_DATE"));
+
+                lastServicePeriod.set("PERIOD_END_DATE", EFFECTIVE_DATE.minusDays(1));
+
+                BigDecimal periodRate = PeriodCalculationUtil.divideToBigDecimal(getDateRate(last_period_begin_date, EFFECTIVE_DATE.minusDays(1), false), GetPeriodMonth(lastContractService.getString("PERIOD_TYPE")));
+
+                lastServicePeriod.set("PERIOD_PRICE", multiply(SERVICE_TOTAL_PRICE, periodRate));
+                lastServicePeriod.set("PARTYA_PERIOD_PRICE", multiply(lastContractService.get("PARTYA_TOTAL_PRICE"), periodRate));
+                lastServicePeriod.set("PERIOD_ADJUSTED_PRICE", lastServicePeriod.get("PERIOD_PRICE"));
+                SDK.getBOAPI().update("BO_EU_DNCTT_CONTRACT_SERVICE_PERIOD", lastServicePeriod, conn);
+
+            }
+
+            String CALC_METHOD_1STPERIOD = contractService.getString("CALC_METHOD_1STPERIOD");
+            //获取服务周期
+            List<PeriodCalculationUtil.Period> periodList = PeriodCalculationUtil.getPeriodListByConfig(PERIOD_TYPE, EFFECTIVE_DATE, EFFECTIVE_DATE, EFFECTIVE_END_DATE, CALC_METHOD_1STPERIOD, "4638", contractService.getString("MONTH_1STQUARTER"));
+
+            SERVICE_UNIT_PRICE = TypeUtil.convert(contractService.get("UNIT_PRICE"), BigDecimal.class);
+
+            SERVICE_TOTAL_PRICE = multiply(SERVICE_UNIT_PRICE, contractService.get("QUANTITY"));
+
+            String vendor_account_id = DBSql.getString(conn, "select VENDOR_ACCOUNT_ID from BO_EU_DNIVT_SERVICE where ID=?", new Object[]{orgContractService.getString("OBJECT_ID")});//供应商账号
+
+            if (periodList != null && periodList.size() > 0) {
+
+                List<String> sbsList = null;
+                String serviceIds = DBSql.getString("select SERVICE_ID from BO_EU_DNIVT_SERVICE_BUNDLE where ID=?", new Object[]{orgContractService.get("OBJECT_ID")});
+                if (StringUtils.isNotBlank(serviceIds)) {
+                    sbsList = Arrays.asList(serviceIds.split(","));
+                }
+
+                //首月+3个月、首月+6个月、首月+12个月 的情况,需要把前两条 合并成一条
+                if (periodList.size() > 1) {
+                    if (CALC_METHOD_1STPERIOD.equals("4597") || CALC_METHOD_1STPERIOD.equals("4594") || CALC_METHOD_1STPERIOD.equals("4591")) {
+                        PeriodCalculationUtil.Period period1 = periodList.get(0);
+                        PeriodCalculationUtil.Period period2 = periodList.get(1);
+                        //小于1
+                        if (period1.getRate().compareTo(BigDecimal.ONE) < 1) {
+                            //合并
+                            period2.setRate(period1.getRate().add(period2.getRate()));
+                            period2.setPeriodBeginDate(period1.getPeriodBeginDate());
+                            //移除第一条
+                            periodList.remove(0);
+                        }
+                    }
+                }
+
+
+                for (PeriodCalculationUtil.Period period : periodList) {
+
+                    BO csp = new BO();//服务周期
+                    csp.set("CONTRACT_ID", orgContractService.get("CONTRACT_ID"));
+                    csp.set("OBJECT_ID", orgContractService.get("OBJECT_ID"));
+                    csp.set("OBJECT_TYPE", orgContractService.get("OBJECT_TYPE"));
+                    csp.set("CONTRACT_SERVICE_ID", orgContractService.get("ID"));
+                    csp.set("PERIOD_BEGIN_DATE", period.getPeriodBeginDateStr());
+                    csp.set("PERIOD_END_DATE", period.getPeriodEndDateStr());
+                    csp.set("QUANTITY", contractService.get("QUANTITY"));
+
+                    csp.set("PERIOD_PRICE", period.getRate().multiply(SERVICE_TOTAL_PRICE));
+                    csp.set("PERIOD_ADJUSTED_PRICE", csp.get("PERIOD_PRICE"));
+                    csp.set("PARTYA_PERIOD_PRICE", multiply(contractService.get("PARTYA_TOTAL_PRICE"), period.getRate()));//三方合同甲方含税总价
+
+                    csp.set("VENDOR_ACCOUNT_ID", vendor_account_id);
+                    csp.setBindId(orgContractService.getString("BINDID"));
+                    SDK.getBOAPI().createDataBO("BO_EU_DNCTT_CONTRACT_SERVICE_PERIOD", csp, uc, conn);
+
+
+                    if (orgContractService.getString("OBJECT_TYPE").equals("2"))//服务包
+                    {
+                        //本周期成本
+                        String prorated_cost_change = DBSql.getString(conn, "select UNIT_COST from BO_EU_DNIVT_SERVICE where ID=?", new Object[]{orgContractService.getString("OBJECT_ID")});//供应商账号
+                        if (sbsList != null) {
+                            for (String sbs : sbsList) {
+                                BO cspbs = new BO();
+                                cspbs.set("CONTRACT_SERVICE_PERIOD_ID", csp.getId());
+                                cspbs.set("SERVICE_ID", sbs);
+                                cspbs.set("VENDOR_ACCOUNT_ID", vendor_account_id);
+                                cspbs.set("PERIOD_COST", prorated_cost_change);
+                                cspbs.setBindId(orgContractService.getString("BINDID"));
+                                SDK.getBOAPI().createDataBO("BO_EU_DNCTT_CONTRACT_SERVICE_PERIOD_BUNDLE_SERVICE", cspbs, uc, conn);
+                            }
+                        }
+                    }
+                }
+            }
+
+
+            contractService.set("IS_EFFECTIVE", "已执行");
+            SDK.getBOAPI().update("BO_EU_DNCTT_CONTRACT_SERVICE_SALE_ADJUST", contractService, conn);
+            DBSql.update(conn, "update BO_EU_DNCTT_CONTRACT_SERVICE_SALE_ADJUST set IS_EFFECTIVE='作废' where CONTRACT_SERVICE_ID=? and EFFECTIVE_DATE >?", new Object[]{contractService.get("CONTRACT_SERVICE_ID"), LocalDateYYYYMMDD(EFFECTIVE_DATE)});
+
+            orgContractService.set("END_DATE", contractService.get("END_DATE"));
+            orgContractService.set("UNIT_PRICE", contractService.get("UNIT_PRICE"));
+            orgContractService.set("TOTAL_PRICE", contractService.get("TOTAL_PRICE"));
+            orgContractService.set("QUANTITY", contractService.get("QUANTITY"));
+            orgContractService.set("PERIOD_TYPE", contractService.get("PERIOD_TYPE"));
+            orgContractService.set("CALC_METHOD_1STPERIOD", contractService.get("CALC_METHOD_1STPERIOD"));
+            orgContractService.set("MONTH_1STQUARTER", contractService.get("MONTH_1STQUARTER"));
+
+            //计算各种不含税金额
+            // 确定周期对应的月数
+            int periodMonths;
+            switch (contractService.getString("PERIOD_TYPE")) {
+                case "610":
+                    periodMonths = 1; // 按月
+                    break;
+                case "611":
+                    periodMonths = 3; // 按季度
+                    break;
+                case "612":
+                    periodMonths = 6; // 按半年
+                    break;
+                case "613":
+                    periodMonths = 12; // 按年
+                    break;
+                default:
+                    periodMonths = 1;
+                    break;
+            }
+
+
+            //月单价  UNIT_PRICE_MONTH
+            orgContractService.set("SERVICE_UNIT_PRICE", SERVICE_UNIT_PRICE.divide(BigDecimal.valueOf(periodMonths)));
+
+            RowMap taxCate = DBSql.getMap("SELECT OID,NAME,ORGID,GENERAL_TABLE_ID,EXT1,CLOSED,IS_ACTIVE FROM BO_EU_DND_GENERAL WHERE  GENERAL_TABLE_ID=44 AND ORGID=? AND OID=?", new Object[]{uc.getCompanyModel().getId(), orgContractService.getString("TAX_CATEGORY_ID")}); //税种
+
+            if (taxCate != null) {
+                BigDecimal taxRate = new BigDecimal(taxCate.getString("EXT1"));
+                //月不含税单价 UNIT_PRICE_MONTH_NOTAX
+                BigDecimal taxExcluded = SERVICE_UNIT_PRICE.divide(BigDecimal.valueOf(periodMonths)).divide(BigDecimal.ONE.add(taxRate), 4, BigDecimal.ROUND_HALF_UP); // 保留4位小数
+                orgContractService.set("SERVICE_UNIT_PRICE_NOTAX", taxExcluded);
+
+                //周期不含税单价 UNIT_PRICE_NOTAX
+
+                orgContractService.set("UNIT_PRICE_NOTAX", SERVICE_UNIT_PRICE.divide(BigDecimal.ONE.add(taxRate), 4, BigDecimal.ROUND_HALF_UP));
+
+                //周期不含税总价 TOTAL_PRICE_NOTAX
+                orgContractService.set("TOTAL_PRICE_NOTAX", SERVICE_TOTAL_PRICE.divide(BigDecimal.ONE.add(taxRate), 4, BigDecimal.ROUND_HALF_UP));
+            } else {
+                orgContractService.set("SERVICE_UNIT_PRICE_NOTAX", null);
+                orgContractService.set("UNIT_PRICE_NOTAX", null);
+                orgContractService.set("TOTAL_PRICE_NOTAX", null);
+            }
+
+            //如果合同服务上面的生效日期小于服务调整的生效日期,则将合同服务生效日期改为服务调整的生效日期
+            if (orgContractService.get("EFFECTIVE_DATE", LocalDate.class).compareTo(contractService.get("EFFECTIVE_DATE", LocalDate.class)) < 0)
+                orgContractService.set("EFFECTIVE_DATE", contractService.get("EFFECTIVE_DATE"));
+
+            SDK.getBOAPI().update("BO_EU_DNCTT_CONTRACT_SERVICE", orgContractService, conn);
+
+            conn.commit();
+        } catch (SQLException e) {
+
+            e.printStackTrace();
+            try {
+                conn.rollback();
+            } catch (SQLException e1) {
+                e1.printStackTrace();
+            }
+        } finally {
+            if (conn != null) DBSql.close(conn);
+        }
+
+        return true;
+    }
+
+    /**
+     *  服务调整--销售 修改结束时间
+     * @param uc
+     * @param serviceId
+     * @param newEndDate
+     * @return
+     */
+    public String editServiceSaleEndDate(UserContext uc, String serviceId, LocalDate newEndDate) {
+
+        RowMap lastServicePeriod = DBSql.getMap("SELECT * FROM BO_EU_DNCTT_CONTRACT_SERVICE_PERIOD WHERE CONTRACT_SERVICE_ID=? ORDER BY PERIOD_BEGIN_DATE DESC", new Object[]{serviceId});//最后一笔服务周期
+
+        LocalDate PERIOD_BEGIN_DATE = TypeUtil.convert(lastServicePeriod.get("PERIOD_BEGIN_DATE"), LocalDate.class);
+        LocalDate PERIOD_END_DATE = TypeUtil.convert(lastServicePeriod.get("PERIOD_END_DATE"), LocalDate.class);
+
+        String bindId = editServiceSale(uc, serviceId, "修改结束日期");
+
+        BO adjBO = SDK.getBOAPI().getByProcess("BO_EU_DNCTT_CONTRACT_SERVICE_SALE_ADJUST", bindId);
+
+        if (PERIOD_END_DATE.equals(newEndDate))
+            return "无需修改";
+
+        if (PERIOD_END_DATE.isAfter(newEndDate)) {
+            //缩短
+
+            if (PERIOD_BEGIN_DATE.isBefore(newEndDate)) {
+                if (lastServicePeriod.get("APPROVE_AND_POST_DATE") != null && StringUtils.isNotBlank(lastServicePeriod.getString("APPROVE_AND_POST_USER_ID")))
+                    return "已审批不能修改了";
+
+                adjBO.set("EFFECTIVE_DATE", PERIOD_BEGIN_DATE);
+            } else {
+
+                String EFFECTIVE_DATE = DBSql.getString("SELECT max(PERIOD_BEGIN_DATE) as PERIOD_BEGIN_DATE FROM BO_EU_DNCTT_CONTRACT_SERVICE_PERIOD WHERE APPROVE_AND_POST_DATE IS NULL and CONTRACT_SERVICE_ID=? AND  PERIOD_BEGIN_DATE <=?", new Object[]{serviceId, LocalDateYYYYMMDD(newEndDate)});
+
+                LocalDate EFFECTIVE_DATE1 = TypeUtil.convert(lastServicePeriod.get("EFFECTIVE_DATE"), LocalDate.class);
+
+                if (EFFECTIVE_DATE1.isAfter(newEndDate))
+                    return "已审批不能修改了";
+
+                adjBO.set("EFFECTIVE_DATE", EFFECTIVE_DATE1);
+
+                //最近的一次服务调整
+                RowMap lastContractServiceAdj = DBSql.getMap("SELECT * FROM BO_EU_DNCTT_CONTRACT_SERVICE_SALE_ADJUST WHERE CONTRACT_SERVICE_ID=? AND IS_EFFECTIVE='已执行' AND EFFECTIVE_DATE <=? ORDER BY EFFECTIVE_DATE DESC", new Object[]{serviceId, LocalDateYYYYMMDD(EFFECTIVE_DATE1)});
+
+                adjBO.set("UNIT_PRICE", lastContractServiceAdj.getString("UNIT_PRICE"));
+                adjBO.set("TOTAL_PRICE", lastContractServiceAdj.getString("TOTAL_PRICE"));
+                adjBO.set("QUANTITY", lastContractServiceAdj.getString("QUANTITY"));
+                adjBO.set("PERIOD_TYPE", lastContractServiceAdj.getString("PERIOD_TYPE"));
+                adjBO.set("CALC_METHOD_1STPERIOD", lastContractServiceAdj.getString("CALC_METHOD_1STPERIOD"));
+                adjBO.set("MONTH_1STQUARTER", lastContractServiceAdj.getString("MONTH_1STQUARTER"));
+                adjBO.set("PARTYA_TOTAL_PRICE", lastContractServiceAdj.getString("PARTYA_TOTAL_PRICE"));
+                adjBO.set("UNIT_PRICE_1STMONTH", lastContractServiceAdj.getString("UNIT_PRICE_1STMONTH"));
+
+            }
+
+        } else {
+            //延长
+            if (lastServicePeriod.get("APPROVE_AND_POST_DATE") != null && StringUtils.isNotBlank(lastServicePeriod.getString("APPROVE_AND_POST_USER_ID"))) {
+                adjBO.set("EFFECTIVE_DATE", PERIOD_END_DATE.plusDays(1));
+            } else {
+                adjBO.set("EFFECTIVE_DATE", PERIOD_BEGIN_DATE);
+            }
+            adjBO.set("REMARK", "修改结束日期");
+        }
+        adjBO.set("END_DATE", newEndDate);
+
+        SDK.getBOAPI().update("BO_EU_DNCTT_CONTRACT_SERVICE_SALE_ADJUST", adjBO);
+
+        execServiceSaleAdj(uc, adjBO.getId());
+
+        DBSql.update("update bo_eu_dnctt_contract_service set END_DATE=? where ID=?", new Object[]{LocalDateYYYYMMDD(newEndDate), serviceId});
+
+        return "ok";
+    }
+
+
+    /**
+     * 服务调整--采购
+     * @param uc
+     * @param serviceId
+     * @param remark
+     * @return
+     */
+    public String editServicePurchase(UserContext uc, String serviceId, String remark) {
+        RowMap contractService = DBSql.getMap("SELECT * FROM BO_EU_DNCTT_CONTRACT_SERVICE_PURCHASE_ADJUST WHERE CONTRACT_SERVICE_ID=? AND IS_EFFECTIVE='未执行' ", new Object[]{serviceId});
+
+        //存在未完成的调整单,继续编辑
+        if (contractService != null) {
+            return contractService.getString("BINDID");
+        }
+
+        contractService = DBSql.getMap("SELECT * FROM BO_EU_DNCTT_CONTRACT_SERVICE_PURCHASE_ADJUST WHERE CONTRACT_SERVICE_ID=? AND IS_EFFECTIVE='已执行' ORDER BY  CREATEDATE DESC ", new Object[]{serviceId});
+
+        String processDefId = "obj_b147ad05008546058736a06bc6205313";//采购
+
+        if (contractService == null) {
+            //初始化
+            contractService = DBSql.getMap("SELECT * FROM BO_EU_DNCTT_CONTRACT_SERVICE WHERE ID=?", new Object[]{serviceId});
+            contractService.remove("ID");
+            contractService.remove("BINDID");
+            ProcessInstance contractInstance = SDK.getProcessAPI().createBOProcessInstance(processDefId, uc.getUID(), "服务调整-" + contractService.getString("NAME") + "-初始");
+            BO editBO = new BO();
+            contractService.remove("CREATEDATE");
+            contractService.remove("CREATEUSER");
+            editBO.setAll(contractService);
+            editBO.setBindId(contractInstance.getId());
+            editBO.set("CONTRACT_SERVICE_ID", serviceId);
+            editBO.set("IS_EFFECTIVE", "已执行");
+            SDK.getBOAPI().create("BO_EU_DNCTT_CONTRACT_SERVICE_PURCHASE_ADJUST", editBO, contractInstance, uc);
+        }
+
+        contractService.remove("ID");
+        contractService.remove("BINDID");
+
+        //新的调整单
+        ProcessInstance contractInstance = SDK.getProcessAPI().createBOProcessInstance(processDefId, uc.getUID(), "服务调整-" + contractService.getString("NAME") + "-" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")));
+        BO editBO = new BO();
+        contractService.remove("CREATEDATE");
+        contractService.remove("CREATEUSER");
+        editBO.setAll(contractService);
+        editBO.set("CONTRACT_SERVICE_ID", serviceId);
+        editBO.setBindId(contractInstance.getId());
+        editBO.set("IS_EFFECTIVE", "未执行");
+        editBO.set("REMARK", remark);
+        SDK.getBOAPI().create("BO_EU_DNCTT_CONTRACT_SERVICE_PURCHASE_ADJUST", editBO, contractInstance, uc);
+
+        return contractInstance.getId();
+    }
+
+
+    /**
+     *  服务调整--采购 修改结束时间
+     * @param uc
+     * @param serviceId
+     * @param newEndDate
+     * @return
+     */
+    public String editServicePurchaseEndDate(UserContext uc, String serviceId, LocalDate newEndDate) {
+
+        RowMap lastServicePeriod = DBSql.getMap("SELECT * FROM BO_EU_DNIVT_ORDER_PAYMENT_PLAN WHERE CONTRACT_SERVICE_ID=? ORDER BY PERIOD_BEGIN_DATE DESC", new Object[]{serviceId});//最后一笔服务周期
+
+        LocalDate PERIOD_BEGIN_DATE = TypeUtil.convert(lastServicePeriod.get("PERIOD_BEGIN_DATE"), LocalDate.class);
+        LocalDate PERIOD_END_DATE = TypeUtil.convert(lastServicePeriod.get("PERIOD_END_DATE"), LocalDate.class);
+
+        String bindId = editServiceSale(uc, serviceId, "修改结束日期");
+
+        BO adjBO = SDK.getBOAPI().getByProcess("BO_EU_DNCTT_CONTRACT_SERVICE_PURCHASE_ADJUST", bindId);
+
+        if (PERIOD_END_DATE.equals(newEndDate))
+            return "无需修改";
+
+        if (PERIOD_END_DATE.isAfter(newEndDate)) {
+            //缩短
+            if (PERIOD_BEGIN_DATE.isBefore(newEndDate)) {
+                if (lastServicePeriod.get("PAY_AMOUNT") != null && lastServicePeriod.getDouble("PAY_AMOUNT") != 0)
+                    return "已审批不能修改了";
+
+                adjBO.set("PURCHASE_START_DATE", PERIOD_BEGIN_DATE);
+            } else {
+
+                String EFFECTIVE_DATE = DBSql.getString("SELECT max(PERIOD_BEGIN_DATE) as PERIOD_BEGIN_DATE FROM BO_EU_DNIVT_ORDER_PAYMENT_PLAN WHERE  PAY_AMOUNT<>0 and PAY_AMOUNT is not NULL  and CONTRACT_SERVICE_ID=? AND  PERIOD_BEGIN_DATE <=?", new Object[]{serviceId, LocalDateYYYYMMDD(newEndDate)});
+
+                LocalDate EFFECTIVE_DATE1 = TypeUtil.convert(lastServicePeriod.get("EFFECTIVE_DATE"), LocalDate.class);
+
+                if (EFFECTIVE_DATE1.isAfter(newEndDate))
+                    return "已审批不能修改了";
+
+                adjBO.set("PURCHASE_START_DATE", EFFECTIVE_DATE1);
+
+                //最近的一次服务调整
+                RowMap lastContractServiceAdj = DBSql.getMap("SELECT * FROM BO_EU_DNCTT_CONTRACT_SERVICE_PURCHASE_ADJUST WHERE CONTRACT_SERVICE_ID=? AND IS_EFFECTIVE='已执行' AND PURCHASE_START_DATE <=? ORDER BY PURCHASE_START_DATE DESC", new Object[]{serviceId, LocalDateYYYYMMDD(EFFECTIVE_DATE1)});
+
+                adjBO.set("UNIT_COST", lastContractServiceAdj.getString("UNIT_COST"));
+                adjBO.set("TOTAL_COST", lastContractServiceAdj.getString("TOTAL_COST"));
+                adjBO.set("QUANTITY", lastContractServiceAdj.getString("QUANTITY"));
+                adjBO.set("PURCHASE_PERIOD_TYPE", lastContractServiceAdj.getString("PURCHASE_PERIOD_TYPE"));
+                adjBO.set("PURCHASE_CALC_METHOD_1STPERIOD", lastContractServiceAdj.getString("PURCHASE_CALC_METHOD_1STPERIOD"));
+                adjBO.set("MONTH_1STQUARTER", lastContractServiceAdj.getString("MONTH_1STQUARTER"));
+                adjBO.set("UNIT_COST_1STMONTH", lastContractServiceAdj.getString("UNIT_COST_1STMONTH"));
+            }
+
+        } else {
+            //延长
+            if (lastServicePeriod.get("PAY_AMOUNT") != null && lastServicePeriod.getDouble("PAY_AMOUNT") != 0) {
+                adjBO.set("PURCHASE_START_DATE", PERIOD_END_DATE.plusDays(1));
+            } else {
+                adjBO.set("PURCHASE_START_DATE", PERIOD_BEGIN_DATE);
+            }
+        }
+        adjBO.set("REMARK", "修改结束日期");
+        adjBO.set("PURCHASE_END_DATE", newEndDate);
+        SDK.getBOAPI().update("BO_EU_DNCTT_CONTRACT_SERVICE_PURCHASE_ADJUST", adjBO);
+        execServicePurchaseAdj(uc, adjBO.getId());
+        DBSql.update("update bo_eu_dnctt_contract_service set PURCHASE_END_DATE=? where ID=?", new Object[]{LocalDateYYYYMMDD(newEndDate), serviceId});
+
+        return "ok";
+    }
+
+
+    /**
+     * 执行服务调整--采购
+     * @param uc
+     * @param boId
+     * @return
+     */
+    public boolean execServicePurchaseAdj(UserContext uc, String boId) {
+        //调整 服务
+        BO contractService = SDK.getBOAPI().get("BO_EU_DNCTT_CONTRACT_SERVICE_PURCHASE_ADJUST", boId);
+
+
+        String PERIOD_TYPE = contractService.getString("PURCHASE_PERIOD_TYPE");
+
+        LocalDate EFFECTIVE_DATE = getLocalDate(contractService.get("PURCHASE_START_DATE"));//服务生效日期
+        LocalDate EFFECTIVE_END_DATE = getLocalDate(contractService.get("PURCHASE_END_DATE"));//服务结束日期
+
+        //合同服务
+        BO orgContractService = SDK.getBOAPI().get("BO_EU_DNCTT_CONTRACT_SERVICE", contractService.getString("CONTRACT_SERVICE_ID"));
+
+        //生效日期之前的一次调整
+        RowMap lastContractService = DBSql.getMap("select * from BO_EU_DNCTT_CONTRACT_SERVICE_PURCHASE_ADJUST where  CONTRACT_SERVICE_ID=? and PURCHASE_START_DATE <=? and IS_EFFECTIVE='已执行' order by PURCHASE_START_DATE desc", new Object[]{contractService.get("CONTRACT_SERVICE_ID"), LocalDateYYYYMMDD(EFFECTIVE_DATE)});
+
+        Connection conn = null;
+        try {
+            conn = DBSql.open();
+            conn.setAutoCommit(false);
+
+            //生效日期之后的服务周期删除
+            DBSql.update(conn, "DELETE FROM BO_EU_DNIVT_ORDER_PAYMENT_PLAN WHERE  CONTRACT_SERVICE_ID=? and PERIOD_BEGIN_DATE >=? and (PAY_AMOUNT=0 or PAY_AMOUNT is NULL)", new Object[]{contractService.get("CONTRACT_SERVICE_ID"), LocalDateYYYYMMDD(EFFECTIVE_DATE)});
+
+            String lastPeriodId = DBSql.getString(conn, "select ID from BO_EU_DNIVT_ORDER_PAYMENT_PLAN where CONTRACT_SERVICE_ID=? and PERIOD_END_DATE >=? order by PERIOD_BEGIN_DATE asc", new Object[]{contractService.get("CONTRACT_SERVICE_ID"), LocalDateYYYYMMDD(EFFECTIVE_DATE)});
+
+            BigDecimal SERVICE_UNIT_COST = null;
+            BigDecimal SERVICE_TOTAL_COST = null;
+
+            boolean teshuchuli = false;
+            String teshuchuliBeginDate = null;
+            BigDecimal COST_1STMONTH = null;
+            LocalDate START_DATE = EFFECTIVE_DATE;
+            if (StringUtils.isNotBlank(lastPeriodId)) {
+
+                //获取第一笔
+
+                //首月成本
+                if (PERIOD_TYPE.equals("4598") || PERIOD_TYPE.equals("4595") || PERIOD_TYPE.equals("4592")) {
+
+                } else {
+                    RowMap firstContractService = DBSql.getMap("select * from BO_EU_DNCTT_CONTRACT_SERVICE_PURCHASE_ADJUST where  CONTRACT_SERVICE_ID=?  and IS_EFFECTIVE='已执行' order by PURCHASE_START_DATE ASC", new Object[]{contractService.get("CONTRACT_SERVICE_ID")});
+
+                    LocalDate firstEFFECTIVE_DATE = getLocalDate(firstContractService.get("PURCHASE_START_DATE"));
+
+                    if (firstEFFECTIVE_DATE.getYear() == EFFECTIVE_DATE.getYear() && firstEFFECTIVE_DATE.getMonth() == EFFECTIVE_DATE.getMonth()) {
+                        teshuchuli = true;
+                        teshuchuliBeginDate = LocalDateYYYYMMDD(EFFECTIVE_DATE);
+                        SERVICE_UNIT_COST = TypeUtil.convert(contractService.get("UNIT_COST_1STMONTH"), BigDecimal.class);
+                        SERVICE_TOTAL_COST = multiply(SERVICE_UNIT_COST, contractService.get("QUANTITY"));
+
+                        BigDecimal ratio = new BigDecimal(EFFECTIVE_DATE.getDayOfMonth()).divide(new BigDecimal(EFFECTIVE_DATE.lengthOfMonth()), 10, BigDecimal.ROUND_HALF_UP);
+                        ratio = BigDecimal.ONE.subtract(ratio);
+
+                        COST_1STMONTH = SERVICE_TOTAL_COST.multiply(ratio);
+
+                        EFFECTIVE_DATE = EFFECTIVE_DATE.plusMonths(1).withDayOfMonth(1);//下个月1号
+                    }
+                }
+
+
+                // 首月单独计费
+                if (teshuchuli) {
+                    SERVICE_UNIT_COST = TypeUtil.convert(lastContractService.get("UNIT_COST_1STMONTH"), BigDecimal.class);
+                    SERVICE_TOTAL_COST = multiply(SERVICE_UNIT_COST, lastContractService.get("QUANTITY"));
+                } else {
+                    SERVICE_UNIT_COST = TypeUtil.convert(lastContractService.get("UNIT_COST"), BigDecimal.class);
+                    SERVICE_TOTAL_COST = multiply(SERVICE_UNIT_COST, lastContractService.get("QUANTITY"));
+                }
+
+
+                BO lastServicePeriod = SDK.getBOAPI().get("BO_EU_DNIVT_ORDER_PAYMENT_PLAN", lastPeriodId);
+
+                LocalDate last_period_begin_date = getLocalDate(lastServicePeriod.get("PERIOD_BEGIN_DATE"));
+
+                lastServicePeriod.set("PERIOD_END_DATE", EFFECTIVE_DATE.minusDays(1));
+
+                BigDecimal periodRate = getDateRate(last_period_begin_date, EFFECTIVE_DATE.minusDays(1), false);
+
+                lastServicePeriod.set("PLAN_AMOUNT", multiply(SERVICE_TOTAL_COST, periodRate));
+                lastServicePeriod.set("REMAIN_AMOUNT", lastServicePeriod.get("PLAN_AMOUNT"));
+
+                SDK.getBOAPI().update("BO_EU_DNIVT_ORDER_PAYMENT_PLAN", lastServicePeriod, conn);
+            }
+
+            //获取服务周期
+            List<PeriodCalculationUtil.Period> periodList = PeriodCalculationUtil.getPeriodListByConfig(PERIOD_TYPE, START_DATE, EFFECTIVE_DATE, EFFECTIVE_END_DATE, contractService.getString("PURCHASE_CALC_METHOD_1STPERIOD"), "4638", contractService.getString("MONTH_1STQUARTER"));
+
+            SERVICE_UNIT_COST = TypeUtil.convert(contractService.get("UNIT_COST"), BigDecimal.class);
+
+            SERVICE_TOTAL_COST = multiply(SERVICE_UNIT_COST, contractService.get("QUANTITY"));
+            RowMap costProduct = DBSql.getMap("select * from BO_EU_DNIVT_ORDER_PRODUCT where CONTRACT_SERVICE_ID=?", new Object[]{contractService.get("CONTRACT_SERVICE_ID")});
+
+            String orderId = costProduct.getString("ORDER_ID");
+            String CONTRACT_COST_ID = costProduct.getString("CONTRACT_COST_ID");
+            String VENDOR_ACCOUNT_ID = DBSql.getString("select VENDOR_ACCOUNT_ID from BO_EU_DNIVT_ORDER where ID=?", new Object[]{orderId});//供应商账户ID
+            if (periodList != null && periodList.size() > 0) {
+
+                int i = 0;
+                for (PeriodCalculationUtil.Period period : periodList) {
+                    i++;
+                    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("PERIOD_BEGIN_DATE", period.getPeriodBeginDateStr());
+                    paymentPlan.set("PERIOD_END_DATE", period.getPeriodEndDateStr());
+
+                    if (teshuchuli && i == 1) {
+                        paymentPlan.set("PLAN_AMOUNT", SERVICE_TOTAL_COST.multiply(period.getRate()).add(COST_1STMONTH));
+                        paymentPlan.set("PLAN_DATE", teshuchuliBeginDate);
+                        paymentPlan.set("PERIOD_BEGIN_DATE", teshuchuliBeginDate);
+                    } else {
+                        paymentPlan.set("PLAN_AMOUNT", SERVICE_TOTAL_COST.multiply(period.getRate()));
+                    }
+
+                    paymentPlan.set("REMAIN_AMOUNT", paymentPlan.get("PLAN_AMOUNT"));
+                    paymentPlan.set("CONTRACT_COST_ID", CONTRACT_COST_ID);
+                    paymentPlan.set("CONTRACT_SERVICE_ID", orgContractService.getId());
+                    paymentPlan.set("PAY_DESC", orgContractService.getString("NAME"));
+                    paymentPlan.set("ACCOUNT_PAYEE", VENDOR_ACCOUNT_ID);//收款单位
+                    SDK.getBOAPI().create("BO_EU_DNIVT_ORDER_PAYMENT_PLAN", paymentPlan, processInstance, uc, conn);
+
+                    System.out.println("==== 创建付款计划:" + paymentPlan.get("PLAN_DATE") + ",金额:" + paymentPlan.get("PLAN_AMOUNT") + " ====");
+                }
+            }
+
+            contractService.set("IS_EFFECTIVE", "已执行");
+            SDK.getBOAPI().update("BO_EU_DNCTT_CONTRACT_SERVICE_PURCHASE_ADJUST", contractService, conn);
+            DBSql.update(conn, "update BO_EU_DNCTT_CONTRACT_SERVICE_PURCHASE_ADJUST set IS_EFFECTIVE='作废' where CONTRACT_SERVICE_ID=? and PURCHASE_START_DATE >?", new Object[]{contractService.get("CONTRACT_SERVICE_ID"), LocalDateYYYYMMDD(EFFECTIVE_DATE)});
+
+            orgContractService.set("UNIT_COST", contractService.get("UNIT_COST"));
+            orgContractService.set("TOTAL_COST", contractService.get("TOTAL_COST"));
+            orgContractService.set("QUANTITY", contractService.get("QUANTITY"));
+            orgContractService.set("PURCHASE_CALC_METHOD_1STPERIOD", contractService.get("PURCHASE_CALC_METHOD_1STPERIOD"));
+            orgContractService.set("MONTH_1STQUARTER", contractService.get("MONTH_1STQUARTER"));
+            orgContractService.set("PURCHASE_PERIOD_TYPE", contractService.get("PURCHASE_PERIOD_TYPE"));
+            orgContractService.set("PURCHASE_END_DATE", contractService.get("PURCHASE_END_DATE"));
+
+            //如果合同服务上面的生效日期小于服务调整的生效日期,则将合同服务生效日期改为服务调整的生效日期
+            if (orgContractService.get("PURCHASE_START_DATE", LocalDate.class).compareTo(contractService.get("PURCHASE_START_DATE", LocalDate.class)) < 0)
+                orgContractService.set("PURCHASE_START_DATE", contractService.get("PURCHASE_START_DATE"));
+
+            SDK.getBOAPI().update("BO_EU_DNCTT_CONTRACT_SERVICE", orgContractService, conn);
+
+
+            conn.commit();
+        } catch (SQLException e) {
+
+            e.printStackTrace();
+            try {
+                conn.rollback();
+            } catch (SQLException e1) {
+                e1.printStackTrace();
+            }
+        } finally {
+            if (conn != null)
+                DBSql.close(conn);
+        }
+        return true;
+    }
+
+
+}

+ 89 - 5
com.awspaas.user.apps.donenow_ivt/src/com/awspaas/user/apps/donenow_ivt/controller/ivtOrderController.java

@@ -696,8 +696,9 @@ public class ivtOrderController {
             int validCount = 0;
 
             for (RowMap cost : costList) {
-                String account_id = cost.getString("ACCOUNT_ID");
+                // String account_id = cost.getString("ACCOUNT_ID");
 
+                String account_id = cost.getString("BILL_ACCOUNT_ID");//计费客户
                 String status_id = cost.getString("STATUS_ID");
 
                 /*待采购/待拣货*/
@@ -738,9 +739,10 @@ public class ivtOrderController {
                 if (StringUtils.isNotBlank(vendor_id)) {
                     VENDOR_ACCOUNT_ID.add(vendor_id);
                 }
+
                 ivtLogger.info("处理的vendor_id: " + vendor_id);
 
-                int purchase_quantity = cost.getInt("QUANTITY") - DBSql.getInt("select sum(QUANTITY) AS QU from BO_EU_DNCTT_CONTRACT_COST_PRODUCT where CONTRACT_COST_ID=? and CLOSED=0", new Object[]{cost.getString("ID")});
+                int purchase_quantity = cost.getInt("QUANTITY") - DBSql.getInt("SELECT sum(a.QUANTITY) AS QU  FROM BO_EU_DNCTT_CONTRACT_COST_PRODUCT a  LEFT JOIN BO_EU_DNIVT_ORDER_PRODUCT b ON a.ORDER_ID=b.ORDER_ID AND a.CONTRACT_COST_ID=b.CONTRACT_COST_ID WHERE  ((a.ORDER_ID is NULL OR a.ORDER_ID='') OR b.ORDER_ID IS NOT NULL) AND  a.CONTRACT_COST_ID=?  and a.CLOSED=0", new Object[]{cost.getString("ID")});
                 if (purchase_quantity <= 0) {
                     ivtLogger.info("采购数量<=0,跳过该记录,ID: " + cost.getString("ID"));
                     continue;
@@ -749,11 +751,13 @@ public class ivtOrderController {
                 validCount++;
             }
 
+
             if (validCount < 1) {
                 ivtLogger.info("没有可处理的采购订单记录");
                 return ResponseObject.newErrResponse("没有可处理的采购订单");
             }
 
+
             ProcessInstance processInstance;
             try {
                 processInstance = SDK.getProcessAPI().createProcessInstance("obj_795cb3601f3a4b919b5896cf5b076a3a", uc.getUID(), "采购订单");
@@ -781,7 +785,7 @@ public class ivtOrderController {
                 int purchaseQuantity = cost.getInt("PURCHASE_QUANTITY");
 
                 if (StringUtils.isBlank(unitCostStr) || StringUtils.isBlank(taxCategoryId) || purchaseQuantity <= 0) {
-                    System.err.println("无效计算参数:UNIT_COST=" + unitCostStr + ",TAX_CATEGORY_ID=" + taxCategoryId + ",PURCHASE_QUANTITY=" + purchaseQuantity);
+                    ivtLogger.info("无效计算参数:UNIT_COST=" + unitCostStr + ",TAX_CATEGORY_ID=" + taxCategoryId + ",PURCHASE_QUANTITY=" + purchaseQuantity);
                     throw new RuntimeException("计算不含税金额失败:参数无效");
                 }
 
@@ -795,7 +799,7 @@ public class ivtOrderController {
                 BigDecimal unitCostNotax = unitCost.divide(BigDecimal.ONE.add(taxRate), 2, RoundingMode.HALF_UP);
 
                 BigDecimal costTotalNotax = unitCostNotax.multiply(new BigDecimal(purchaseQuantity)).setScale(2, RoundingMode.HALF_UP);
-                purchaseOrderProduct.set("PURCHASE_ACCOUNT_ID", cost.getString("ACCOUNT_ID"));
+                purchaseOrderProduct.set("PURCHASE_ACCOUNT_ID", cost.getString("BILL_ACCOUNT_ID"));//使用计费客户
                 purchaseOrderProduct.set("NAME", cost.getString("NAME"));
                 purchaseOrderProduct.set("PRODUCT_ID", cost.getString("PRODUCT_ID"));
                 purchaseOrderProduct.set("QUANTITY", cost.getString("PURCHASE_QUANTITY"));
@@ -947,7 +951,7 @@ public class ivtOrderController {
      * @param orderId
      * @return
      */
-    @Mapping("com.awspaas.user.apps.donenow_ivt.createPaymentPlan")
+    @Mapping("com.awspaas.user.apps.donenow_ivt.ivt_createPaymentPlan")
     public ResponseObject createPaymentPlan(UserContext uc, String orderId) {
 
         //校验
@@ -970,10 +974,15 @@ public class ivtOrderController {
 
                         LocalDate PERIOD_BEGIN_DATE = service.get("PURCHASE_START_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);
 
+                         */
+                        LocalDate START_DATE = PERIOD_BEGIN_DATE;
+                        LocalDate PERIOD_END_DATE = service.get("PURCHASE_END_DATE", LocalDate.class);
+
                         //采购单开始日期
                         if (service.get("PURCHASE_START_DATE") != null) {
                             START_DATE = TypeUtil.convert(service.get("PURCHASE_START_DATE").toString().substring(0, 10), LocalDate.class);
@@ -1008,4 +1017,79 @@ public class ivtOrderController {
     }
 
 
+    /**
+     * 检查付款计划是否修改
+     * @param uc
+     * @param requestBindidId
+     * @return
+     */
+    @Mapping("com.awspaas.user.apps.donenow_ivt.checkPaymentPlans")
+    public ResponseObject checkPaymentPlans(UserContext uc, String requestBindidId) {
+
+        List<RowMap> list = DBSql.getMaps("select * from BO_EU_DNIVT_PAY_REQUEST_DETAIL where BINDID=?", new Object[]{requestBindidId});
+
+        if (list.isEmpty()) return ResponseObject.newOkResponse();
+
+        StringBuilder sb = new StringBuilder();
+        for (RowMap detail : list) {
+            String PAYMENT_PLAN_ID = detail.getString("PAYMENT_PLAN_ID");
+            BigDecimal PLAN_AMOUNT = TypeUtil.convert(detail.get("PLAN_AMOUNT"), BigDecimal.class);
+
+            RowMap plan = DBSql.getMap("select * from BO_EU_DNIVT_ORDER_PAYMENT_PLAN where ID=?", new Object[]{PAYMENT_PLAN_ID});
+
+            BigDecimal PLAN_AMOUNT0 = TypeUtil.convert(plan.get("PLAN_AMOUNT"), BigDecimal.class);
+
+            //比较是否相等
+            if (PLAN_AMOUNT.compareTo(PLAN_AMOUNT0) != 0) {
+                ivtLogger.info("付款计划已修改:" + plan.getString("PAY_DESC") + ":" + PLAN_AMOUNT0 + ":" + PLAN_AMOUNT);
+                sb.append(plan.getString("PAY_DESC")).append(":").append(PLAN_AMOUNT0).append(",");
+            }
+        }
+
+        if (sb.length() > 0) {
+            return ResponseObject.newOkResponse("付款计划已修改");
+        }
+
+        return ResponseObject.newOkResponse();
+    }
+
+
+    /**
+     * 同步付款计划金额
+     * @param uc
+     * @param requestBindidId
+     * @return
+     */
+    @Mapping("com.awspaas.user.apps.donenow_ivt.asnyPaymentPlans")
+    public ResponseObject asnyPaymentPlans(UserContext uc, String requestBindidId) {
+
+        List<RowMap> list = DBSql.getMaps("select * from BO_EU_DNIVT_PAY_REQUEST_DETAIL where BINDID=?", new Object[]{requestBindidId});
+
+        if (list.isEmpty())
+            return ResponseObject.newOkResponse();
+
+        for (RowMap detail : list) {
+            String PAYMENT_PLAN_ID = detail.getString("PAYMENT_PLAN_ID");
+            BigDecimal PLAN_AMOUNT = TypeUtil.convert(detail.get("PLAN_AMOUNT"), BigDecimal.class);
+
+            RowMap plan = DBSql.getMap("select * from BO_EU_DNIVT_ORDER_PAYMENT_PLAN where ID=?", new Object[]{PAYMENT_PLAN_ID});
+
+            BigDecimal PLAN_AMOUNT0 = TypeUtil.convert(plan.get("PLAN_AMOUNT"), BigDecimal.class);
+
+            //比较是否相等
+            if (PLAN_AMOUNT.compareTo(PLAN_AMOUNT0) != 0) {
+
+                BO detailBO = SDK.getBOAPI().get("BO_EU_DNIVT_PAY_REQUEST_DETAIL", detail.getString("ID"));
+
+                detailBO.set("PLAN_AMOUNT", PLAN_AMOUNT0);
+
+                SDK.getBOAPI().update("BO_EU_DNIVT_PAY_REQUEST_DETAIL", detailBO);
+
+            }
+        }
+
+        return ResponseObject.newOkResponse();
+    }
+
+
 }

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

@@ -3,7 +3,6 @@ package com.awspaas.user.apps.donenow_ivt.event;
 import com.actionsoft.bpms.bo.engine.BO;
 import com.actionsoft.bpms.bpmn.engine.core.delegate.ProcessExecutionContext;
 import com.actionsoft.bpms.bpmn.engine.listener.ExecuteListener;
-import com.actionsoft.bpms.commons.database.RowMap;
 import com.actionsoft.bpms.util.DBSql;
 import com.actionsoft.sdk.local.SDK;
 import com.actionsoft.sdk.local.api.Logger;
@@ -13,8 +12,6 @@ import java.time.LocalDate;
 import java.time.format.DateTimeFormatter;
 import java.util.List;
 
-import static com.awspaas.user.apps.donenow_ivt.utils.CityAbbreviationUtil.getCityAbbreviation;
-
 public class ivtOrderFormAfter extends ExecuteListener {
     private static final Logger logger = SDK.getLogAPI().getLogger(ivtOrderFormAfter.class);//记录日志
 
@@ -50,6 +47,11 @@ public class ivtOrderFormAfter extends ExecuteListener {
             SDK.getBOAPI().update("BO_EU_DNCTT_CONTRACT_COST_PRODUCT", costProduct);
         }
 
+        //删除多余的采购订单产品
+        List<String> costProductIds = DBSql.getList("SELECT a.ID FROM BO_EU_DNCTT_CONTRACT_COST_PRODUCT a  LEFT JOIN BO_EU_DNIVT_ORDER_PRODUCT b ON a.ORDER_ID=b.ORDER_ID AND a.CONTRACT_COST_ID=b.CONTRACT_COST_ID WHERE b.ID IS NULL AND a.ORDER_ID=?", String.class, new Object[]{orderBO.getId()});
+        for (String costProductId : costProductIds) {
+            SDK.getBOAPI().remove("BO_EU_DNCTT_CONTRACT_COST_PRODUCT", costProductId);
+        }
 
         //采购订单编号
         String purchaseOrderNo = orderBO.getString("PURCHASE_ORDER_NO");
@@ -61,10 +63,9 @@ public class ivtOrderFormAfter extends ExecuteListener {
             String varname = processExecutionContext.getUserContext().getCompanyModel().getId() + "_ivtorder_" + LocalDate.now().getYear();
             purchaseOrderNo = SDK.getRuleAPI().executeAtScript("@sequence(" + varname + ",5)");
 
-            String DISTRICT_ID = DBSql.getString("select DISTRICT_ID from BO_EU_DNCRM_ACCOUNT where ID=?", new Object[]{orderBO.getString("VENDOR_ACCOUNT_ID")});
-
             String cssx = "SH";//城市缩写
-
+            /*
+            String DISTRICT_ID = DBSql.getString("select DISTRICT_ID from BO_EU_DNCRM_ACCOUNT where ID=?", new Object[]{orderBO.getString("VENDOR_ACCOUNT_ID")});
             if (StringUtils.isNotBlank(DISTRICT_ID)) {
                 RowMap city = DBSql.getMap("SELECT EXTTEXT1,EXTTEXT2 FROM BO_ACT_DICT_KV_ITEM WHERE DICTKEY = 'GB.ADDR' AND ITEMNO= ?", new Object[]{DISTRICT_ID});
                 if (city != null) {
@@ -76,6 +77,7 @@ public class ivtOrderFormAfter extends ExecuteListener {
                     cssx = getCityAbbreviation(cssx);
                 }
             }
+            */
             purchaseOrderNo = "CHT-" + cssx + "-" + LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")) + "-" + purchaseOrderNo;
 
             orderBO.set("PURCHASE_ORDER_NO", purchaseOrderNo);

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

@@ -34,14 +34,14 @@ public class payRequestProcessAfterComplete extends ExecuteListener {
         if (details != null && details.size() > 0)
             for (BO detail : details) {
                 String PAYMENT_PLAN_ID = detail.getString("PAYMENT_PLAN_ID");
-                BigDecimal PLAN_AMOUNT = detail.get("PLAN_AMOUNT", BigDecimal.class);
+                BigDecimal AMOUNT = detail.get("AMOUNT", BigDecimal.class);//时间付款金额
 
                 BO paymentPlan = SDK.getBOAPI().get("BO_EU_DNIVT_ORDER_PAYMENT_PLAN", PAYMENT_PLAN_ID);
 
                 BigDecimal PLAN_AMOUNT_OLD = paymentPlan.get("PLAN_AMOUNT", BigDecimal.class);
-                BigDecimal PAY_AMOUNT = paymentPlan.get("PAY_AMOUNT", BigDecimal.class);
+                BigDecimal PAY_AMOUNT = paymentPlan.get("PAY_AMOUNT", BigDecimal.class);//已付金额
 
-                PAY_AMOUNT = PAY_AMOUNT.add(PLAN_AMOUNT);
+                PAY_AMOUNT = PAY_AMOUNT.add(AMOUNT);
 
                 BigDecimal REMAIN_AMOUNT = PLAN_AMOUNT_OLD.subtract(PAY_AMOUNT);
                 paymentPlan.set("REMAIN_AMOUNT", REMAIN_AMOUNT);

+ 144 - 145
com.awspaas.user.apps.donenow_ivt/src/com/awspaas/user/apps/donenow_ivt/service/PaymentPlanService.java

@@ -4,7 +4,6 @@ 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;
@@ -13,6 +12,8 @@ import org.apache.commons.lang3.StringUtils;
 
 import java.math.BigDecimal;
 import java.math.RoundingMode;
+import java.sql.Connection;
+import java.sql.SQLException;
 import java.time.LocalDate;
 import java.time.Month;
 import java.time.format.DateTimeFormatter;
@@ -57,179 +58,177 @@ public class PaymentPlanService {
         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;
-
-                    logger.info("生成付款计划SERVICE_ID--" + SERVICE_ID);
-                    BO service = SDK.getBOAPI().get("BO_EU_DNCTT_CONTRACT_SERVICE", SERVICE_ID);
-                    String RULE_CATE = service.getString("PURCHASE_PERIOD_TYPE");//采购周期
-                    LocalDate PERIOD_BEGIN_DATE = service.get("PURCHASE_START_DATE", LocalDate.class);
-                    BigDecimal TOTAL_COST = toBigDecimal(service.get("TOTAL_COST"));//周期成本
-                    if (RULE_CATE.equals("609")) {   //一次性付费
-
-                        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_BEGIN_DATE);
-                        paymentPlan.set("PLAN_AMOUNT", TOTAL_COST);
-                        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);
-                        continue;
-                    }
+        Connection conn = null;
+        try {
+            conn = DBSql.open();
+            conn.setAutoCommit(false);
+
+            int total = 0;
+            boolean isOnlyOne = true;
+            for (BO orderProduct : orderProducts) {
+                if (StringUtils.isNotBlank(orderProduct.getString("CONTRACT_COST_ID"))) {
+                    String SERVICE_ID = DBSql.getString(conn, "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(conn, "SELECT COUNT(1) CNT FROM BO_EU_DNCTT_CONTRACT_SERVICE_PURCHASE_ADJUST WHERE CONTRACT_SERVICE_ID=? ", new Object[]{SERVICE_ID}) > 0) {
+                            continue;
+                        }
+
+                        logger.info("生成付款计划SERVICE_ID--" + SERVICE_ID);
+                        BO service = SDK.getBOAPI().get("BO_EU_DNCTT_CONTRACT_SERVICE", SERVICE_ID);
+                        String RULE_CATE = service.getString("PURCHASE_PERIOD_TYPE");//采购周期
+                        LocalDate PERIOD_BEGIN_DATE = service.get("PURCHASE_START_DATE", LocalDate.class);
+                        BigDecimal TOTAL_COST = toBigDecimal(service.get("TOTAL_COST"));//周期成本
+                        if (RULE_CATE.equals("609")) {   //一次性付费
+
+                            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_BEGIN_DATE);
+                            paymentPlan.set("PLAN_AMOUNT", TOTAL_COST);
+                            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, conn);
+                            continue;
+                        }
+
+                        // 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 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);
 
-                    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);
+                        LocalDate START_DATE = PERIOD_BEGIN_DATE;
+                        LocalDate PERIOD_END_DATE = service.get("PURCHASE_END_DATE", LocalDate.class);//新增采购结束时间
 
-                    //采购单开始日期
+                        //采购单开始日期
+                    /*
                     if (service.get("PURCHASE_START_DATE") != null) {
                         START_DATE = TypeUtil.convert(service.get("PURCHASE_START_DATE").toString().substring(0, 10), LocalDate.class);
                     }
+                     */
 
+                        String PURCHASE_CALC_METHOD_1STPERIOD = service.getString("PURCHASE_CALC_METHOD_1STPERIOD");
 
-                    String PURCHASE_CALC_METHOD_1STPERIOD = service.getString("PURCHASE_CALC_METHOD_1STPERIOD");
-
-                    if (StringUtils.isBlank(RULE_CATE) || StringUtils.isBlank(PURCHASE_CALC_METHOD_1STPERIOD)) {
-                        continue;
-                    }
-
-                    if (PERIOD_BEGIN_DATE == null || PERIOD_END_DATE == null || PERIOD_BEGIN_DATE.isAfter(PERIOD_END_DATE)) {
-                        continue;
-                    }
+                        if (StringUtils.isBlank(RULE_CATE) || StringUtils.isBlank(PURCHASE_CALC_METHOD_1STPERIOD)) {
+                            continue;
+                        }
 
+                        if (PERIOD_BEGIN_DATE == null || PERIOD_END_DATE == null || PERIOD_BEGIN_DATE.isAfter(PERIOD_END_DATE)) {
+                            continue;
+                        }
 
-                    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});
+                        if (DBSql.getInt(conn, "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;
+                        }
 
-                    List<PeriodCalculationUtil.Period> periods = PeriodCalculationUtil.getPeriodListByConfig(RULE_CATE, PERIOD_BEGIN_DATE, START_DATE, PERIOD_END_DATE, PURCHASE_CALC_METHOD_1STPERIOD, service.getString("CALC_METHOD_1STYEAR"), service.getString("MONTH_1STQUARTER"));
+                        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(conn, sql, new Object[]{orderId, orderProduct.getString("CONTRACT_COST_ID"), SERVICE_ID});
 
-                    if (periods.isEmpty())
-                        continue;
+                        BigDecimal UNIT_COST_1STMONTH = BigDecimal.ZERO;
+                        String firstPeriodBeginDate = null;
 
-                    //2025年11月5日
-                    /*
-                    BigDecimal COST_TOTAL = orderProduct.get("COST_TOTAL", BigDecimal.class);//总金额
-                    BigDecimal RATE_TOTAL = periods.stream().map(period -> period.getRate()).reduce(BigDecimal.ZERO, BigDecimal::add);
-                     */
+                        //首月单独计算
+                        if (RULE_CATE.equals("4598") || RULE_CATE.equals("4595") || RULE_CATE.equals("4592")) {
+                            //签约之日开始算周期,则不需要
 
-                    BigDecimal UNIT_COST_1STMONTH = BigDecimal.ZERO;
-                    //首月总价需要单独计算   613	按年支付	4591	开通日期所在月
-                    if (periods.size() > 0 && service.get("PURCHASE_CALC_METHOD_1STPERIOD").equals("4591")) {
-                        PeriodCalculationUtil.Period period = periods.get(0);
-                        if (period.getRate().compareTo(BigDecimal.ONE) < 0) {
+                        } else {
                             UNIT_COST_1STMONTH = toBigDecimal(service.get("UNIT_COST_1STMONTH"));
-                            UNIT_COST_1STMONTH = period.getRate().multiply(BigDecimal.valueOf(12)).multiply(UNIT_COST_1STMONTH);
-                            //RATE_TOTAL = RATE_TOTAL.subtract(period.getRate());//减去首月
-                            //COST_TOTAL = COST_TOTAL.subtract(UNIT_COST_1STMONTH);//减去首月
+                            BigDecimal ratio = new BigDecimal(PERIOD_BEGIN_DATE.getDayOfMonth()).divide(new BigDecimal(PERIOD_BEGIN_DATE.lengthOfMonth()), 10, BigDecimal.ROUND_HALF_UP);
+                            ratio = BigDecimal.ONE.subtract(ratio);
+                            UNIT_COST_1STMONTH = ratio.multiply(UNIT_COST_1STMONTH);
+                            firstPeriodBeginDate = PERIOD_BEGIN_DATE.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
+                            //下月一号
+                            PERIOD_BEGIN_DATE = PERIOD_BEGIN_DATE.plusMonths(1).withDayOfMonth(1);
                         }
-                    }
 
-                    // 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);
-
-
-                    int i = 0;
-                    for (PeriodCalculationUtil.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());
-
-                        //首月总价需要单独计算   613	按年支付	4591	开通日期所在月
-                        if (i == 1 && service.get("PURCHASE_CALC_METHOD_1STPERIOD").equals("4591")) {
-                            //firstRate<1
-                            if (period.getRate().compareTo(BigDecimal.ONE) < 0) {
-                                /*
-                                BigDecimal UNIT_COST_1STMONTH = toBigDecimal(service.get("UNIT_COST_1STMONTH"));
-                                UNIT_COST_1STMONTH = period.getRate().multiply(BigDecimal.valueOf(12)).multiply(UNIT_COST_1STMONTH);
-                                paymentPlan.set("PLAN_AMOUNT", period.getRate().multiply(UNIT_COST_1STMONTH));
-                                 */
-                                if (periods.size() == 1) {
-                                    paymentPlan.set("PLAN_AMOUNT", UNIT_COST_1STMONTH);
-                                } else {
-                                    continue;
-                                }
-                            } else {
-                                paymentPlan.set("PLAN_AMOUNT", TOTAL_COST.multiply(period.getRate()));
-                            }
-                        } else {
-                            if (i == 2 && UNIT_COST_1STMONTH.compareTo(BigDecimal.ZERO) > 0) {
+                        List<PeriodCalculationUtil.Period> periods = PeriodCalculationUtil.getPeriodListByConfig(RULE_CATE, START_DATE, PERIOD_BEGIN_DATE, PERIOD_END_DATE, PURCHASE_CALC_METHOD_1STPERIOD, service.getString("CALC_METHOD_1STYEAR"), service.getString("MONTH_1STQUARTER"));
+
+                        int i = 0;
+                        for (PeriodCalculationUtil.Period period : periods) {
+                            total++;
+                            i++;
+                            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("PERIOD_BEGIN_DATE", period.getPeriodBeginDateStr());
+                            paymentPlan.set("PERIOD_END_DATE", period.getPeriodEndDateStr());
+
+                            //第一条周期要加上首月成本
+                            if (i == 1 && UNIT_COST_1STMONTH.compareTo(BigDecimal.ZERO) > 0) {
                                 paymentPlan.set("PLAN_AMOUNT", TOTAL_COST.multiply(period.getRate()).add(UNIT_COST_1STMONTH));
+                                paymentPlan.set("PLAN_DATE", firstPeriodBeginDate);
+                                paymentPlan.set("PERIOD_BEGIN_DATE", firstPeriodBeginDate);
                             } else {
                                 paymentPlan.set("PLAN_AMOUNT", TOTAL_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);//收款单位
+                            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, conn);
 
-                        paymentPlan.set("PERIOD_BEGIN_DATE", period.getPeriodBeginDateStr());
-                        paymentPlan.set("PERIOD_END_DATE", period.getPeriodEndDateStr());
-
-                        SDK.getBOAPI().create("BO_EU_DNIVT_ORDER_PAYMENT_PLAN", paymentPlan, processInstance, uc);
-
-                        System.out.println("==== 创建付款计划:" + paymentPlan.get("PLAN_DATE") + ",金额:" + paymentPlan.get("PLAN_AMOUNT") + " ====");
+                            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") + " ====");
 
+            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(conn, 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, conn);
+                System.out.println("==== 创建付款计划:" + paymentPlan.get("PLAN_DATE") + ",金额:" + paymentPlan.get("PLAN_AMOUNT") + " ====");
+            }
+            logger.info("付款计划生成完成,生成付款计划数量:" + total);
+            conn.commit();
+        } catch (SQLException e) {
+            e.printStackTrace();
+            try {
+                conn.rollback();
+            } catch (SQLException ex) {
+                throw new RuntimeException(ex);
+            }
+        } finally {
+            if (conn != null) DBSql.close(conn);
         }
-        logger.info("付款计划生成完成,生成付款计划数量:" + total);
+
     }
 
     /**