|
|
@@ -0,0 +1,243 @@
|
|
|
+package com.lc.ibps.components.reagent.service;
|
|
|
+
|
|
|
+
|
|
|
+import cn.hutool.core.date.DateUtil;
|
|
|
+import com.lc.ibps.api.form.sql.util.BeanUtils;
|
|
|
+import com.lc.ibps.base.core.util.Collections;
|
|
|
+import com.lc.ibps.base.framework.id.UniqueIdUtil;
|
|
|
+import com.lc.ibps.base.framework.table.ICommonDao;
|
|
|
+import com.lc.ibps.cloud.provider.GenericProvider;
|
|
|
+import com.lc.ibps.untils.SqlUtil;
|
|
|
+import com.lc.ibps.untils.StrUtil;
|
|
|
+import org.springframework.stereotype.Service;
|
|
|
+
|
|
|
+import javax.annotation.Resource;
|
|
|
+import java.time.LocalDate;
|
|
|
+import java.time.format.DateTimeFormatter;
|
|
|
+import java.util.*;
|
|
|
+import java.util.stream.Collectors;
|
|
|
+
|
|
|
+@Service
|
|
|
+public class OrderService extends GenericProvider {
|
|
|
+
|
|
|
+ @Resource
|
|
|
+ private ICommonDao commonDao;
|
|
|
+
|
|
|
+
|
|
|
+ public String processOrder(String id, String operate) {
|
|
|
+ logger.warn("com.lc.ibps.components.reagent.service.OrderService.processOrder()--->id={}, operate={}", id, operate);
|
|
|
+
|
|
|
+ // 校验操作类型
|
|
|
+ if (!Arrays.asList("start", "back", "end").contains(operate)) {
|
|
|
+ return "-1^非法的操作类型: " + operate;
|
|
|
+ }
|
|
|
+
|
|
|
+ // ================= 1. 基础校验与主表查询 (公共逻辑) =================
|
|
|
+ if (id == null || id.trim().isEmpty()) {
|
|
|
+ return "-1^id为空";
|
|
|
+ }
|
|
|
+
|
|
|
+ List<String> idList = Arrays.stream(id.split(","))
|
|
|
+ .map(String::trim)
|
|
|
+ .filter(s -> !s.isEmpty())
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ if (idList.isEmpty()) {
|
|
|
+ return "-1^id非法";
|
|
|
+ }
|
|
|
+
|
|
|
+ String safeIdStr = idList.stream()
|
|
|
+ .map(s -> s.replace("'", "''"))
|
|
|
+ .collect(Collectors.joining("','"));
|
|
|
+
|
|
|
+ // 查询入库登记子表
|
|
|
+ String sqlMain = "SELECT * from t_sjhxhclrkysdjbzb where parent_id_ in('" + safeIdStr + "')";
|
|
|
+ List<Map<String, Object>> inSubList = commonDao.query(sqlMain);
|
|
|
+
|
|
|
+ if (inSubList == null || inSubList.isEmpty()) {
|
|
|
+ return "-1^未找到入库登记子表记录";
|
|
|
+ }
|
|
|
+
|
|
|
+ // ================= 2. 查询订单子表 (公共逻辑) =================
|
|
|
+ List<String> ddzIdList = inSubList.stream()
|
|
|
+ .map(m -> {
|
|
|
+ Object val = m.get("ding_dan_zi_id_");
|
|
|
+ return val != null ? val.toString().trim() : null;
|
|
|
+ })
|
|
|
+ .filter(Objects::nonNull)
|
|
|
+ .distinct()
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ List<Map<String, Object>> orderSubList = new ArrayList<>();
|
|
|
+ if (!ddzIdList.isEmpty()) {
|
|
|
+ String safeDdzIdStr = ddzIdList.stream()
|
|
|
+ .map(s -> s.replace("'", "''"))
|
|
|
+ .collect(Collectors.joining("','"));
|
|
|
+ String sqlSub = "SELECT * from t_sjhccgsqbhzzb where id_ in('" + safeDdzIdStr + "')";
|
|
|
+ orderSubList = commonDao.query(sqlSub);
|
|
|
+ }
|
|
|
+
|
|
|
+ Map<String, Map<String, Object>> orderSubMap = orderSubList.stream()
|
|
|
+ .collect(Collectors.toMap(
|
|
|
+ m -> (String) m.get("id_"),
|
|
|
+ m -> m,
|
|
|
+ (v1, v2) -> v1
|
|
|
+ ));
|
|
|
+
|
|
|
+ // ================= 3. 【第一阶段】全量预校验与SQL构造 (核心差异点) =================
|
|
|
+ List<String> updateSqls = new ArrayList<>();
|
|
|
+
|
|
|
+ for (Map<String, Object> inSub : inSubList) {
|
|
|
+ String ddzId = (String) inSub.get("ding_dan_zi_id_");
|
|
|
+
|
|
|
+ if (ddzId == null || !orderSubMap.containsKey(ddzId)) {
|
|
|
+ return "-1^数据错误:找不到对应的订单子表记录 (dingDanZiId=" + ddzId + ")";
|
|
|
+ }
|
|
|
+
|
|
|
+ Map<String, Object> orderSub = orderSubMap.get(ddzId);
|
|
|
+
|
|
|
+ // 获取数值
|
|
|
+ double inQty = getDoubleValue(inSub.get("shu_liang_"));
|
|
|
+ double currentYuLing = getDoubleValue(orderSub.get("yu_ling_liang_"));
|
|
|
+ double currentDaiRuKu = getDoubleValue(orderSub.get("dai_ru_ku_shu_lia"));
|
|
|
+ double orderQty = getDoubleValue(orderSub.get("shu_liang_")); // 订单总量,start时用
|
|
|
+
|
|
|
+ if (inQty <= 0) {
|
|
|
+ return "-1^数量必须为正数 (当前值:" + inQty + ")";
|
|
|
+ }
|
|
|
+
|
|
|
+ // --- 根据 operate 计算新值和校验 ---
|
|
|
+ double newYuLing = 0.0;
|
|
|
+ Double newDaiRuKu = null; // null 表示该操作不更新此字段
|
|
|
+ boolean checkPassed = false;
|
|
|
+ String errorMsg = "";
|
|
|
+
|
|
|
+ if ("start".equals(operate)) {
|
|
|
+ // [START] 占用预留,减少待入库
|
|
|
+ double availableQty = orderQty - currentYuLing;
|
|
|
+ if (availableQty < inQty) {
|
|
|
+ errorMsg = "已超过可入库数量! (可用:" + availableQty + ", 申请:" + inQty + ")";
|
|
|
+ } else {
|
|
|
+ newYuLing = currentYuLing + inQty;
|
|
|
+ newDaiRuKu = currentDaiRuKu - inQty;
|
|
|
+ checkPassed = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ } else if ("back".equals(operate)) {
|
|
|
+ // [BACK] 释放预留,恢复待入库 (撤销 start)
|
|
|
+ if (currentYuLing < inQty) {
|
|
|
+ errorMsg = "当前预留量不足,无法撤销! (当前预留:" + currentYuLing + ", 需撤销:" + inQty + ")";
|
|
|
+ } else {
|
|
|
+ newYuLing = currentYuLing - inQty;
|
|
|
+ newDaiRuKu = currentDaiRuKu + inQty;
|
|
|
+ checkPassed = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ } else if ("end".equals(operate)) {
|
|
|
+ // [END] 消除本次预留 (不恢复待入库,因为已正式入库)
|
|
|
+ if (currentYuLing < inQty) {
|
|
|
+ errorMsg = "当前预留量不足,确认失败! (当前总预留:" + currentYuLing + ", 本次需释放:" + inQty + ")";
|
|
|
+ } else {
|
|
|
+ newYuLing = currentYuLing - inQty;
|
|
|
+ // newDaiRuKu 保持 null,不更新该字段
|
|
|
+ checkPassed = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ // --- 处理校验结果 ---
|
|
|
+ if (!checkPassed) {
|
|
|
+ String mingCheng = Objects.toString(orderSub.get("ming_cheng_"), "");
|
|
|
+ String bianMa = Objects.toString(orderSub.get("bian_ma_"), "");
|
|
|
+ String operateStr = "";
|
|
|
+ if(operate.equals("start")){
|
|
|
+ operateStr = "启动";
|
|
|
+ } else if (operate.equals("back")){
|
|
|
+ operateStr = "撤回";
|
|
|
+ } else if (operate.equals("end")){
|
|
|
+ operateStr = "结束";
|
|
|
+ }
|
|
|
+ // 统一错误消息格式
|
|
|
+ return "-1^" + mingCheng + bianMa + "操作(" + operateStr + ")失败!" + errorMsg;
|
|
|
+ }
|
|
|
+
|
|
|
+ // --- 构造 SQL ---
|
|
|
+ // 基础部分:更新预留量
|
|
|
+ StringBuilder sqlBuilder = new StringBuilder();
|
|
|
+ sqlBuilder.append("update t_sjhccgsqbhzzb set yu_ling_liang_ = ").append(newYuLing);
|
|
|
+
|
|
|
+ // 如果需要更新待入库数 (start 和 back 需要,end 不需要)
|
|
|
+ if (newDaiRuKu != null) {
|
|
|
+ if (newDaiRuKu < 0) {
|
|
|
+ return "-1^计算错误:待入库数不能为负数";
|
|
|
+ }
|
|
|
+ sqlBuilder.append(", dai_ru_ku_shu_lia = ").append(newDaiRuKu);
|
|
|
+ }
|
|
|
+
|
|
|
+ sqlBuilder.append(" where id_ = '").append(ddzId.replace("'", "''")).append("'");
|
|
|
+ updateSqls.add(sqlBuilder.toString());
|
|
|
+ }
|
|
|
+
|
|
|
+ // ================= 4. 【第二阶段】执行批量更新 (公共逻辑) =================
|
|
|
+ if (!updateSqls.isEmpty()) {
|
|
|
+ logger.info("Operation [{}] check passed. Executing {} updates...", operate, updateSqls.size());
|
|
|
+ try {
|
|
|
+ for (String sql : updateSqls) {
|
|
|
+ commonDao.execute(sql);
|
|
|
+ }
|
|
|
+ logger.info("Operation [{}] completed successfully.", operate);
|
|
|
+ } catch (Exception e) {
|
|
|
+ logger.error("Error executing SQL for operation: {}", operate, e);
|
|
|
+ return "-1^数据库更新失败:" + e.getMessage();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return "1^success!";
|
|
|
+ }
|
|
|
+
|
|
|
+ public void deleteErrorRecord(String id) throws Exception {
|
|
|
+ if (id == null || id.trim().isEmpty()) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 解析ID列表 (支持逗号分隔)
|
|
|
+ List<String> idList = Arrays.stream(id.split(","))
|
|
|
+ .map(String::trim)
|
|
|
+ .filter(s -> !s.isEmpty())
|
|
|
+ .distinct()
|
|
|
+ .collect(Collectors.toList());
|
|
|
+
|
|
|
+ for (String singleId : idList) {
|
|
|
+ String safeId = singleId.replace("'", "''"); // 简单的SQL防注入处理
|
|
|
+
|
|
|
+ // 1. 先删子表 (t_sjhxhclrkysdjbzb),因为通常有外键约束或逻辑关联
|
|
|
+ // 条件:parent_id_ = singleId
|
|
|
+ String delSubSql = "DELETE FROM t_sjhxhclrkysdjbzb WHERE parent_id_ = '" + safeId + "'";
|
|
|
+ logger.debug("Executing delete sub-table SQL: {}", delSubSql);
|
|
|
+ commonDao.execute(delSubSql);
|
|
|
+
|
|
|
+ // 2. 再删主表 (t_sjhxhclrkysdjb)
|
|
|
+ // 条件:id_ = singleId
|
|
|
+ String delMainSql = "DELETE FROM t_sjhxhclrkysdjb WHERE id_ = '" + safeId + "'";
|
|
|
+ logger.debug("Executing delete main-table SQL: {}", delMainSql);
|
|
|
+ commonDao.execute(delMainSql);
|
|
|
+
|
|
|
+ logger.info("Successfully cleaned up error records for ID: {}", singleId);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+// ================= 辅助方法 =================
|
|
|
+
|
|
|
+ private double getDoubleValue(Object obj) {
|
|
|
+ if (obj == null) return 0.0;
|
|
|
+ if (obj instanceof Number) return ((Number) obj).doubleValue();
|
|
|
+ try {
|
|
|
+ String str = obj.toString().trim();
|
|
|
+ if (str.isEmpty()) return 0.0;
|
|
|
+ return Double.parseDouble(str);
|
|
|
+ } catch (NumberFormatException e) {
|
|
|
+ logger.warn("Failed to parse number from: {}", obj);
|
|
|
+ return 0.0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
+
|