Explorar o código

固话代缴费插入后更新周期表

HULEI hai 3 semanas
pai
achega
2edaebd659

+ 168 - 0
com.awspaas.user.apps.donenow_ctt/src/com/awspaas/user/apps/donenow_ctt/controller/contractApproveController.java

@@ -15,6 +15,7 @@ import com.awspaas.user.apps.donenow_ctt.service.contractService;
 import org.apache.commons.lang3.StringUtils;
 
 import java.math.BigDecimal;
+import java.math.RoundingMode;
 import java.sql.Connection;
 import java.sql.SQLException;
 import java.text.SimpleDateFormat;
@@ -2519,6 +2520,173 @@ public class contractApproveController {
         }
     }
 
+    @Mapping(value = "com.awspaas.user.apps.donenow_ctt.updatetax")
+    public ResponseObject updateContractPeriodByImportLogic(UserContext uc, String phone, String feeDate, String amount) {
+        // 1. 构建统一返回结果Map(与指定接口风格一致)
+        Map<String, Object> result = new HashMap<>();
+        result.put("result", "ok");
+        result.put("message", "处理完成");
+        result.put("updatedCount", 0);
+        result.put("periodBeginDate", "");
+        result.put("periodEndDate", "");
+
+        try {
+            // 2. 多参数校验(统一错误信息返回,与指定风格一致)
+            String errorMsg = "";
+            if (phone == null || phone.trim().isEmpty() || phone.trim().length() < 11) {
+                errorMsg = "手机号不能为空且格式正确(至少11位)";
+            } else if (feeDate == null || feeDate.trim().isEmpty()) {
+                errorMsg = "账期不能为空(格式:2025-03 或 202503)";
+            } else if (amount == null || amount.trim().isEmpty()) {
+                errorMsg = "金额不能为空";
+            }
+
+            if (!errorMsg.isEmpty()) {
+                result.put("message", errorMsg);
+                ResponseObject responseObject = ResponseObject.newOkResponse();
+                responseObject.setData(result);
+                return responseObject;
+            }
+
+            // 3. 参数格式化处理(去空格、金额类型转换,避免后续报错)
+            String phoneTrim = phone.trim();
+            String feeDateTrim = feeDate.trim();
+            BigDecimal totalAmount;
+
+            // 金额转换为BigDecimal,保留4位小数(兼容财务格式,与指定风格一致)
+            try {
+                totalAmount = new BigDecimal(amount.trim()).setScale(4, RoundingMode.HALF_UP);
+            } catch (NumberFormatException e) {
+                result.put("message", "金额格式错误(请输入数字,如100或100.50)");
+                ResponseObject responseObject = ResponseObject.newOkResponse();
+                responseObject.setData(result);
+                return responseObject;
+            }
+
+            // 4. 提取手机号后四位(用于匹配合同服务ID)
+            String phoneLast4 = phoneTrim.substring(phoneTrim.length() - 4);
+
+            // 5. 账期转换为周期起止日期(兼容两种格式,复用指定风格的转换逻辑)
+            Map<String, String> periodDateMap = convertFeeDateToPeriod(feeDateTrim);
+            if (periodDateMap == null) {
+                result.put("message", "账期格式错误(需为yyyy-MM或yyyyMM,如2025-03)");
+                ResponseObject responseObject = ResponseObject.newOkResponse();
+                responseObject.setData(result);
+                return responseObject;
+            }
+
+            String periodBeginDate = periodDateMap.get("begin");
+            String periodEndDate = periodDateMap.get("end");
+            result.put("periodBeginDate", periodBeginDate);
+            result.put("periodEndDate", periodEndDate);
+
+            // 6. 匹配合同服务ID(单条查询,与指定风格的SQL操作一致)
+            String contractId = matchContractIdByPhoneLast4(phoneLast4);
+            if (contractId == null || contractId.trim().isEmpty()) {
+                result.put("message", "未匹配到该手机号对应的合同服务ID");
+                ResponseObject responseObject = ResponseObject.newOkResponse();
+                responseObject.setData(result);
+                return responseObject;
+            }
+
+            // 7. 单条更新合同周期表(核心业务,与指定风格的SQL操作一致)
+            int updatedCount = updateSingleContractPeriod(contractId, totalAmount, periodBeginDate, periodEndDate);
+            result.put("updatedCount", updatedCount);
+
+            if (updatedCount > 0) {
+                result.put("message", "单条合同周期数据更新成功");
+            } else {
+                result.put("message", "单条合同周期数据更新失败,无对应周期记录");
+            }
+
+            // 8. 成功返回(与指定风格一致,封装ResponseObject)
+            ResponseObject responseObject = ResponseObject.newOkResponse();
+            responseObject.setData(result);
+            return responseObject;
+        } catch (Exception e) {
+            // 9. 异常处理(与指定风格一致,打印堆栈+统一返回错误信息)
+            e.printStackTrace();
+            result.put("result", "error");
+            result.put("message", "更新失败:" + e.getMessage());
+            result.put("updatedCount", 0);
+            ResponseObject responseObject = ResponseObject.newOkResponse();
+            responseObject.setData(result);
+            return responseObject;
+        }
+    }
+
+    // ====================== 工具方法(完全匹配指定接口风格,无全局常量,无报错) =======================
+    /**
+     * 账期转换(兼容2025-03 和 202503格式,与指定风格一致)
+     */
+    private Map<String, String> convertFeeDateToPeriod(String feeDate) {
+        try {
+            // 严格解析,避免无效日期,与指定风格一致
+            SimpleDateFormat sdfInput = feeDate.contains("-") ?
+                    new SimpleDateFormat("yyyy-MM") : new SimpleDateFormat("yyyyMM");
+            sdfInput.setLenient(false);
+            Date feeDateObj = sdfInput.parse(feeDate);
+
+            Calendar cal = Calendar.getInstance();
+            cal.setTime(feeDateObj);
+            SimpleDateFormat sdfOutput = new SimpleDateFormat("yyyy-MM-dd");
+
+            // 当月1日
+            cal.set(Calendar.DAY_OF_MONTH, 1);
+            String periodBeginDate = sdfOutput.format(cal.getTime());
+
+            // 当月最后1日
+            cal.set(Calendar.DAY_OF_MONTH, cal.getActualMaximum(Calendar.DAY_OF_MONTH));
+            String periodEndDate = sdfOutput.format(cal.getTime());
+
+            // 封装返回结果
+            Map<String, String> periodMap = new HashMap<>();
+            periodMap.put("begin", periodBeginDate);
+            periodMap.put("end", periodEndDate);
+            return periodMap;
+        } catch (ParseException e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    /**
+     * 单条匹配合同服务ID(通过手机号后四位,与指定风格的SQL操作一致)
+     */
+    private String matchContractIdByPhoneLast4(String phoneLast4) {
+        String sql = "SELECT CONTRACT_SERVICE_ID " +
+                " FROM BO_EU_DNCRM_INSTALLED_PRODUCT " +
+                " WHERE RIGHT(REFERENCE_NUMBER,4) = ?";
+        List<RowMap> contractList = DBSql.getMaps(sql, new Object[]{phoneLast4});
+        if (contractList != null && !contractList.isEmpty()) {
+            return Objects.toString(contractList.get(0).get("CONTRACT_SERVICE_ID"), "").trim();
+        }
+        return "";
+    }
+
+    /**
+     * 单条更新合同周期表(精准更新,与指定风格的SQL操作一致,无批量逻辑)
+     */
+    private int updateSingleContractPeriod(String contractId, BigDecimal amount, String periodBeginDate, String periodEndDate) {
+        if (contractId.isEmpty() || amount.compareTo(BigDecimal.ZERO) <= 0 || periodBeginDate.isEmpty() || periodEndDate.isEmpty()) {
+            return 0;
+        }
+
+        try {
+            String sql = "UPDATE BO_EU_DNCTT_CONTRACT_SERVICE_PERIOD SET " +
+                    "PERIOD_PRICE = ? " +
+                    "WHERE CONTRACT_SERVICE_ID = ? " +
+                    "AND PERIOD_BEGIN_DATE >= ? " +
+                    "AND PERIOD_END_DATE <= ?";
+
+            Object[] params = new Object[]{amount, contractId, periodBeginDate, periodEndDate};
+            return DBSql.update(sql, params);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return 0;
+        }
+    }
+
     @Mapping(value = "com.awspaas.user.apps.donenow_ctt.insertPumaDataByQuarter")
     public ResponseObject insertPumaDataByQuarter(UserContext uc) {
         try {

+ 108 - 70
com.awspaas.user.apps.donenow_ctt/src/com/awspaas/user/apps/donenow_ctt/event/DataWindowImportAfterEvent.java

@@ -1,3 +1,5 @@
+package com.awspaas.user.apps.donenow_ctt.event;
+
 import com.actionsoft.bpms.dw.exec.event.ideimport.DataWindowAfterImport;
 import com.actionsoft.bpms.dw.exec.imp.model.ImportModel;
 import com.actionsoft.bpms.server.UserContext;
@@ -13,81 +15,90 @@ import java.time.format.DateTimeFormatter;
 import java.time.format.DateTimeParseException;
 import java.util.*;
 
+/**
+ * 数据导入后事件处理类(全数据库驱动,精确到天,4位小数,兼容DATETIME时间戳)
+ * 功能:查询当天代缴费数据,匹配合同ID,更新对应账期的合同周期金额
+ */
 public class DataWindowImportAfterEvent extends DataWindowAfterImport {
     // ====================== 全局静态常量(统一配置,方便维护) =======================
     // 日期格式化常量:核心精确到天,兼容账期转换
     private static final DateTimeFormatter FORMATTER_DATE = DateTimeFormatter.ofPattern("yyyy-MM-dd"); // 当前时间(精确到天)
-    private static final DateTimeFormatter FORMATTER_YEAR_MONTH_DASH = DateTimeFormatter.ofPattern("yyyy-MM"); // 账期格式1
-    private static final DateTimeFormatter FORMATTER_YEAR_MONTH_NO_DASH = DateTimeFormatter.ofPattern("yyyyMM"); // 账期格式2
-    private static final DateTimeFormatter FORMATTER_YEAR_MONTH_DAY = DateTimeFormatter.ofPattern("yyyy-MM-dd"); // 周期起止日期
+    private static final DateTimeFormatter FORMATTER_YEAR_MONTH_DASH = DateTimeFormatter.ofPattern("yyyy-MM"); // 账期格式1(带横杠)
+    private static final DateTimeFormatter FORMATTER_YEAR_MONTH_NO_DASH = DateTimeFormatter.ofPattern("yyyyMM"); // 账期格式2(无横杠)
+    private static final DateTimeFormatter FORMATTER_YEAR_MONTH_DAY = DateTimeFormatter.ofPattern("yyyy-MM-dd"); // 周期起止日期(纯日期)
 
-    // 数据库表名常量(对应你的业务表)
+    // 数据库表名常量(对应业务表,需与实际数据库表结构一致
     private static final String TABLE_INSTALLED_PRODUCT = "BO_EU_DNCRM_INSTALLED_PRODUCT"; // 已安装产品表(匹配合同ID)
     private static final String TABLE_CONTRACT_PERIOD = "BO_EU_DNCTT_CONTRACT_SERVICE_PERIOD"; // 合同周期表(最终更新表)
-    private static final String TABLE_PROXY_PAY = "BO_EU_DNCTT_PROXY_PAY"; // 代缴费表(核心数据来源手机号/账期/金额)
+    private static final String TABLE_PROXY_PAY = "BO_EU_DNCTT_PROXY_PAY"; // 代缴费表(核心数据来源手机号/账期/金额)
 
-    // 数据库字段名常量(与表结构严格对应)
-    private static final String FIELD_CONTRACT_SERVICE_ID = "CONTRACT_SERVICE_ID"; // 合同服务ID
-    private static final String FIELD_PERIOD_PRICE = "PERIOD_PRICE"; // 周期金额(待更新)
+    // 数据库字段名常量(与表结构严格对应,大小写需匹配数据库
+    private static final String FIELD_CONTRACT_SERVICE_ID = "CONTRACT_SERVICE_ID"; // 合同服务ID(唯一标识)
+    private static final String FIELD_PERIOD_PRICE = "PERIOD_PRICE"; // 周期金额(待更新字段
     private static final String FIELD_REFERENCE_NUMBER = "REFERENCE_NUMBER"; // 参考编号(提取手机号后四位)
-    private static final String FIELD_EXTENDED_PRICE = "EXTENDED_PRICE"; // 含税总金额(数据库金额来源)
-    private static final String FIELD_CREATE_DATE = "CREATE_DATE"; // 创建时间(查询条件)
-    private static final String FIELD_PHONE = "PHONE"; // 完整手机号
-    private static final String FIELD_FEE_DATE = "FEE_DATE"; // 账期
+    private static final String FIELD_EXTENDED_PRICE = "EXTENDED_PRICE"; // 含税总金额(数据来源:代缴费表
+    private static final String FIELD_CREATE_DATE = "CREATEDATE"; // 创建时间(查询条件:代缴费表
+    private static final String FIELD_PHONE = "PHONE"; // 完整手机号(代缴费表)
+    private static final String FIELD_FEE_DATE = "FEE_DATE"; // 账期(代缴费表)
 
-    // 提示信息常量(统一日志输出)
+    // 提示信息常量(统一日志输出,便于问题排查
     private static final String MSG_NO_CURRENT_DATA = "未查询到当天(" + LocalDate.now().format(FORMATTER_DATE) + ")的有效代缴费数据";
     private static final String MSG_NO_CONTRACT_ID = "未匹配到对应的合同服务ID";
-    private static final String MSG_FEE_DATE_FORMAT_ERROR = "账期格式错误(需为yyyy-MM或yyyyMM)";
+    private static final String MSG_FEE_DATE_FORMAT_ERROR = "账期格式错误(需为yyyy-MM或yyyyMM格式)";
     private static final String MSG_NO_VALID_DATA = "无有效数据可进行后续处理";
     private static final String MSG_PROCESS_COMPLETE = "处理完成:更新周期表%d条数据";
 
-    // 简单日志方法(无SDK依赖,控制台输出)
+    // ====================== 构造方法(平台要求:必须存在无参构造器) =======================
+    public DataWindowImportAfterEvent() {
+        super();
+    }
+
+    // ====================== 简单日志方法(无SDK依赖,控制台输出详细信息) =======================
     private static void log(String msg) {
         System.out.println("[DataWindowImportAfterEvent] " + msg);
     }
 
-    // ====================== 核心业务方法(重写平台导入事件,全数据库驱动) =======================
+    // ====================== 核心业务方法(重写平台导入事件,全数据库驱动执行) =======================
     @Override
     public void excute(UserContext userContext, String processDefId, String formDefId, List<ImportModel> importModels, String type, Map<String, Object> extendParams) {
         // 1. 获取当前系统日期(精确到天),作为数据库查询核心条件
         String currentDate = LocalDate.now().format(FORMATTER_DATE);
-        log("===== 开始处理,当前查询日期(精确到天):" + currentDate + " =====");
+        log("===== 业务处理开始,当前查询日期(精确到天):" + currentDate + " =====");
 
         // 2. 从代缴费表查询当天所有有效数据(手机号、账期、金额)
         List<RowMap> proxyPayList = getProxyPayDataByCurrentDate(currentDate);
         if (proxyPayList == null || proxyPayList.isEmpty()) {
             log(MSG_NO_CURRENT_DATA);
-            log("===== 处理结束,无有效数据 =====");
+            log("===== 业务处理结束,无有效代缴费数据 =====");
             return;
         }
         log("查询到当天代缴费记录共:" + proxyPayList.size() + " 条");
 
-        // 3. 整理数据库返回数据(格式化、去重、过滤无效数据)
-        Map<String, BigDecimal> phoneAmountMap = new HashMap<>(); // 手机号后四位 → 含税金额
+        // 3. 整理数据库返回数据(格式化、去重、过滤无效数据,4位小数
+        Map<String, BigDecimal> phoneAmountMap = new HashMap<>(); // 手机号后四位 → 4位小数含税金额
         Map<String, String> phoneFeeDateMap = new HashMap<>();    // 手机号后四位 → 账期
-        Set<String> phoneLast4Set = new HashSet<>();               // 去重手机号后四位
+        Set<String> phoneLast4Set = new HashSet<>();               // 去重手机号后四位集合
 
         for (RowMap row : proxyPayList) {
             // 3.1 提取并校验完整手机号(截取后四位)
             String fullPhone = Objects.toString(row.get(FIELD_PHONE), "").trim();
             if (StringUtils.isBlank(fullPhone) || fullPhone.length() < 4) {
-                log("手机号无效(为空或长度不足4位),跳过当前记录:" + fullPhone);
+                log("【数据过滤】手机号无效(为空或长度不足4位),跳过当前记录:" + fullPhone);
                 continue;
             }
-            String phoneLast4 = fullPhone.substring(fullPhone.length() - 4); // 截取后四位
+            String phoneLast4 = fullPhone.substring(fullPhone.length() - 4); // 截取手机号后四位
 
             // 3.2 提取并校验账期
             String feeDate = Objects.toString(row.get(FIELD_FEE_DATE), "").trim();
             if (StringUtils.isBlank(feeDate)) {
-                log("账期为空,跳过当前记录(手机号后四位:" + phoneLast4 + ")");
+                log("【数据过滤】账期为空,跳过当前记录(手机号后四位:" + phoneLast4 + ")");
                 continue;
             }
 
-            // 3.3 提取并格式化金额(兼容多类型,避免报错
+            // 3.3 提取并格式化金额(兼容多类型,保留4位小数,四舍五入
             BigDecimal amount = formatAmountFromRow(row);
             if (amount.compareTo(BigDecimal.ZERO) == 0) {
-                log("金额无效(为0或转换失败),跳过当前记录(手机号后四位:" + phoneLast4 + ")");
+                log("【数据过滤】金额无效(为0或转换失败),跳过当前记录(手机号后四位:" + phoneLast4 + ")");
                 continue;
             }
 
@@ -100,16 +111,16 @@ public class DataWindowImportAfterEvent extends DataWindowAfterImport {
         // 4. 校验整理后的数据是否有效
         if (phoneLast4Set.isEmpty() || phoneAmountMap.isEmpty()) {
             log(MSG_NO_VALID_DATA);
-            log("===== 处理结束,无有效数据 =====");
+            log("===== 业务处理结束,无有效整理数据 =====");
             return;
         }
         log("整理后有效数据共:" + phoneLast4Set.size() + " 条");
 
-        // 5. 手机号后四位匹配合同服务ID(建立映射关系)
+        // 5. 手机号后四位匹配合同服务ID(建立映射关系,批量查询提高效率
         Map<String, String> phoneContractMap = matchPhoneToContractId(new ArrayList<>(phoneLast4Set));
         if (phoneContractMap.isEmpty()) {
             log(MSG_NO_CONTRACT_ID);
-            log("===== 处理结束,无匹配合同 =====");
+            log("===== 业务处理结束,无匹配合同服务ID =====");
             return;
         }
         log("匹配到有效合同服务ID共:" + phoneContractMap.size() + " 个");
@@ -121,41 +132,44 @@ public class DataWindowImportAfterEvent extends DataWindowAfterImport {
         for (Map.Entry<String, String> entry : phoneContractMap.entrySet()) {
             String phoneLast4 = entry.getKey();
             String contractId = entry.getValue();
-            BigDecimal amount = phoneAmountMap.getOrDefault(phoneLast4, BigDecimal.ZERO).setScale(2, RoundingMode.HALF_UP);
+            // 金额保留4位小数,兜底格式化(防止数据异常)
+            BigDecimal amount = phoneAmountMap.getOrDefault(phoneLast4, BigDecimal.ZERO).setScale(4, RoundingMode.HALF_UP);
 
-            // 过滤无效金额
+            // 过滤无效金额(大于0才参与更新)
             if (amount.compareTo(BigDecimal.ZERO) > 0) {
                 contractAmountMap.put(contractId, amount);
             }
 
-            // 提取基准账期(仅取第一个有效值)
+            // 提取基准账期(仅取第一个有效值,用于统一转换周期
             if (StringUtils.isBlank(targetFeeDate)) {
                 targetFeeDate = phoneFeeDateMap.getOrDefault(phoneLast4, "");
             }
         }
 
-        // 7. 账期转换为当月起止日期(精准更新对应周期)
+        // 7. 账期转换为当月起止日期(精准更新对应周期,兼容两种账期格式
         Map<String, String> periodDateMap = convertFeeDateToPeriod(targetFeeDate);
         if (periodDateMap == null) {
             log(MSG_FEE_DATE_FORMAT_ERROR);
-            log("===== 处理结束,账期转换失败 =====");
+            log("===== 业务处理结束,账期转换失败 =====");
             return;
         }
         String periodBeginDate = periodDateMap.get("begin");
         String periodEndDate = periodDateMap.get("end");
-        log("账期转换完成,更新周期:" + periodBeginDate + " 至 " + periodEndDate);
+        log("账期转换完成,更新周期范围:" + periodBeginDate + " 至 " + periodEndDate);
 
-        // 8. 批量更新合同服务周期表(核心落地步骤)
+        // 8. 批量更新合同服务周期表(核心落地步骤,兼容DATETIME时间戳
         int updatedCount = batchUpdateContractPeriod(contractAmountMap, periodBeginDate, periodEndDate);
 
         // 9. 打印最终处理结果,流程闭环
-        log("===== 处理完成,共更新周期表 " + updatedCount + " 条数据 =====");
+        log("===== 业务处理完成,共更新合同周期表 " + updatedCount + " 条数据 =====");
     }
 
     // ====================== 工具方法(各司其职,解耦主流程,无报错兼容) =======================
     /**
      * 核心:以当前日期(精确到天)为条件,查询代缴费表当天所有有效数据
      * 忽略CREATE_DATE的时分秒,避免因时间戳差异导致数据遗漏
+     * @param currentDate 当前日期(格式:yyyy-MM-dd)
+     * @return 当天代缴费记录列表
      */
     private List<RowMap> getProxyPayDataByCurrentDate(String currentDate) {
         // SQL优化:使用DATE()函数提取日期部分,兼容DATETIME/DATE类型字段
@@ -163,12 +177,15 @@ public class DataWindowImportAfterEvent extends DataWindowAfterImport {
                 " FROM " + TABLE_PROXY_PAY +
                 " WHERE DATE(" + FIELD_CREATE_DATE + ") = ?"; // 忽略时分秒,精准匹配当天所有记录
 
-        // 执行查询,返回当天所有代缴费记录(平台通用方法,无报错)
+        // 执行查询,返回当天所有代缴费记录(平台通用方法,无报错兼容
         return DBSql.getMaps(sql, currentDate);
     }
 
     /**
      * 格式化从RowMap中提取的金额(兼容BigDecimal/Number/String类型,避免转换报错)
+     * 最终保留4位小数,四舍五入,符合高精度财务需求
+     * @param row 数据库查询结果行
+     * @return 格式化后的4位小数金额
      */
     private BigDecimal formatAmountFromRow(RowMap row) {
         Object amountObj = row.get(FIELD_EXTENDED_PRICE);
@@ -179,24 +196,26 @@ public class DataWindowImportAfterEvent extends DataWindowAfterImport {
                 if (amountObj instanceof BigDecimal) {
                     amount = (BigDecimal) amountObj;
                 } else if (amountObj instanceof Number) {
-                    // 兼容Integer/Double/Long等数值类型
+                    // 兼容Integer/Double/Long/Float所有数值类型
                     amount = BigDecimal.valueOf(((Number) amountObj).doubleValue());
                 } else {
-                    // 兼容字符串类型金额,去除空格后转换
+                    // 兼容字符串类型金额,去除首尾空格后转换
                     amount = new BigDecimal(amountObj.toString().trim());
                 }
             } catch (NumberFormatException e) {
-                log("金额转换失败,无效值:" + amountObj.toString());
+                log("【金额转换异常】无效金额值,转换失败:" + amountObj.toString());
                 amount = BigDecimal.ZERO;
             }
         }
 
-        // 格式化金额:保留2位小数,四舍五入(符合财务数据规范)
-        return amount.setScale(2, RoundingMode.HALF_UP);
+        // 格式化金额:保留4位小数,四舍五入(符合高精度财务数据规范)
+        return amount.setScale(4, RoundingMode.HALF_UP);
     }
 
     /**
-     * 匹配手机号后四位与合同服务ID(从已安装产品表查询,批量匹配提高效率)
+     * 匹配手机号后四位与合同服务ID(从已安装产品表批量查询,提高执行效率)
+     * @param phoneLast4List 手机号后四位列表
+     * @return 手机号后四位 → 合同服务ID 映射关系
      */
     private Map<String, String> matchPhoneToContractId(List<String> phoneLast4List) {
         Map<String, String> phoneContractMap = new HashMap<>();
@@ -205,31 +224,35 @@ public class DataWindowImportAfterEvent extends DataWindowAfterImport {
         }
 
         try {
-            // 动态拼接IN条件SQL,批量查询(避免循环单条查询,提高效率
-            StringBuilder sql = new StringBuilder("SELECT RIGHT(" + FIELD_REFERENCE_NUMBER + ",4) AS REF_LAST4, " +
+            // 动态拼接IN条件SQL,批量查询(避免循环单条查询,提升性能
+            StringBuilder sqlBuilder = new StringBuilder("SELECT RIGHT(" + FIELD_REFERENCE_NUMBER + ",4) AS REF_LAST4, " +
                     FIELD_CONTRACT_SERVICE_ID + " FROM " + TABLE_INSTALLED_PRODUCT + " WHERE RIGHT(" +
                     FIELD_REFERENCE_NUMBER + ",4) IN (");
 
+            // 拼接IN条件占位符
             for (int i = 0; i < phoneLast4List.size(); i++) {
-                sql.append(i == 0 ? "?" : ",?");
+                if (i > 0) {
+                    sqlBuilder.append(",");
+                }
+                sqlBuilder.append("?");
             }
-            sql.append(")");
+            sqlBuilder.append(")");
 
             // 执行查询,封装映射关系
-            List<RowMap> contractList = DBSql.getMaps(sql.toString(), phoneLast4List.toArray());
+            List<RowMap> contractList = DBSql.getMaps(sqlBuilder.toString(), phoneLast4List.toArray());
             for (RowMap row : contractList) {
                 String refLast4 = row.getString("REF_LAST4");
-                refLast4 = refLast4 == null ? "" : refLast4.trim();
                 String contractId = row.getString(FIELD_CONTRACT_SERVICE_ID);
-                contractId = contractId == null ? "" : contractId.trim();
 
-                // 过滤无效数据,封装有效映射
+                // 过滤无效数据,封装有效映射(非空判断)
                 if (StringUtils.isNoneBlank(refLast4, contractId)) {
+                    refLast4 = refLast4.trim();
+                    contractId = contractId.trim();
                     phoneContractMap.put(refLast4, contractId);
                 }
             }
         } catch (Exception e) {
-            log("匹配手机号与合同ID异常:" + e.getMessage());
+            log("【合同ID匹配异常】异常信息:" + e.getMessage());
             e.printStackTrace();
         }
 
@@ -238,72 +261,87 @@ public class DataWindowImportAfterEvent extends DataWindowAfterImport {
 
     /**
      * 账期转换为当月起止日期(支持yyyy-MM和yyyyMM两种格式,兼容业务场景)
+     * @param feeDate 账期(格式:yyyy-MM 或 yyyyMM)
+     * @return 当月起止日期映射(begin:当月1号,end:当月最后一天)
      */
     private Map<String, String> convertFeeDateToPeriod(String feeDate) {
         if (StringUtils.isBlank(feeDate)) {
+            log("【账期转换异常】账期为空,无法转换");
             return null;
         }
 
         try {
-            // 解析账期为YearMonth对象,兼容两种格式
+            // 解析账期为YearMonth对象,兼容两种常见格式
             YearMonth feeYearMonth = feeDate.contains("-") ?
                     YearMonth.parse(feeDate, FORMATTER_YEAR_MONTH_DASH) :
                     YearMonth.parse(feeDate, FORMATTER_YEAR_MONTH_NO_DASH);
 
-            // 构建当月起止日期(1号至月末最后一天)
+            // 构建当月起止日期(1号至月末最后一天,格式:yyyy-MM-dd
             Map<String, String> periodMap = new HashMap<>(2);
             periodMap.put("begin", feeYearMonth.atDay(1).format(FORMATTER_YEAR_MONTH_DAY));
             periodMap.put("end", feeYearMonth.atEndOfMonth().format(FORMATTER_YEAR_MONTH_DAY));
 
             return periodMap;
         } catch (DateTimeParseException e) {
-            log("账期格式转换异常,无效账期:" + feeDate + ",异常信息:" + e.getMessage());
+            log("【账期转换异常】无效账期格式,无法解析:" + feeDate + ",异常信息:" + e.getMessage());
             e.printStackTrace();
             return null;
         }
     }
 
     /**
-     * 批量更新合同服务周期表(使用CASE WHEN语法,一条SQL完成所有更新,高效防注入)
+     * 批量更新合同服务周期表(使用CASE WHEN语法,一条SQL完成所有更新,高效防SQL注入)
+     * 兼容DATETIME类型时间戳(00:00:00),避免日期匹配失败
+     * @param contractAmountMap 合同ID → 4位小数金额 映射
+     * @param periodBeginDate 周期开始日期(格式:yyyy-MM-dd)
+     * @param periodEndDate 周期结束日期(格式:yyyy-MM-dd)
+     * @return 受影响的记录数
      */
     private int batchUpdateContractPeriod(Map<String, BigDecimal> contractAmountMap, String periodBeginDate, String periodEndDate) {
+        // 入参有效性校验
         if (contractAmountMap.isEmpty() || StringUtils.isAnyBlank(periodBeginDate, periodEndDate)) {
+            log("【批量更新异常】入参无效,无法执行更新");
             return 0;
         }
 
         try {
-            // 动态拼接批量更新SQL
-            StringBuilder sql = new StringBuilder("UPDATE " + TABLE_CONTRACT_PERIOD + " SET " +
+            // 动态拼接批量更新SQL(CASE WHEN语法,高效更新多条记录)
+            StringBuilder sqlBuilder = new StringBuilder("UPDATE " + TABLE_CONTRACT_PERIOD + " SET " +
                     FIELD_PERIOD_PRICE + " = CASE " + FIELD_CONTRACT_SERVICE_ID + " ");
-            List<Object> batchParams = new ArrayList<>();
-            List<String> contractIdList = new ArrayList<>();
 
-            // 拼接CASE WHEN条件(合同ID → 对应金额)
+            List<Object> batchParams = new ArrayList<>(); // SQL参数列表(防注入)
+            List<String> contractIdList = new ArrayList<>(); // 合同ID列表(用于WHERE条件)
+
+            // 拼接CASE WHEN条件(合同ID → 对应4位小数金额)
             for (Map.Entry<String, BigDecimal> entry : contractAmountMap.entrySet()) {
                 String contractId = entry.getKey();
                 BigDecimal amount = entry.getValue();
-                sql.append("WHEN ? THEN ? ");
+
+                sqlBuilder.append("WHEN ? THEN ? ");
                 batchParams.add(contractId);
                 batchParams.add(amount);
                 contractIdList.add(contractId);
             }
 
-            // 拼接WHERE条件(限定合同ID和周期日期范围,避免误改数据)
-            sql.append("END WHERE ").append(FIELD_CONTRACT_SERVICE_ID).append(" IN (");
+            // 拼接WHERE条件(限定合同ID和周期日期范围,避免误改数据,兼容DATETIME时间戳
+            sqlBuilder.append("END WHERE ").append(FIELD_CONTRACT_SERVICE_ID).append(" IN (");
             for (int i = 0; i < contractIdList.size(); i++) {
-                sql.append(i == 0 ? "?" : ",?");
+                if (i > 0) {
+                    sqlBuilder.append(",");
+                }
+                sqlBuilder.append("?");
             }
-            sql.append(") AND PERIOD_BEGIN_DATE >= ? AND PERIOD_END_DATE <= ?");
+            sqlBuilder.append(") AND DATE(PERIOD_BEGIN_DATE) >= ? AND DATE(PERIOD_END_DATE) <= ?");
 
-            // 追加WHERE条件参数
+            // 追加WHERE条件参数(合同ID列表 + 周期起止日期)
             batchParams.addAll(contractIdList);
             batchParams.add(periodBeginDate);
             batchParams.add(periodEndDate);
 
             // 执行批量更新,返回受影响行数
-            return DBSql.update(sql.toString(), batchParams.toArray());
+            return DBSql.update(sqlBuilder.toString(), batchParams.toArray());
         } catch (Exception e) {
-            log("批量更新周期表异常:" + e.getMessage());
+            log("批量更新异常】更新合同周期表失败,异常信息:" + e.getMessage());
             e.printStackTrace();
             return 0;
         }