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.math.RoundingMode;
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.*;

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);

        if (editBO.get("END_DATE") == null) {
            DBSql.update("UPDATE BO_EU_DNCTT_CONTRACT_SERVICE a JOIN BO_EU_DNCTT_CONTRACT b ON a.CONTRACT_ID=b.ID set a.END_DATE=b.END_DATE WHERE a.END_DATE IS NULL AND a.ID=?", new Object[]{serviceId});
            DBSql.update("UPDATE BO_EU_DNCTT_CONTRACT_SERVICE_SALE_ADJUST a JOIN BO_EU_DNCTT_CONTRACT b ON a.CONTRACT_ID=b.ID set a.END_DATE=b.END_DATE WHERE a.END_DATE IS NULL a.CONTRACT_SERVICE_ID=?", new Object[]{serviceId});
        }

        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");

        //一次性收费
        if (PERIOD_TYPE.equals("609")) {

            BO periodBO = SDK.getBOAPI().query("BO_EU_DNCTT_CONTRACT_SERVICE_PERIOD").addQuery("CONTRACT_SERVICE_ID =", orgContractService.getId()).detail();

            periodBO.set("PERIOD_PRICE", contractService.get("UNIT_PRICE"));
            periodBO.set("PARTYA_PERIOD_PRICE", contractService.get("TOTAL_PRICE"));
            periodBO.set("PERIOD_ADJUSTED_PRICE", contractService.get("QUANTITY"));
            SDK.getBOAPI().update("BO_EU_DNCTT_CONTRACT_SERVICE_PERIOD", periodBO);

            orgContractService.set("UNIT_PRICE", contractService.get("UNIT_PRICE"));
            orgContractService.set("TOTAL_PRICE", contractService.get("TOTAL_PRICE"));
            orgContractService.set("QUANTITY", contractService.get("QUANTITY"));
            SDK.getBOAPI().update("BO_EU_DNCTT_CONTRACT_SERVICE", orgContractService);

            DBSql.update("UPDATE bo_eu_dnctt_contract_service_period a SET a.PERIOD_COST =( SELECT SUM(b.PLAN_AMOUNT) FROM BO_EU_DNIVT_ORDER_PAYMENT_PLAN b WHERE a.CONTRACT_SERVICE_ID=? AND b.CONTRACT_SERVICE_ID = a.CONTRACT_SERVICE_ID) WHERE a.CONTRACT_SERVICE_ID=? AND EXISTS ( SELECT 1 FROM BO_EU_DNIVT_ORDER_PAYMENT_PLAN b JOIN bo_eu_dnctt_contract_service c ON b.CONTRACT_SERVICE_ID = c.ID WHERE b.CONTRACT_SERVICE_ID = a.CONTRACT_SERVICE_ID AND c.PERIOD_TYPE = 609 AND c.ID=?)", new Object[]{orgContractService.getId(), orgContractService.getId(), orgContractService.getId()});
            return true;
        }


        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;


            BigDecimal SERVICE_UNIT_COST = BigDecimal.ZERO;//服务单元成本
            BigDecimal SERVICE_TOTAL_COST = BigDecimal.ZERO;//服务总成本


            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"));

                //无需采购
                if (orgContractService.getString("NEED_PURCHASE").equals("1") == false) {
                    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_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"));

                lastServicePeriod.set("PERIOD_COST", multiply(SERVICE_TOTAL_COST, periodRate));

                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"));


            contractServiceLogger.info("服务周期个数-------" + periodList.size());
            contractServiceLogger.info(periodList.toString());

            SERVICE_UNIT_PRICE = TypeUtil.convert(contractService.get("UNIT_PRICE"), BigDecimal.class);

            SERVICE_TOTAL_PRICE = multiply(SERVICE_UNIT_PRICE, contractService.get("QUANTITY"));

            //无需采购
            if (orgContractService.getString("NEED_PURCHASE").equals("1") == false) {
                SERVICE_UNIT_COST = contractService.get("UNIT_COST", BigDecimal.class);//服务单元成本
                SERVICE_TOTAL_COST = multiply(SERVICE_UNIT_COST, 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) < 0) {
                            //合并
                            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("PERIOD_COST", period.getRate().multiply(SERVICE_TOTAL_COST));

                    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 = 1;
            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)));

            BigDecimal result = SERVICE_UNIT_PRICE.divide(BigDecimal.valueOf(periodMonths), 4, // 精度：保留2位小数
                    RoundingMode.HALF_UP // 舍入模式：四舍五入
            );
            orgContractService.set("SERVICE_UNIT_PRICE", result);

            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), 4, BigDecimal.ROUND_HALF_UP).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);
        }

        //分摊采购成本
        paySplitServiceMonth(uc, orgContractService.getId());
        return true;
    }

    /**
     *  服务调整--销售 修改结束时间
     * @param uc
     * @param serviceId
     * @param newEndDate
     * @return
     */
    public String editServiceSaleEndDate(UserContext uc, String serviceId, LocalDate newEndDate) {

        //一次性收费，无需修改
        if (DBSql.getString("select PERIOD_TYPE from BO_EU_DNCTT_CONTRACT_SERVICE where CONTRACT_SERVICE_ID=?", new Object[]{serviceId}).equals("609")) {
            return "无需修改";
        }

        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);
        if (PERIOD_END_DATE.equals(newEndDate)) return "无需修改";

        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 NOT NULL and CONTRACT_SERVICE_ID=? AND  PERIOD_END_DATE >=?", new Object[]{serviceId, LocalDateYYYYMMDD(newEndDate)});
        if (StringUtils.isBlank(EFFECTIVE_DATE)) return "已审批不能修改了";


        String bindId = editServiceSale(uc, serviceId, "修改结束日期");

        BO adjBO = SDK.getBOAPI().getByProcess("BO_EU_DNCTT_CONTRACT_SERVICE_SALE_ADJUST", bindId);

        if (PERIOD_END_DATE.isAfter(newEndDate)) {
            //缩短

            if (PERIOD_BEGIN_DATE.isBefore(newEndDate)) {

                adjBO.set("EFFECTIVE_DATE", PERIOD_BEGIN_DATE);

            } else {

                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 = null;
                if (StringUtils.isBlank(EFFECTIVE_DATE)) {
                    EFFECTIVE_DATE = DBSql.getString("SELECT max(PERIOD_END_DATE) as PERIOD_END_DATE FROM BO_EU_DNCTT_CONTRACT_SERVICE_PERIOD WHERE  CONTRACT_SERVICE_ID=? AND  PERIOD_BEGIN_DATE <=?", new Object[]{serviceId, LocalDateYYYYMMDD(newEndDate)});

                    EFFECTIVE_DATE1 = TypeUtil.convert(EFFECTIVE_DATE, LocalDate.class);
                    EFFECTIVE_DATE1 = EFFECTIVE_DATE1.plusDays(1);

                } else {
                    EFFECTIVE_DATE1 = TypeUtil.convert(EFFECTIVE_DATE, LocalDate.class);
                }


                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", "服务延期：" + LocalDateYYYYMMDD(PERIOD_END_DATE) + "->" + LocalDateYYYYMMDD(newEndDate));

        adjBO.set("END_DATE", newEndDate);
        SDK.getBOAPI().update("BO_EU_DNCTT_CONTRACT_SERVICE_SALE_ADJUST", adjBO);

        if (execServiceSaleAdj(uc, adjBO.getId()) == false) {
            DBSql.update("delete from BO_EU_DNCTT_CONTRACT_SERVICE_SALE_ADJUST where ID=? AND IS_EFFECTIVE<>'已执行'", new Object[]{adjBO.getId()});
        } else {
            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});//最后一笔服务周期

        //一次性收费，无需修改
        if (DBSql.getString("select PURCHASE_PERIOD_TYPE from BO_EU_DNCTT_CONTRACT_SERVICE where CONTRACT_SERVICE_ID=?", new Object[]{serviceId}).equals("609")) {
            return "无需修改";
        }

        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);

        if (PERIOD_END_DATE.equals(newEndDate)) return "无需修改";

        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)});

        if (StringUtils.isNotBlank(EFFECTIVE_DATE)) return "已审批不能修改了";


        String bindId = editServicePurchase(uc, serviceId, "修改结束日期");

        BO adjBO = SDK.getBOAPI().getByProcess("BO_EU_DNCTT_CONTRACT_SERVICE_PURCHASE_ADJUST", bindId);


        if (PERIOD_END_DATE.isAfter(newEndDate)) {
            //缩短
            if (PERIOD_BEGIN_DATE.isBefore(newEndDate)) {

                adjBO.set("PURCHASE_START_DATE", PERIOD_BEGIN_DATE);
            } else {

                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 = null;
                if (StringUtils.isBlank(EFFECTIVE_DATE)) {
                    EFFECTIVE_DATE = DBSql.getString("SELECT max(PERIOD_END_DATE) as PERIOD_END_DATE FROM BO_EU_DNIVT_ORDER_PAYMENT_PLAN WHERE  CONTRACT_SERVICE_ID=? AND  PERIOD_BEGIN_DATE <=?", new Object[]{serviceId, LocalDateYYYYMMDD(newEndDate)});

                    EFFECTIVE_DATE1 = TypeUtil.convert(EFFECTIVE_DATE, LocalDate.class);
                    EFFECTIVE_DATE1 = EFFECTIVE_DATE1.plusDays(1);

                } else {
                    EFFECTIVE_DATE1 = TypeUtil.convert(EFFECTIVE_DATE, LocalDate.class);
                }

                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", "服务延期：" + LocalDateYYYYMMDD(PERIOD_END_DATE) + "->" + LocalDateYYYYMMDD(newEndDate));
        adjBO.set("PURCHASE_END_DATE", newEndDate);
        SDK.getBOAPI().update("BO_EU_DNCTT_CONTRACT_SERVICE_PURCHASE_ADJUST", adjBO);

        if (execServicePurchaseAdj(uc, adjBO.getId(), null) == false) {
            DBSql.update("delete from BO_EU_DNCTT_CONTRACT_SERVICE_PURCHASE_ADJUST where ID=? AND IS_EFFECTIVE<>'已执行'", new Object[]{adjBO.getId()});
        } else {
            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
     * @param boName
     * @return
     */
    public boolean execServicePurchaseAdj(UserContext uc, String boId, String boName) {
        //调整 服务
        BO contractService = SDK.getBOAPI().get("BO_EU_DNCTT_CONTRACT_SERVICE_PURCHASE_ADJUST", boId);

        if (StringUtils.isNotBlank(boName) && !boName.equals("BO_EU_DNIVT_ORDER_PAYMENT_PLAN_MONTH")) {
            return false;
        }
        String PERIOD_TYPE = contractService.getString("PURCHASE_PERIOD_TYPE");
        String PURCHASE_CALC_METHOD_1STPERIOD = contractService.getString("PURCHASE_CALC_METHOD_1STPERIOD");

        int periodMonths;
        switch (contractService.getString("PURCHASE_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;
        }

        if (StringUtils.isBlank(boName)) {
            boName = "BO_EU_DNIVT_ORDER_PAYMENT_PLAN";
        } else {
            if (PERIOD_TYPE.equals("609") == false)
                PERIOD_TYPE = "610";//按月
        }

        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)});

        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

        Connection conn = null;
        try {
            conn = DBSql.open();
            conn.setAutoCommit(false);

            //生效日期之后的服务周期删除
            if (PERIOD_TYPE.equals("609")) {
                DBSql.update(conn, "DELETE FROM " + boName + " WHERE  CONTRACT_SERVICE_ID=? ", new Object[]{contractService.get("CONTRACT_SERVICE_ID")});
            } else {
                DBSql.update(conn, "DELETE FROM " + boName + " 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 " + boName + " 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 (PURCHASE_CALC_METHOD_1STPERIOD.equals("4598") || PURCHASE_CALC_METHOD_1STPERIOD.equals("4595") || PURCHASE_CALC_METHOD_1STPERIOD.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"));

                    //按月收费，且从1号开始
                    if (EFFECTIVE_DATE.getDayOfMonth() == 1 && PERIOD_TYPE.equals("610") && boName.equals("BO_EU_DNIVT_ORDER_PAYMENT_PLAN")) {

                        //下月一号
                        EFFECTIVE_DATE = EFFECTIVE_DATE.plusMonths(1).withDayOfMonth(1);//下个月1号
                        BO paymentPlan = new BO();
                        paymentPlan.set("ORDER_ID", orderId);
                        paymentPlan.set("PLAN_DATE", teshuchuliBeginDate);
                        paymentPlan.set("PERIOD_BEGIN_DATE", teshuchuliBeginDate);
                        paymentPlan.set("PERIOD_END_DATE", EFFECTIVE_DATE.minusDays(1).format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
                        paymentPlan.set("PLAN_AMOUNT", SERVICE_TOTAL_COST);
                        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);//收款单位
                        ProcessInstance processInstance = SDK.getProcessAPI().createProcessInstance("obj_5cb4ae4a42944fd0a9a284ff4c64c65d", uc.getUID(), "付款计划");
                        paymentPlan.setBindId(processInstance.getId());
                        SDK.getBOAPI().create("BO_EU_DNIVT_ORDER_PAYMENT_PLAN", paymentPlan, processInstance, uc, conn);
                        COST_1STMONTH = BigDecimal.ZERO;
                        teshuchuli = false;

                    } else {
                        BigDecimal ratio = new BigDecimal(EFFECTIVE_DATE.lengthOfMonth() - EFFECTIVE_DATE.getDayOfMonth() + 1).divide(new BigDecimal(EFFECTIVE_DATE.lengthOfMonth()), 10, BigDecimal.ROUND_HALF_UP);
                        COST_1STMONTH = SERVICE_TOTAL_COST.multiply(ratio);
                        EFFECTIVE_DATE = EFFECTIVE_DATE.plusMonths(1).withDayOfMonth(1);//下个月1号
                    }

                    //首月单独一条
                    if (boName.equals("BO_EU_DNIVT_ORDER_PAYMENT_PLAN_MONTH") && !PERIOD_TYPE.equals("609")) {
                        BO paymentPlan = new BO();
                        paymentPlan.set("ORDER_ID", orderId);
                        paymentPlan.set("PLAN_AMOUNT", COST_1STMONTH);
                        paymentPlan.set("PLAN_DATE", teshuchuliBeginDate);
                        paymentPlan.set("PERIOD_BEGIN_DATE", teshuchuliBeginDate);
                        paymentPlan.set("PERIOD_END_DATE", EFFECTIVE_DATE.minusDays(1).format(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
                        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().createDataBO(boName, paymentPlan, uc, conn);

                        COST_1STMONTH = BigDecimal.ZERO;
                        teshuchuli = false;
                    }

                }
            }

            if (StringUtils.isNotBlank(lastPeriodId)) {
                // 首月单独计费
                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);
                    //拆算成月成本
                    if (boName.equals("BO_EU_DNIVT_ORDER_PAYMENT_PLAN_MONTH")) {
                        SERVICE_UNIT_COST = SERVICE_UNIT_COST.divide(new BigDecimal(periodMonths), 10, BigDecimal.ROUND_HALF_UP);
                    }
                    SERVICE_TOTAL_COST = multiply(SERVICE_UNIT_COST, lastContractService.get("QUANTITY"));
                }

                BO lastServicePeriod = SDK.getBOAPI().get(boName, lastPeriodId);
                LocalDate last_period_begin_date = getLocalDate(lastServicePeriod.get("PERIOD_BEGIN_DATE"));
                BigDecimal periodRate = getDateRate(last_period_begin_date, EFFECTIVE_DATE.minusDays(1), false);
                if (periodRate.compareTo(BigDecimal.ZERO) > 0) {
                    lastServicePeriod.set("PERIOD_END_DATE", EFFECTIVE_DATE.minusDays(1));
                    lastServicePeriod.set("PLAN_AMOUNT", multiply(SERVICE_TOTAL_COST, periodRate));
                    lastServicePeriod.set("REMAIN_AMOUNT", lastServicePeriod.get("PLAN_AMOUNT"));
                    SDK.getBOAPI().update(boName, lastServicePeriod, conn);
                } else {
                    SDK.getBOAPI().remove(boName, lastPeriodId, 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);
            //拆算成月成本
            if (boName.equals("BO_EU_DNIVT_ORDER_PAYMENT_PLAN_MONTH")) {
                SERVICE_UNIT_COST = SERVICE_UNIT_COST.divide(new BigDecimal(periodMonths), 10, BigDecimal.ROUND_HALF_UP);
            }

            SERVICE_TOTAL_COST = multiply(SERVICE_UNIT_COST, contractService.get("QUANTITY"));

            if (periodList != null && periodList.size() > 0) {

                int i = 0;
                for (PeriodCalculationUtil.Period period : periodList) {
                    i++;
                    BO paymentPlan = new BO();
                    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);//收款单位

                    if (boName.equals("BO_EU_DNIVT_ORDER_PAYMENT_PLAN")) {
                        ProcessInstance processInstance = SDK.getProcessAPI().createProcessInstance("obj_5cb4ae4a42944fd0a9a284ff4c64c65d", uc.getUID(), "付款计划");
                        paymentPlan.setBindId(processInstance.getId());
                        SDK.getBOAPI().create(boName, paymentPlan, processInstance, uc, conn);
                    } else {
                        SDK.getBOAPI().createDataBO(boName, paymentPlan, uc, conn);
                    }

                    System.out.println("==== 创建付款计划：" + paymentPlan.get("PLAN_DATE") + "，金额：" + paymentPlan.get("PLAN_AMOUNT") + " ====");
                }
            }

            if (boName.equals("BO_EU_DNIVT_ORDER_PAYMENT_PLAN")) {

                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);
        }

        //生成每月的采购计划
        if (boName.equals("BO_EU_DNIVT_ORDER_PAYMENT_PLAN")) {
            execServicePurchaseAdj(uc, boId, "BO_EU_DNIVT_ORDER_PAYMENT_PLAN_MONTH");

            //分摊采购成本
            paySplitServiceMonth(uc, contractService.getString("CONTRACT_SERVICE_ID"));
        }

        return true;
    }


    /**
     * 将合同服务的采购成本按照服务周期进行分摊处理。
     * <p>
     * 该方法根据合同服务ID查询相关的付款计划和服务周期数据，
     * 并根据不同服务类型（如一次性收费或分期服务）将付款金额分摊至各个服务周期中。
     * 分摊结果会更新到服务周期表中的 PERIOD_COST 字段。
     *
     * @param uc 当前用户上下文信息，用于权限控制等用途（当前未使用）
     * @param contractServiceId 合同服务ID，作为主键用于查询相关数据
     */
    //合同服务采购成本平摊到服务周期上面
    public void paySplitServiceMonth(UserContext uc, String contractServiceId) {

        RowMap service = DBSql.getMap("select * from BO_EU_DNCTT_CONTRACT_SERVICE where ID=?", new Object[]{contractServiceId});

        // 查询与该合同服务关联的所有付款计划，并按开始时间排序
        List<RowMap> payPlanList = DBSql.getMaps("select * from BO_EU_DNIVT_ORDER_PAYMENT_PLAN_MONTH where CONTRACT_SERVICE_ID=? ORDER BY PERIOD_BEGIN_DATE", new Object[]{contractServiceId});

        if (payPlanList.isEmpty() || payPlanList.size() == 0) return;

        // 查询与该合同服务对应的服务周期记录，并按开始时间排序
        List<RowMap> contractServicePeriodList = DBSql.getMaps("select * from BO_EU_DNCTT_CONTRACT_SERVICE_PERIOD where CONTRACT_SERVICE_ID=? ORDER BY PERIOD_BEGIN_DATE", new Object[]{contractServiceId});

        if (contractServicePeriodList.isEmpty() || contractServicePeriodList.size() == 0) return;

        // 处理“一次性收费”类型的合同服务：所有付款计划总和直接赋给第一个服务周期的成本
        if (service.getString("PERIOD_TYPE").equals("609")) {
            BigDecimal SUM_PLAN_AMOUNT = BigDecimal.ZERO;
            for (RowMap payPlan : payPlanList) {

                SUM_PLAN_AMOUNT = SUM_PLAN_AMOUNT.add(TypeUtil.convert(payPlan.get("PLAN_AMOUNT"), BigDecimal.class));
            }

            DBSql.update("update BO_EU_DNCTT_CONTRACT_SERVICE_PERIOD set PERIOD_COST=? where ID=? ", new Object[]{SUM_PLAN_AMOUNT, contractServicePeriodList.get(0).getString("ID")});
            return;
        }

        LocalDate LAST_DATE = null;
        for (RowMap servicePeriod : contractServicePeriodList) {
            // 获取当前服务周期的结束日期
            LocalDate PERIOD_END_DATE = TypeUtil.convert(servicePeriod.get("PERIOD_END_DATE"), LocalDate.class);
            SDK.getLogAPI().consoleInfo("PERIOD_END_DATE：" + PERIOD_END_DATE.toString());

            BigDecimal SUM_PLAN_AMOUNT = BigDecimal.ZERO;

            for (RowMap payPlan : payPlanList) {
                LocalDate PAY_PERIOD_BEGIN_DATE = TypeUtil.convert(payPlan.get("PERIOD_BEGIN_DATE"), LocalDate.class);

                SDK.getLogAPI().consoleInfo("PAY_PERIOD_BEGIN_DATE：" + PAY_PERIOD_BEGIN_DATE.toString());

                // 跳过已处理过的付款计划（通过上一个周期末日期+1判断）
                if (LAST_DATE != null && PAY_PERIOD_BEGIN_DATE.isBefore(LAST_DATE)) {
                    continue;
                }

                // 若付款计划起始日在当前服务周期之后，则跳过
                if (PERIOD_END_DATE.isBefore(PAY_PERIOD_BEGIN_DATE)) {
                    continue;
                }

                SDK.getLogAPI().consoleInfo("PLAN_AMOUNT ： " + payPlan.getString("PLAN_AMOUNT"));

                // 累加符合时间段内的付款计划金额
                SUM_PLAN_AMOUNT = SUM_PLAN_AMOUNT.add(TypeUtil.convert(payPlan.get("PLAN_AMOUNT"), BigDecimal.class));

            }
            // 更新当前服务周期的成本字段
            DBSql.update("update BO_EU_DNCTT_CONTRACT_SERVICE_PERIOD set PERIOD_COST=? where ID=? ", new Object[]{SUM_PLAN_AMOUNT, servicePeriod.getString("ID")});

            SDK.getLogAPI().consoleInfo("服务周期：" + servicePeriod.getString("ID") + ":" + SUM_PLAN_AMOUNT);

            // 设置下一轮比较的时间起点为当前周期结束后一天
            LAST_DATE = PERIOD_END_DATE.plusDays(1);
        }

    }


}
