|
@@ -16,40 +16,50 @@ import java.time.format.DateTimeParseException;
|
|
|
import java.util.*;
|
|
import java.util.*;
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * 数据导入后事件处理类(全数据库驱动,精确到天,4位小数,兼容DATETIME时间戳)
|
|
|
|
|
- * 功能:查询当天代缴费数据,匹配合同ID,更新对应账期的合同周期金额
|
|
|
|
|
- * 金额计算逻辑:ISP_TOTAL + SERVICE_FEE
|
|
|
|
|
|
|
+ * 数据导入后事件处理类
|
|
|
|
|
+ * 核心逻辑:
|
|
|
|
|
+ * 1. 服务表主键为 `ID`
|
|
|
|
|
+ * 2. 日期匹配整个月份(DATE_FORMAT)
|
|
|
|
|
+ * 3. 付款计划表:PAY_AMOUNT = PLAN_AMOUNT,REMAIN_AMOUNT = 0
|
|
|
|
|
+ * 4. 服务周期表:PERIOD_COST = PERIOD_PRICE
|
|
|
*/
|
|
*/
|
|
|
public class DataWindowImportAfterEvent extends DataWindowAfterImport {
|
|
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 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 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_ISP_TOTAL = "ISP_TOTAL"; // ISP总金额
|
|
|
|
|
- private static final String FIELD_SERVICE_FEE = "SERVICE_FEE"; // 服务费
|
|
|
|
|
- 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 DateTimeFormatter FORMATTER_DATE = DateTimeFormatter.ofPattern("yyyy-MM-dd");
|
|
|
|
|
+ private static final DateTimeFormatter FORMATTER_YEAR_MONTH_DASH = DateTimeFormatter.ofPattern("yyyy-MM");
|
|
|
|
|
+ private static final DateTimeFormatter FORMATTER_YEAR_MONTH_NO_DASH = DateTimeFormatter.ofPattern("yyyyMM");
|
|
|
|
|
+
|
|
|
|
|
+ // 表名常量
|
|
|
|
|
+ private static final String TABLE_CONTRACT_SERVICE = "BO_EU_DNCTT_CONTRACT_SERVICE";
|
|
|
|
|
+ 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_PAYMENT_PLAN = "BO_EU_DNIVT_ORDER_PAYMENT_PLAN";
|
|
|
|
|
+
|
|
|
|
|
+ // 字段名常量
|
|
|
|
|
+ private static final String FIELD_SERVICE_PRIMARY_KEY = "ID"; // 服务表主键
|
|
|
|
|
+ private static final String FIELD_PERIOD_PRICE = "PERIOD_PRICE";
|
|
|
|
|
+ private static final String FIELD_PERIOD_COST = "PERIOD_COST"; // 新增:服务周期成本
|
|
|
|
|
+ private static final String FIELD_PERIOD_ADJUSTED_PRICE = "PERIOD_ADJUSTED_PRICE";
|
|
|
|
|
+ private static final String FIELD_SERVICE_NAME = "NAME";
|
|
|
|
|
+ private static final String FIELD_ISP_TOTAL = "ISP_TOTAL";
|
|
|
|
|
+ private static final String FIELD_TAX_DOLLARS = "TAX_DOLLARS";
|
|
|
|
|
+ private static final String FIELD_PLAN_DATE = "PLAN_DATE";
|
|
|
|
|
+ private static final String FIELD_PLAN_AMOUNT = "PLAN_AMOUNT";
|
|
|
|
|
+ private static final String FIELD_PAY_AMOUNT = "PAY_AMOUNT";
|
|
|
|
|
+ private static final String FIELD_REMAIN_AMOUNT = "REMAIN_AMOUNT";
|
|
|
|
|
+ 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 FIELD_PERIOD_BEGIN_DATE = "PERIOD_BEGIN_DATE";
|
|
|
|
|
+ private static final String FIELD_PERIOD_END_DATE = "PERIOD_END_DATE";
|
|
|
|
|
+ private static final String FIELD_PAY_PLAN_CONTRACT_ID = "CONTRACT_SERVICE_ID"; // 付款计划表关联字段
|
|
|
|
|
+
|
|
|
|
|
+ // 提示信息常量
|
|
|
private static final String MSG_NO_CURRENT_DATA = "未查询到当天(" + LocalDate.now().format(FORMATTER_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_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_NO_VALID_DATA = "无有效数据可进行后续处理";
|
|
|
- private static final String MSG_PROCESS_COMPLETE = "处理完成:更新周期表%d条数据";
|
|
|
|
|
|
|
|
|
|
- // 构造方法(平台要求:必须存在无参构造器)
|
|
|
|
|
public DataWindowImportAfterEvent() {
|
|
public DataWindowImportAfterEvent() {
|
|
|
super();
|
|
super();
|
|
|
}
|
|
}
|
|
@@ -60,171 +70,154 @@ public class DataWindowImportAfterEvent extends DataWindowAfterImport {
|
|
|
|
|
|
|
|
@Override
|
|
@Override
|
|
|
public void excute(UserContext userContext, String processDefId, String formDefId, List<ImportModel> importModels, String type, Map<String, Object> extendParams) {
|
|
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);
|
|
String currentDate = LocalDate.now().format(FORMATTER_DATE);
|
|
|
- log("===== 业务处理开始,当前查询日期(精确到天):" + currentDate + " =====");
|
|
|
|
|
|
|
+ log("===== 业务处理开始,当前查询日期:" + currentDate + " =====");
|
|
|
|
|
|
|
|
- // 2. 从代缴费表查询当天所有有效数据(手机号、账期、金额)
|
|
|
|
|
|
|
+ // 1. 查询当天的代缴费数据
|
|
|
List<RowMap> proxyPayList = getProxyPayDataByCurrentDate(currentDate);
|
|
List<RowMap> proxyPayList = getProxyPayDataByCurrentDate(currentDate);
|
|
|
if (proxyPayList == null || proxyPayList.isEmpty()) {
|
|
if (proxyPayList == null || proxyPayList.isEmpty()) {
|
|
|
log(MSG_NO_CURRENT_DATA);
|
|
log(MSG_NO_CURRENT_DATA);
|
|
|
- log("===== 业务处理结束,无有效代缴费数据 =====");
|
|
|
|
|
|
|
+ log("===== 业务处理结束 =====");
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
log("查询到当天代缴费记录共:" + proxyPayList.size() + " 条");
|
|
log("查询到当天代缴费记录共:" + proxyPayList.size() + " 条");
|
|
|
|
|
|
|
|
- // 3. 整理数据库返回数据
|
|
|
|
|
- Map<String, BigDecimal> phoneAmountMap = new HashMap<>(); // 手机号后四位 → 4位小数含税金额
|
|
|
|
|
- Map<String, String> phoneFeeDateMap = new HashMap<>(); // 手机号后四位 → 账期
|
|
|
|
|
- Set<String> phoneLast4Set = new HashSet<>(); // 去重手机号后四位集合
|
|
|
|
|
-
|
|
|
|
|
|
|
+ // 2. 整理有效数据:按账期分组,存储手机号后四位和对应金额
|
|
|
|
|
+ Map<String, Map<String, BigDecimal>> feeDatePhoneAmountMap = new HashMap<>();
|
|
|
|
|
+ Map<String, Set<String>> feeDatePhoneLast4Map = new HashMap<>();
|
|
|
for (RowMap row : proxyPayList) {
|
|
for (RowMap row : proxyPayList) {
|
|
|
- // 3.1 提取并校验完整手机号(截取后四位)
|
|
|
|
|
String fullPhone = Objects.toString(row.get(FIELD_PHONE), "").trim();
|
|
String fullPhone = Objects.toString(row.get(FIELD_PHONE), "").trim();
|
|
|
- if (StringUtils.isBlank(fullPhone) || fullPhone.length() < 4) {
|
|
|
|
|
- log("【数据过滤】手机号无效(为空或长度不足4位),跳过当前记录:" + fullPhone);
|
|
|
|
|
|
|
+
|
|
|
|
|
+ // ↓↓↓ 只改这里 ↓↓↓
|
|
|
|
|
+ String cleanPhone = fullPhone.replaceAll("-", ""); // 新增:清理-
|
|
|
|
|
+ if (StringUtils.isBlank(cleanPhone) || cleanPhone.length() < 4) { // 改过滤条件
|
|
|
|
|
+ log("【数据过滤】手机号无效:" + fullPhone);
|
|
|
continue;
|
|
continue;
|
|
|
}
|
|
}
|
|
|
- String phoneLast4 = fullPhone.substring(fullPhone.length() - 4); // 截取手机号后四位
|
|
|
|
|
|
|
+ String phoneLast4 = cleanPhone.substring(cleanPhone.length() - 4); // 改提取逻辑
|
|
|
|
|
+ // ↑↑↑ 修改结束 ↑↑↑
|
|
|
|
|
|
|
|
- // 3.2 提取并校验账期
|
|
|
|
|
String feeDate = Objects.toString(row.get(FIELD_FEE_DATE), "").trim();
|
|
String feeDate = Objects.toString(row.get(FIELD_FEE_DATE), "").trim();
|
|
|
if (StringUtils.isBlank(feeDate)) {
|
|
if (StringUtils.isBlank(feeDate)) {
|
|
|
- log("【数据过滤】账期为空,跳过当前记录(手机号后四位:" + phoneLast4 + ")");
|
|
|
|
|
|
|
+ log("【数据过滤】账期为空,跳过(手机号后四位:" + phoneLast4 + ")");
|
|
|
continue;
|
|
continue;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 3.3 计算金额:ISP_TOTAL + SERVICE_FEE(保留4位小数,四舍五入)
|
|
|
|
|
BigDecimal amount = calculateAmountFromRow(row);
|
|
BigDecimal amount = calculateAmountFromRow(row);
|
|
|
if (amount.compareTo(BigDecimal.ZERO) == 0) {
|
|
if (amount.compareTo(BigDecimal.ZERO) == 0) {
|
|
|
- log("【数据过滤】金额无效(为0或转换失败),跳过当前记录(手机号后四位:" + phoneLast4 + ")");
|
|
|
|
|
|
|
+ log("【数据过滤】金额无效,跳过(手机号后四位:" + phoneLast4 + ",账期:" + feeDate + ")");
|
|
|
continue;
|
|
continue;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 3.4 封装到容器(自动去重,Map重复key会覆盖,保留最新数据)
|
|
|
|
|
- phoneLast4Set.add(phoneLast4);
|
|
|
|
|
- phoneAmountMap.put(phoneLast4, amount);
|
|
|
|
|
- phoneFeeDateMap.put(phoneLast4, feeDate);
|
|
|
|
|
|
|
+ // 按账期分组存储(原有逻辑完全不变)
|
|
|
|
|
+ feeDatePhoneAmountMap.computeIfAbsent(feeDate, k -> new HashMap<>()).put(phoneLast4, amount);
|
|
|
|
|
+ feeDatePhoneLast4Map.computeIfAbsent(feeDate, k -> new HashSet<>()).add(phoneLast4);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 4. 校验整理后的数据是否有效
|
|
|
|
|
- if (phoneLast4Set.isEmpty() || phoneAmountMap.isEmpty()) {
|
|
|
|
|
|
|
+ if (feeDatePhoneLast4Map.isEmpty()) {
|
|
|
log(MSG_NO_VALID_DATA);
|
|
log(MSG_NO_VALID_DATA);
|
|
|
- log("===== 业务处理结束,无有效整理数据 =====");
|
|
|
|
|
|
|
+ log("===== 业务处理结束 =====");
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
- log("整理后有效数据共:" + phoneLast4Set.size() + " 条");
|
|
|
|
|
-
|
|
|
|
|
- // 5. 手机号后四位匹配合同服务ID(建立映射关系,批量查询提高效率)
|
|
|
|
|
- Map<String, String> phoneContractMap = matchPhoneToContractId(new ArrayList<>(phoneLast4Set));
|
|
|
|
|
- if (phoneContractMap.isEmpty()) {
|
|
|
|
|
- log(MSG_NO_CONTRACT_ID);
|
|
|
|
|
- log("===== 业务处理结束,无匹配合同服务ID =====");
|
|
|
|
|
- return;
|
|
|
|
|
|
|
+ log("整理后有效账期数:" + feeDatePhoneLast4Map.size() + " 个");
|
|
|
|
|
+ for (String feeDate : feeDatePhoneLast4Map.keySet()) {
|
|
|
|
|
+ log("账期:" + feeDate + ",有效手机号后四位数量:" + feeDatePhoneLast4Map.get(feeDate).size());
|
|
|
|
|
+ // 新增:打印具体的后四位列表(核心代码)
|
|
|
|
|
+ log("账期:" + feeDate + ",有效手机号后四位列表:" + new ArrayList<>(feeDatePhoneLast4Map.get(feeDate)));
|
|
|
}
|
|
}
|
|
|
- log("匹配到有效合同服务ID共:" + phoneContractMap.size() + " 个");
|
|
|
|
|
-
|
|
|
|
|
- // 6. 转换为合同ID-金额映射
|
|
|
|
|
- Map<String, BigDecimal> contractAmountMap = new HashMap<>();
|
|
|
|
|
- String targetFeeDate = ""; // 基准账期(取第一个有效账期)
|
|
|
|
|
|
|
|
|
|
- for (Map.Entry<String, String> entry : phoneContractMap.entrySet()) {
|
|
|
|
|
- String phoneLast4 = entry.getKey();
|
|
|
|
|
- String contractId = entry.getValue();
|
|
|
|
|
- // 金额保留4位小数,兜底格式化(防止数据异常)
|
|
|
|
|
- BigDecimal amount = phoneAmountMap.getOrDefault(phoneLast4, BigDecimal.ZERO).setScale(4, RoundingMode.HALF_UP);
|
|
|
|
|
|
|
+ // 3. 逐账期处理数据
|
|
|
|
|
+ for (String feeDate : feeDatePhoneLast4Map.keySet()) {
|
|
|
|
|
+ log("===== 开始处理账期:" + feeDate + " =====");
|
|
|
|
|
+ Set<String> phoneLast4Set = feeDatePhoneLast4Map.get(feeDate);
|
|
|
|
|
+ Map<String, BigDecimal> phoneAmountMap = feeDatePhoneAmountMap.get(feeDate);
|
|
|
|
|
|
|
|
- // 过滤无效金额
|
|
|
|
|
- if (amount.compareTo(BigDecimal.ZERO) > 0) {
|
|
|
|
|
- contractAmountMap.put(contractId, amount);
|
|
|
|
|
|
|
+ // 3.1 匹配手机号后四位对应的合同服务ID(使用服务表主键ID)
|
|
|
|
|
+ Map<String, String> phoneContractMap = matchPhoneToContractId(new ArrayList<>(phoneLast4Set));
|
|
|
|
|
+ if (phoneContractMap.isEmpty()) {
|
|
|
|
|
+ log("账期" + feeDate + ":" + MSG_NO_CONTRACT_ID);
|
|
|
|
|
+ continue;
|
|
|
|
|
+ }
|
|
|
|
|
+ log("账期" + feeDate + ":匹配到合同服务ID共:" + phoneContractMap.size() + " 个");
|
|
|
|
|
+
|
|
|
|
|
+ // 3.2 转换为合同服务ID和金额的映射
|
|
|
|
|
+ Map<String, BigDecimal> contractAmountMap = new HashMap<>();
|
|
|
|
|
+ for (Map.Entry<String, String> entry : phoneContractMap.entrySet()) {
|
|
|
|
|
+ String phoneLast4 = entry.getKey();
|
|
|
|
|
+ String contractId = entry.getValue();
|
|
|
|
|
+ BigDecimal amount = phoneAmountMap.getOrDefault(phoneLast4, BigDecimal.ZERO).setScale(4, RoundingMode.HALF_UP);
|
|
|
|
|
+ if (amount.compareTo(BigDecimal.ZERO) > 0) {
|
|
|
|
|
+ contractAmountMap.put(contractId, amount);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // 提取基准账期
|
|
|
|
|
- if (StringUtils.isBlank(targetFeeDate)) {
|
|
|
|
|
- targetFeeDate = phoneFeeDateMap.getOrDefault(phoneLast4, "");
|
|
|
|
|
|
|
+ // 3.3 转换账期为 yyyyMM 格式(用于DATE_FORMAT匹配)
|
|
|
|
|
+ String feeDateYm = convertFeeDateToYmFormat(feeDate);
|
|
|
|
|
+ if (feeDateYm == null) {
|
|
|
|
|
+ log("账期" + feeDate + ":" + MSG_FEE_DATE_FORMAT_ERROR);
|
|
|
|
|
+ continue;
|
|
|
}
|
|
}
|
|
|
- }
|
|
|
|
|
|
|
+ log("账期" + feeDate + ":转换为yyyyMM格式:" + feeDateYm);
|
|
|
|
|
|
|
|
- // 7. 账期转换为当月起止日期
|
|
|
|
|
- Map<String, String> periodDateMap = convertFeeDateToPeriod(targetFeeDate);
|
|
|
|
|
- if (periodDateMap == null) {
|
|
|
|
|
- log(MSG_FEE_DATE_FORMAT_ERROR);
|
|
|
|
|
- log("===== 业务处理结束,账期转换失败 =====");
|
|
|
|
|
- return;
|
|
|
|
|
- }
|
|
|
|
|
- String periodBeginDate = periodDateMap.get("begin");
|
|
|
|
|
- String periodEndDate = periodDateMap.get("end");
|
|
|
|
|
- log("账期转换完成,更新周期范围:" + periodBeginDate + " 至 " + periodEndDate);
|
|
|
|
|
|
|
+ // 3.4 更新合同周期表(DATE_FORMAT匹配整个月份,且PERIOD_COST = PERIOD_PRICE)
|
|
|
|
|
+ int contractUpdatedCount = batchUpdateContractPeriod(contractAmountMap, feeDateYm);
|
|
|
|
|
+ log("账期" + feeDate + ":合同周期表更新 " + contractUpdatedCount + " 条数据");
|
|
|
|
|
+
|
|
|
|
|
+ // 3.5 更新采购订单付款计划表
|
|
|
|
|
+ // 核心规则:PAY_AMOUNT = PLAN_AMOUNT,REMAIN_AMOUNT = 0
|
|
|
|
|
+ int paymentUpdatedCount = batchUpdatePaymentPlan(contractAmountMap, feeDateYm);
|
|
|
|
|
+ log("账期" + feeDate + ":采购订单付款计划表更新 " + paymentUpdatedCount + " 条数据");
|
|
|
|
|
|
|
|
- // 8. 批量更新合同服务周期表
|
|
|
|
|
- int updatedCount = batchUpdateContractPeriod(contractAmountMap, periodBeginDate, periodEndDate);
|
|
|
|
|
|
|
+ log("===== 账期" + feeDate + "处理完成 =====");
|
|
|
|
|
+ }
|
|
|
|
|
|
|
|
- // 9. 打印最终处理结果,流程闭环
|
|
|
|
|
- log("===== 业务处理完成,共更新合同周期表 " + updatedCount + " 条数据 =====");
|
|
|
|
|
|
|
+ log("===== 所有账期业务处理完成 =====");
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * 核心:以当前日期(精确到天)为条件,查询代缴费表当天所有有效数据
|
|
|
|
|
- * 忽略CREATE_DATE的时分秒,避免因时间戳差异导致数据遗漏
|
|
|
|
|
- * @param currentDate 当前日期(格式:yyyy-MM-dd)
|
|
|
|
|
- * @return 当天代缴费记录列表
|
|
|
|
|
|
|
+ * 查询当天的代缴费数据
|
|
|
*/
|
|
*/
|
|
|
private List<RowMap> getProxyPayDataByCurrentDate(String currentDate) {
|
|
private List<RowMap> getProxyPayDataByCurrentDate(String currentDate) {
|
|
|
- // SQL优化:使用DATE()函数提取日期部分,兼容DATETIME/DATE类型字段
|
|
|
|
|
- // 替换查询字段:EXTENDED_PRICE → ISP_TOTAL + SERVICE_FEE
|
|
|
|
|
- String sql = "SELECT " + FIELD_PHONE + ", " + FIELD_FEE_DATE + ", " + FIELD_ISP_TOTAL + ", " + FIELD_SERVICE_FEE + ", " + FIELD_CREATE_DATE +
|
|
|
|
|
- " FROM " + TABLE_PROXY_PAY +
|
|
|
|
|
- " WHERE DATE(" + FIELD_CREATE_DATE + ") = ?"; // 忽略时分秒,精准匹配当天所有记录
|
|
|
|
|
-
|
|
|
|
|
- // 执行查询,返回当天所有代缴费记录(平台通用方法,无报错兼容)
|
|
|
|
|
|
|
+ String sql = String.format(
|
|
|
|
|
+ "SELECT %s, %s, %s, %s, %s FROM %s WHERE DATE(%s) = ?",
|
|
|
|
|
+ FIELD_PHONE, FIELD_FEE_DATE, FIELD_ISP_TOTAL, FIELD_TAX_DOLLARS, FIELD_CREATE_DATE,
|
|
|
|
|
+ TABLE_PROXY_PAY, FIELD_CREATE_DATE
|
|
|
|
|
+ );
|
|
|
|
|
+ log("执行代缴费数据查询SQL:" + sql + ",参数:" + currentDate);
|
|
|
return DBSql.getMaps(sql, currentDate);
|
|
return DBSql.getMaps(sql, currentDate);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * 计算金额:ISP_TOTAL + SERVICE_FEE(兼容多类型,避免转换报错)
|
|
|
|
|
- * 最终保留4位小数,四舍五入,符合高精度财务需求
|
|
|
|
|
- * @param row 数据库查询结果行
|
|
|
|
|
- * @return 格式化后的4位小数金额
|
|
|
|
|
|
|
+ * 计算金额(ISP_TOTAL + TAX_DOLLARS)
|
|
|
*/
|
|
*/
|
|
|
private BigDecimal calculateAmountFromRow(RowMap row) {
|
|
private BigDecimal calculateAmountFromRow(RowMap row) {
|
|
|
- // 提取ISP_TOTAL字段值并转换
|
|
|
|
|
BigDecimal ispTotal = getBigDecimalFromRow(row, FIELD_ISP_TOTAL);
|
|
BigDecimal ispTotal = getBigDecimalFromRow(row, FIELD_ISP_TOTAL);
|
|
|
- // 提取SERVICE_FEE字段值并转换
|
|
|
|
|
- BigDecimal serviceFee = getBigDecimalFromRow(row, FIELD_SERVICE_FEE);
|
|
|
|
|
-
|
|
|
|
|
- // 计算总和并保留4位小数
|
|
|
|
|
- BigDecimal totalAmount = ispTotal.add(serviceFee).setScale(4, RoundingMode.HALF_UP);
|
|
|
|
|
-
|
|
|
|
|
- log("【金额计算】ISP_TOTAL=" + ispTotal + ", SERVICE_FEE=" + serviceFee + ", 合计=" + totalAmount);
|
|
|
|
|
- return totalAmount;
|
|
|
|
|
|
|
+ BigDecimal taxDollars = getBigDecimalFromRow(row, FIELD_TAX_DOLLARS);
|
|
|
|
|
+ BigDecimal total = ispTotal.add(taxDollars).setScale(4, RoundingMode.HALF_UP);
|
|
|
|
|
+ log("【金额计算】ISP_TOTAL=" + ispTotal + ", TAX_DOLLARS=" + taxDollars + " → 合计=" + total);
|
|
|
|
|
+ return total;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * 从RowMap中提取指定字段并转换为BigDecimal(兼容各种数据类型)
|
|
|
|
|
- * @param row 数据库行数据
|
|
|
|
|
- * @param fieldName 字段名
|
|
|
|
|
- * @return 转换后的BigDecimal,默认值为0
|
|
|
|
|
|
|
+ * 从RowMap中安全获取BigDecimal类型值
|
|
|
*/
|
|
*/
|
|
|
private BigDecimal getBigDecimalFromRow(RowMap row, String fieldName) {
|
|
private BigDecimal getBigDecimalFromRow(RowMap row, String fieldName) {
|
|
|
Object valueObj = row.get(fieldName);
|
|
Object valueObj = row.get(fieldName);
|
|
|
BigDecimal value = BigDecimal.ZERO;
|
|
BigDecimal value = BigDecimal.ZERO;
|
|
|
-
|
|
|
|
|
if (valueObj != null) {
|
|
if (valueObj != null) {
|
|
|
try {
|
|
try {
|
|
|
if (valueObj instanceof BigDecimal) {
|
|
if (valueObj instanceof BigDecimal) {
|
|
|
value = (BigDecimal) valueObj;
|
|
value = (BigDecimal) valueObj;
|
|
|
} else if (valueObj instanceof Number) {
|
|
} else if (valueObj instanceof Number) {
|
|
|
- // 兼容Integer/Double/Long/Float等所有数值类型
|
|
|
|
|
value = BigDecimal.valueOf(((Number) valueObj).doubleValue());
|
|
value = BigDecimal.valueOf(((Number) valueObj).doubleValue());
|
|
|
} else {
|
|
} else {
|
|
|
- // 兼容字符串类型金额,去除首尾空格后转换
|
|
|
|
|
String valueStr = valueObj.toString().trim();
|
|
String valueStr = valueObj.toString().trim();
|
|
|
if (StringUtils.isNotBlank(valueStr)) {
|
|
if (StringUtils.isNotBlank(valueStr)) {
|
|
|
value = new BigDecimal(valueStr);
|
|
value = new BigDecimal(valueStr);
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
} catch (NumberFormatException e) {
|
|
} catch (NumberFormatException e) {
|
|
|
- log("【字段转换异常】字段" + fieldName + "值无效,转换失败:" + valueObj.toString());
|
|
|
|
|
|
|
+ log("【字段转换异常】字段" + fieldName + "值无效:" + valueObj.toString());
|
|
|
value = BigDecimal.ZERO;
|
|
value = BigDecimal.ZERO;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
@@ -232,23 +225,18 @@ public class DataWindowImportAfterEvent extends DataWindowAfterImport {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * 匹配手机号后四位与合同服务ID(从已安装产品表批量查询,提高执行效率)
|
|
|
|
|
- * @param phoneLast4List 手机号后四位列表
|
|
|
|
|
- * @return 手机号后四位 → 合同服务ID 映射关系
|
|
|
|
|
|
|
+ * 匹配手机号后四位对应的合同服务ID(核心:服务表主键是ID)
|
|
|
*/
|
|
*/
|
|
|
private Map<String, String> matchPhoneToContractId(List<String> phoneLast4List) {
|
|
private Map<String, String> matchPhoneToContractId(List<String> phoneLast4List) {
|
|
|
Map<String, String> phoneContractMap = new HashMap<>();
|
|
Map<String, String> phoneContractMap = new HashMap<>();
|
|
|
- if (phoneLast4List == null || phoneLast4List.isEmpty()) {
|
|
|
|
|
|
|
+ if (phoneLast4List.isEmpty()) {
|
|
|
return phoneContractMap;
|
|
return phoneContractMap;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
try {
|
|
try {
|
|
|
- // 动态拼接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条件占位符
|
|
|
|
|
|
|
+ StringBuilder sqlBuilder = new StringBuilder();
|
|
|
|
|
+ sqlBuilder.append("SELECT RIGHT(").append(FIELD_SERVICE_NAME).append(",4) AS NAME_LAST4, ");
|
|
|
|
|
+ sqlBuilder.append(FIELD_SERVICE_PRIMARY_KEY).append(" FROM ").append(TABLE_CONTRACT_SERVICE);
|
|
|
|
|
+ sqlBuilder.append(" WHERE RIGHT(").append(FIELD_SERVICE_NAME).append(",4) IN (");
|
|
|
for (int i = 0; i < phoneLast4List.size(); i++) {
|
|
for (int i = 0; i < phoneLast4List.size(); i++) {
|
|
|
if (i > 0) {
|
|
if (i > 0) {
|
|
|
sqlBuilder.append(",");
|
|
sqlBuilder.append(",");
|
|
@@ -257,110 +245,166 @@ public class DataWindowImportAfterEvent extends DataWindowAfterImport {
|
|
|
}
|
|
}
|
|
|
sqlBuilder.append(")");
|
|
sqlBuilder.append(")");
|
|
|
|
|
|
|
|
- // 执行查询,封装映射关系
|
|
|
|
|
|
|
+ log("执行合同匹配SQL:" + sqlBuilder.toString() + ",参数:" + phoneLast4List);
|
|
|
List<RowMap> contractList = DBSql.getMaps(sqlBuilder.toString(), phoneLast4List.toArray());
|
|
List<RowMap> contractList = DBSql.getMaps(sqlBuilder.toString(), phoneLast4List.toArray());
|
|
|
for (RowMap row : contractList) {
|
|
for (RowMap row : contractList) {
|
|
|
- String refLast4 = row.getString("REF_LAST4");
|
|
|
|
|
- String contractId = row.getString(FIELD_CONTRACT_SERVICE_ID);
|
|
|
|
|
-
|
|
|
|
|
- // 过滤无效数据,封装有效映射
|
|
|
|
|
- if (StringUtils.isNoneBlank(refLast4, contractId)) {
|
|
|
|
|
- refLast4 = refLast4.trim();
|
|
|
|
|
- contractId = contractId.trim();
|
|
|
|
|
- phoneContractMap.put(refLast4, contractId);
|
|
|
|
|
|
|
+ String nameLast4 = row.getString("NAME_LAST4");
|
|
|
|
|
+ String contractId = row.getString(FIELD_SERVICE_PRIMARY_KEY);
|
|
|
|
|
+ if (StringUtils.isNoneBlank(nameLast4, contractId)) {
|
|
|
|
|
+ phoneContractMap.put(nameLast4.trim(), contractId.trim());
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
} catch (Exception e) {
|
|
} catch (Exception e) {
|
|
|
- log("【合同ID匹配异常】异常信息:" + e.getMessage());
|
|
|
|
|
|
|
+ log("【合同ID匹配异常】" + e.getMessage());
|
|
|
e.printStackTrace();
|
|
e.printStackTrace();
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
return phoneContractMap;
|
|
return phoneContractMap;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * 账期转换为当月起止日期(支持yyyy-MM和yyyyMM两种格式,兼容业务场景)
|
|
|
|
|
- * @param feeDate 账期(格式:yyyy-MM 或 yyyyMM)
|
|
|
|
|
- * @return 当月起止日期映射(begin:当月1号,end:当月最后一天)
|
|
|
|
|
|
|
+ * 转换账期为 yyyyMM 格式(支持yyyy-MM/yyyyMM两种输入)
|
|
|
*/
|
|
*/
|
|
|
- private Map<String, String> convertFeeDateToPeriod(String feeDate) {
|
|
|
|
|
|
|
+ private String convertFeeDateToYmFormat(String feeDate) {
|
|
|
if (StringUtils.isBlank(feeDate)) {
|
|
if (StringUtils.isBlank(feeDate)) {
|
|
|
- log("【账期转换异常】账期为空,无法转换");
|
|
|
|
|
|
|
+ log("【账期转换异常】账期为空");
|
|
|
return null;
|
|
return null;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
try {
|
|
try {
|
|
|
- // 解析账期为YearMonth对象,兼容两种格式
|
|
|
|
|
YearMonth feeYearMonth = feeDate.contains("-") ?
|
|
YearMonth feeYearMonth = feeDate.contains("-") ?
|
|
|
YearMonth.parse(feeDate, FORMATTER_YEAR_MONTH_DASH) :
|
|
YearMonth.parse(feeDate, FORMATTER_YEAR_MONTH_DASH) :
|
|
|
YearMonth.parse(feeDate, FORMATTER_YEAR_MONTH_NO_DASH);
|
|
YearMonth.parse(feeDate, FORMATTER_YEAR_MONTH_NO_DASH);
|
|
|
-
|
|
|
|
|
- // 构建当月起止日期(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;
|
|
|
|
|
|
|
+ return feeYearMonth.format(FORMATTER_YEAR_MONTH_NO_DASH);
|
|
|
} catch (DateTimeParseException e) {
|
|
} catch (DateTimeParseException e) {
|
|
|
- log("【账期转换异常】无效账期格式,无法解析:" + feeDate + ",异常信息:" + e.getMessage());
|
|
|
|
|
|
|
+ log("【账期转换异常】无效格式:" + feeDate);
|
|
|
e.printStackTrace();
|
|
e.printStackTrace();
|
|
|
return null;
|
|
return null;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
|
- * 批量更新合同服务周期表(使用CASE WHEN语法,一条SQL完成所有更新,高效防SQL注入)
|
|
|
|
|
- * 兼容DATETIME类型时间戳(00:00:00),避免日期匹配失败
|
|
|
|
|
- * @param contractAmountMap 合同ID → 4位小数金额 映射
|
|
|
|
|
- * @param periodBeginDate 周期开始日期(格式:yyyy-MM-dd)
|
|
|
|
|
- * @param periodEndDate 周期结束日期(格式:yyyy-MM-dd)
|
|
|
|
|
- * @return 受影响的记录数
|
|
|
|
|
|
|
+ * 批量更新合同周期表
|
|
|
|
|
+ * 核心规则:PERIOD_COST = PERIOD_PRICE
|
|
|
*/
|
|
*/
|
|
|
- private int batchUpdateContractPeriod(Map<String, BigDecimal> contractAmountMap, String periodBeginDate, String periodEndDate) {
|
|
|
|
|
- // 入参有效性校验
|
|
|
|
|
- if (contractAmountMap.isEmpty() || StringUtils.isAnyBlank(periodBeginDate, periodEndDate)) {
|
|
|
|
|
- log("【批量更新异常】入参无效,无法执行更新");
|
|
|
|
|
|
|
+ private int batchUpdateContractPeriod(Map<String, BigDecimal> contractAmountMap, String feeDateYm) {
|
|
|
|
|
+ if (contractAmountMap.isEmpty() || StringUtils.isBlank(feeDateYm)) {
|
|
|
|
|
+ log("【批量更新异常】入参无效");
|
|
|
return 0;
|
|
return 0;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
try {
|
|
try {
|
|
|
- // 动态拼接批量更新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<>(); // SQL参数列表(防注入)
|
|
|
|
|
- List<String> contractIdList = new ArrayList<>(); // 合同ID列表(用于WHERE条件)
|
|
|
|
|
|
|
+ StringBuilder sqlBuilder = new StringBuilder();
|
|
|
|
|
+ sqlBuilder.append("UPDATE ").append(TABLE_CONTRACT_PERIOD).append(" SET ");
|
|
|
|
|
|
|
|
- // 拼接CASE WHEN条件(合同ID → 对应4位小数金额)
|
|
|
|
|
|
|
+ // 1. 更新PERIOD_PRICE
|
|
|
|
|
+ sqlBuilder.append(FIELD_PERIOD_PRICE).append(" = CASE ").append(FIELD_PAY_PLAN_CONTRACT_ID).append(" ");
|
|
|
for (Map.Entry<String, BigDecimal> entry : contractAmountMap.entrySet()) {
|
|
for (Map.Entry<String, BigDecimal> entry : contractAmountMap.entrySet()) {
|
|
|
- String contractId = entry.getKey();
|
|
|
|
|
- BigDecimal amount = entry.getValue();
|
|
|
|
|
|
|
+ sqlBuilder.append("WHEN ? THEN ? ");
|
|
|
|
|
+ }
|
|
|
|
|
+ sqlBuilder.append("END, ");
|
|
|
|
|
+
|
|
|
|
|
+ // 2. 关键:PERIOD_COST = PERIOD_PRICE
|
|
|
|
|
+ sqlBuilder.append(FIELD_PERIOD_COST).append(" = ").append(FIELD_PERIOD_PRICE).append(", ");
|
|
|
|
|
|
|
|
|
|
+ // 3. 更新PERIOD_ADJUSTED_PRICE
|
|
|
|
|
+ sqlBuilder.append(FIELD_PERIOD_ADJUSTED_PRICE).append(" = CASE ").append(FIELD_PAY_PLAN_CONTRACT_ID).append(" ");
|
|
|
|
|
+ for (Map.Entry<String, BigDecimal> entry : contractAmountMap.entrySet()) {
|
|
|
sqlBuilder.append("WHEN ? THEN ? ");
|
|
sqlBuilder.append("WHEN ? THEN ? ");
|
|
|
- batchParams.add(contractId);
|
|
|
|
|
- batchParams.add(amount);
|
|
|
|
|
- contractIdList.add(contractId);
|
|
|
|
|
}
|
|
}
|
|
|
|
|
+ sqlBuilder.append("END ");
|
|
|
|
|
|
|
|
- // 拼接WHERE条件
|
|
|
|
|
- sqlBuilder.append("END WHERE ").append(FIELD_CONTRACT_SERVICE_ID).append(" IN (");
|
|
|
|
|
- for (int i = 0; i < contractIdList.size(); i++) {
|
|
|
|
|
|
|
+ // WHERE条件:合同ID IN + 周期包含当前账期月份
|
|
|
|
|
+ sqlBuilder.append("WHERE ").append(FIELD_PAY_PLAN_CONTRACT_ID).append(" IN (");
|
|
|
|
|
+ for (int i = 0; i < contractAmountMap.size(); i++) {
|
|
|
if (i > 0) {
|
|
if (i > 0) {
|
|
|
sqlBuilder.append(",");
|
|
sqlBuilder.append(",");
|
|
|
}
|
|
}
|
|
|
sqlBuilder.append("?");
|
|
sqlBuilder.append("?");
|
|
|
}
|
|
}
|
|
|
- sqlBuilder.append(") AND DATE(PERIOD_BEGIN_DATE) >= ? AND DATE(PERIOD_END_DATE) <= ?");
|
|
|
|
|
|
|
+ sqlBuilder.append(") AND ");
|
|
|
|
|
+ sqlBuilder.append("DATE_FORMAT(").append(FIELD_PERIOD_BEGIN_DATE).append(", '%Y%m') <= ? AND ");
|
|
|
|
|
+ sqlBuilder.append("DATE_FORMAT(").append(FIELD_PERIOD_END_DATE).append(", '%Y%m') >= ?");
|
|
|
|
|
+
|
|
|
|
|
+ // 组装参数
|
|
|
|
|
+ List<Object> params = new ArrayList<>();
|
|
|
|
|
+ // 1. PERIOD_PRICE的CASE参数(ID, 金额)
|
|
|
|
|
+ for (Map.Entry<String, BigDecimal> entry : contractAmountMap.entrySet()) {
|
|
|
|
|
+ params.add(entry.getKey());
|
|
|
|
|
+ params.add(entry.getValue());
|
|
|
|
|
+ }
|
|
|
|
|
+ // 2. PERIOD_ADJUSTED_PRICE的CASE参数(ID, 金额)
|
|
|
|
|
+ for (Map.Entry<String, BigDecimal> entry : contractAmountMap.entrySet()) {
|
|
|
|
|
+ params.add(entry.getKey());
|
|
|
|
|
+ params.add(entry.getValue());
|
|
|
|
|
+ }
|
|
|
|
|
+ // 3. IN条件的合同ID参数
|
|
|
|
|
+ params.addAll(contractAmountMap.keySet());
|
|
|
|
|
+ // 4. 日期条件参数(yyyyMM格式)
|
|
|
|
|
+ params.add(feeDateYm);
|
|
|
|
|
+ params.add(feeDateYm);
|
|
|
|
|
+
|
|
|
|
|
+ log("执行合同周期表更新SQL:" + sqlBuilder.toString());
|
|
|
|
|
+ log("合同周期表更新参数列表:" + params);
|
|
|
|
|
+ return DBSql.update(sqlBuilder.toString(), params.toArray());
|
|
|
|
|
+ } catch (Exception e) {
|
|
|
|
|
+ log("【合同周期表更新异常】" + e.getMessage());
|
|
|
|
|
+ e.printStackTrace();
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ /**
|
|
|
|
|
+ * 批量更新采购订单付款计划表
|
|
|
|
|
+ * 核心规则:PAY_AMOUNT = PLAN_AMOUNT,REMAIN_AMOUNT = 0
|
|
|
|
|
+ */
|
|
|
|
|
+ private int batchUpdatePaymentPlan(Map<String, BigDecimal> contractAmountMap, String feeDateYm) {
|
|
|
|
|
+ if (contractAmountMap.isEmpty() || StringUtils.isBlank(feeDateYm)) {
|
|
|
|
|
+ log("【付款计划更新异常】入参无效");
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ }
|
|
|
|
|
+ try {
|
|
|
|
|
+ StringBuilder sqlBuilder = new StringBuilder();
|
|
|
|
|
+ sqlBuilder.append("UPDATE ").append(TABLE_PAYMENT_PLAN).append(" SET ");
|
|
|
|
|
+
|
|
|
|
|
+ // 1. 更新PLAN_AMOUNT(核心金额)
|
|
|
|
|
+ sqlBuilder.append(FIELD_PLAN_AMOUNT).append(" = CASE ").append(FIELD_PAY_PLAN_CONTRACT_ID).append(" ");
|
|
|
|
|
+ for (Map.Entry<String, BigDecimal> entry : contractAmountMap.entrySet()) {
|
|
|
|
|
+ sqlBuilder.append("WHEN ? THEN ? ");
|
|
|
|
|
+ }
|
|
|
|
|
+ sqlBuilder.append("END, ");
|
|
|
|
|
|
|
|
- // 追加WHERE条件参数
|
|
|
|
|
- batchParams.addAll(contractIdList);
|
|
|
|
|
- batchParams.add(periodBeginDate);
|
|
|
|
|
- batchParams.add(periodEndDate);
|
|
|
|
|
|
|
+ // 2. 关键:PAY_AMOUNT 等于 PLAN_AMOUNT
|
|
|
|
|
+ sqlBuilder.append(FIELD_PAY_AMOUNT).append(" = ").append(FIELD_PLAN_AMOUNT).append(", ");
|
|
|
|
|
|
|
|
- // 执行批量更新,返回受影响行数
|
|
|
|
|
- return DBSql.update(sqlBuilder.toString(), batchParams.toArray());
|
|
|
|
|
|
|
+ // 3. 关键:REMAIN_AMOUNT 设置为 0
|
|
|
|
|
+ sqlBuilder.append(FIELD_REMAIN_AMOUNT).append(" = 0 ");
|
|
|
|
|
+
|
|
|
|
|
+ // WHERE条件:合同ID IN + 计划日期匹配当前账期月份
|
|
|
|
|
+ sqlBuilder.append("WHERE ").append(FIELD_PAY_PLAN_CONTRACT_ID).append(" IN (");
|
|
|
|
|
+ for (int i = 0; i < contractAmountMap.size(); i++) {
|
|
|
|
|
+ if (i > 0) {
|
|
|
|
|
+ sqlBuilder.append(",");
|
|
|
|
|
+ }
|
|
|
|
|
+ sqlBuilder.append("?");
|
|
|
|
|
+ }
|
|
|
|
|
+ sqlBuilder.append(") AND ");
|
|
|
|
|
+ sqlBuilder.append("DATE_FORMAT(").append(FIELD_PLAN_DATE).append(", '%Y%m') = ?");
|
|
|
|
|
+
|
|
|
|
|
+ // 组装参数
|
|
|
|
|
+ List<Object> params = new ArrayList<>();
|
|
|
|
|
+ // 1. PLAN_AMOUNT的CASE参数(ID, 金额)
|
|
|
|
|
+ for (Map.Entry<String, BigDecimal> entry : contractAmountMap.entrySet()) {
|
|
|
|
|
+ params.add(entry.getKey());
|
|
|
|
|
+ params.add(entry.getValue());
|
|
|
|
|
+ }
|
|
|
|
|
+ // 2. IN条件的合同ID参数
|
|
|
|
|
+ params.addAll(contractAmountMap.keySet());
|
|
|
|
|
+ // 3. 日期条件参数(yyyyMM格式)
|
|
|
|
|
+ params.add(feeDateYm);
|
|
|
|
|
+
|
|
|
|
|
+ log("执行付款计划表更新SQL:" + sqlBuilder.toString());
|
|
|
|
|
+ log("付款计划表更新参数列表:" + params);
|
|
|
|
|
+ return DBSql.update(sqlBuilder.toString(), params.toArray());
|
|
|
} catch (Exception e) {
|
|
} catch (Exception e) {
|
|
|
- log("【批量更新异常】更新合同周期表失败,异常信息:" + e.getMessage());
|
|
|
|
|
|
|
+ log("【付款计划表更新异常】" + e.getMessage());
|
|
|
e.printStackTrace();
|
|
e.printStackTrace();
|
|
|
return 0;
|
|
return 0;
|
|
|
}
|
|
}
|