package com.zy.third.erp.task; import com.alibaba.fastjson.JSON; import com.baomidou.mybatisplus.mapper.EntityWrapper; import com.core.exception.CoolException; import com.zy.asrs.entity.LocDetl; import com.zy.asrs.entity.LocDetlChangelog; import com.zy.asrs.entity.OrderDetl; import com.zy.asrs.entity.OrderDetlChangelog; import com.zy.asrs.mapper.LocDetlChangelogMapper; import com.zy.asrs.mapper.OrderDetlChangelogMapper; import com.zy.asrs.service.OrderDetlService; import com.zy.common.service.erp.ErpSqlServer; import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; import java.text.SimpleDateFormat; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; @Slf4j @Component public class ERPOrderDetlScheduler { @Autowired private ErpSqlServer erpSqlServer; @Autowired private OrderDetlService orderDetlService; @Autowired private OrderDetlChangelogMapper OrderDetlChangelogMapper; @Value("${erp.enabled}") private Boolean erpEnabled; @Transactional(rollbackFor = Throwable.class) @Scheduled(cron = "0 */30 * * * ?") public void ERPOrderDetlScheduler() { if (!erpEnabled) return; boolean result = false; List logs = OrderDetlChangelogMapper.selectUnprocessedLogs(); List orderDetlList = orderDetlService.selectList(new EntityWrapper<>()); // 获取主表所有数据 for (OrderDetl item : orderDetlList) { try { // 根据唯一标识 (order_no, matnr, out_order_no) 检查副表是否已有数据 boolean exists = checkIfExistsInErp(item); if (!exists) { // 如果副表中没有记录,插入新数据 insertIntoErp(item); } } catch (Exception e) { log.error("处理ERP同步失败,OrderDetl ID:" + item.getOrderNo(), e); } } for (OrderDetlChangelog changelog : logs) { try { String action = changelog.getActionType(); OrderDetl item = parseJsonToItem(changelog.getData()); Map content = locDetlToMap(item); switch (action) { case "UPDATE": try { // 解析 JSON Map dataMap = JSON.parseObject(changelog.getData(), Map.class); Map afterMap = (Map) dataMap.get("after"); // 拼接 UPDATE SQL StringBuilder setSql = new StringBuilder(); afterMap.forEach((k, v) -> { if (v == null) { setSql.append("[").append(k).append("]=NULL,"); } else if (v instanceof Number) { setSql.append("[").append(k).append("]=").append(v).append(","); } else { setSql.append("[").append(k).append("]='").append(((String)v).replace("'", "''")).append("',"); } }); setSql.deleteCharAt(setSql.length() - 1); // 去掉最后逗号 String updateSql = "UPDATE man_order_detl_erp SET " + setSql + " WHERE order_no='" + escapeSql((String)afterMap.get("order_no")) + "' AND out_order_no='" + escapeSql((String)afterMap.get("out_order_no")) + "' AND matnr='" + escapeSql((String)afterMap.get("matnr")) + "'"; if(erpSqlServer.update(updateSql) > 0){ log.info("同步ERP更新成功: orderNo={}, matnr={}", afterMap.get("order_no"), afterMap.get("matnr")); result = true; }else{ log.info("同步ERP更新失败: orderNo={}, matnr={}", afterMap.get("order_no"), afterMap.get("matnr")); } } catch (Exception e) { log.error("更新ERP失败: locNo=" + changelog.getOrderNo(), e); } break; case "DELETE": String deleteSql = "DELETE FROM man_order_detl_erp WHERE " + "order_no='" + escapeSql(item.getOrderNo()) + "' AND " + "out_order_no='" + escapeSql(item.getOutOrderNo()) + "' AND " + "matnr='" + escapeSql(item.getMatnr()) + "' AND " + "anfme=" + item.getAnfme(); if(erpSqlServer.update(deleteSql) > 0){ log.info("同步ERP删除成功: orderNo={},matnr={}", item.getOrderNo(),item.getMatnr()); result = true; }else{ log.info("同步ERP删除失败: orderNo={},matnr={}", item.getOrderNo(),item.getMatnr()); } break; default: log.error("未知操作类型:" + action); } if(result){ OrderDetlChangelogMapper.markProcessed(changelog.getId()); }else { throw new CoolException("同步失败"); } } catch (Exception e) { log.error("同步ERP失败,日志ID:" + changelog.getId(), e); } } } /** * 检查副表 man_order_detl_erp 是否已经存在此记录 */ private boolean checkIfExistsInErp(OrderDetl item) { String checkSql = "SELECT * FROM man_order_detl_erp WHERE order_no = '" + escapeSql(item.getOrderNo()) + "' AND " + "out_order_no = '" + escapeSql(item.getOutOrderNo()) + "' AND " + "matnr = '" + escapeSql(item.getMatnr()) + "'"; List> result = erpSqlServer.select(checkSql); // 使用 ErpSqlServer 查询副表是否已有记录 if (result != null && !result.isEmpty()) { return result.size() > 0; } return false; } /** * 插入数据到副表 man_order_detl_erp */ private void insertIntoErp(OrderDetl item) { Map content = locDetlToMap(item); // 将主表实体转换为Map String insertSql = buildInsertSql("man_order_detl_erp", content); if (erpSqlServer.update(insertSql) > 0) { log.info("同步ERP插入成功: orderNo={}, matnr={}", item.getOrderNo(), item.getMatnr()); } else { log.info("同步ERP插入失败: orderNo={}, matnr={}", item.getOrderNo(), item.getMatnr()); } } /** * 拼接 INSERT SQL */ private String buildInsertSql(String tableName, Map content) { StringBuilder columns = new StringBuilder(); StringBuilder values = new StringBuilder(); content.forEach((k, v) -> { columns.append("[").append(k).append("],"); values.append(toSqlValue(v)).append(","); }); columns.deleteCharAt(columns.length() - 1); // 去掉最后逗号 values.deleteCharAt(values.length() - 1); // 去掉最后逗号 return "INSERT INTO " + tableName + " (" + columns + ") VALUES (" + values + ")"; } /** 拼接 UPDATE SQL */ private String buildUpdateSql(String tableName, Map content, String whereClause) { StringBuilder setSql = new StringBuilder(); content.forEach((k, v) -> { setSql.append(k).append("=").append(toSqlValue(v)).append(","); }); setSql.deleteCharAt(setSql.length() - 1); return "UPDATE " + tableName + " SET " + setSql + " WHERE " + whereClause; } /** JSON 转实体 */ private OrderDetl parseJsonToItem(String dataJson) { return JSON.parseObject(dataJson, OrderDetl.class); } /** 转换为 SQL 可用的值 */ private String toSqlValue(Object value) { if (value == null) return "NULL"; if (value instanceof String) return "'" + escapeSql((String) value) + "'"; if (value instanceof Date) return "'" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format((Date) value) + "'"; return value.toString(); } /** SQL 注入简单转义 */ private String escapeSql(String str) { if (str == null) return ""; return str.replace("'", "''"); } /** 实体转 Map */ private Map locDetlToMap(OrderDetl item) { Map map = new HashMap<>(); map.put("order_no", item.getOrderNo()); map.put("out_order_no", item.getOutOrderNo()); map.put("matnr", item.getMatnr()); map.put("anfme",item.getAnfme()); map.put("qty",item.getQty()); map.put("maktx", item.getMaktx()); map.put("batch", item.getBatch()); map.put("specs", item.getSpecs()); map.put("model", item.getModel()); map.put("color", item.getColor()); map.put("brand", item.getBrand()); map.put("unit", item.getUnit()); map.put("price", item.getPrice()); map.put("sku", item.getSku()); map.put("units", item.getUnits()); map.put("barcode", item.getBarcode()); map.put("origin", item.getOrigin()); map.put("manu", item.getManu()); map.put("manu_date", item.getManuDate()); map.put("item_num", item.getItemNum()); map.put("safe_qty", item.getSafeQty()); map.put("weight", item.getWeight()); map.put("length", item.getLength()); map.put("volume", item.getVolume()); map.put("three_code", item.getThreeCode()); map.put("supp", item.getSupp()); map.put("supp_code", item.getSuppCode()); map.put("be_batch", item.getBeBatch()); map.put("dead_time", item.getDeadTime()); map.put("dead_warn", item.getDeadWarn()); map.put("source", item.getSource()); map.put("inspect", item.getInspect()); map.put("danger", item.getDanger()); map.put("status", item.getStatus()); map.put("create_by", item.getCreateBy()); map.put("create_time", item.getCreateTime()); map.put("update_by", item.getUpdateBy()); map.put("update_time", item.getUpdateTime()); map.put("memo", item.getMemo()); map.put("work_qty", item.getWorkQty()); map.put("auto_id", item.getAutoId()); map.put("lu_hao", item.getLuHao()); map.put("temp1", item.getTemp1()); map.put("temp2", item.getTemp2()); map.put("temp3", item.getTemp3()); map.put("ware_id", item.getWareId()); map.put("ware_name", item.getWareName()); map.put("packing", item.getPacking()); map.put("i_no", item.getINo()); map.put("pro_type", item.getProType()); return map; } }