Browse Source

2026-01-20

接口优化
master
fengyuan_yang 5 months ago
parent
commit
7c06b0216a
  1. 59
      src/main/java/com/gaotao/modules/crossAreaTransfer/service/impl/CrossAreaTransferServiceImpl.java
  2. 9
      src/main/java/com/gaotao/modules/erp/service/ErpInterfaceService.java
  3. 171
      src/main/java/com/gaotao/modules/erp/service/impl/ErpInterfaceServiceImpl.java
  4. 16
      src/main/resources/mapper/stock/StockTransactionLogDao.xml

59
src/main/java/com/gaotao/modules/crossAreaTransfer/service/impl/CrossAreaTransferServiceImpl.java

@ -180,24 +180,9 @@ public class CrossAreaTransferServiceImpl extends ServiceImpl<CrossAreaTransferM
// 获取出库返回的transNo用于入库时传递 // 获取出库返回的transNo用于入库时传递
String outboundTransNo = String.valueOf(outboundResult.get("transNo")); String outboundTransNo = String.valueOf(outboundResult.get("transNo"));
// 如果出库返回的synced_flag为'Y'则异步调用ERP接口
try {
String syncedFlag = String.valueOf(outboundResult.get("syncedFlag"));
if ("Y".equalsIgnoreCase(syncedFlag)) {
if (outboundTransNo != null && !outboundTransNo.isEmpty() && !"*".equals(outboundTransNo) && !"null".equals(outboundTransNo)) {
String returnSite = String.valueOf(outboundResult.get("Site"));
String returnBuNo = String.valueOf(outboundResult.get("buNo"));
logger.info("跨区调拨出库存储过程执行成功,synced_flag=Y,准备异步调用ERP接口,site={}, buNo={}, transNo={}",
returnSite, returnBuNo, outboundTransNo);
erpInterfaceService.asyncCallErpInterface(returnSite, returnBuNo, outboundTransNo);
}
} else {
logger.info("跨区调拨出库synced_flag不为'Y',不调用ERP接口,synced_flag={}", syncedFlag);
}
} catch (Exception e) {
logger.error("跨区调拨出库异步调用ERP接口触发失败(不影响主流程),错误: {}", e.getMessage(), e);
}
String outboundSyncedFlag = String.valueOf(outboundResult.get("syncedFlag"));
String returnSite = String.valueOf(outboundResult.get("Site"));
String returnBuNo = String.valueOf(outboundResult.get("buNo"));
// 3. 调用入库存储过程 GetSaveLabelVerification调拨入库 // 3. 调用入库存储过程 GetSaveLabelVerification调拨入库
// 入库时需要传递出库返回的transNo作为第三个参数 // 入库时需要传递出库返回的transNo作为第三个参数
@ -230,23 +215,35 @@ public class CrossAreaTransferServiceImpl extends ServiceImpl<CrossAreaTransferM
throw new RuntimeException(msg); throw new RuntimeException(msg);
} }
// 如果入库返回的synced_flag为'Y'则异步调用ERP接口
String inboundSyncedFlag = String.valueOf(inboundResult.get("syncedFlag"));
String inboundTransNo = String.valueOf(inboundResult.get("transNo"));
// 4. 按顺序异步调用ERP接口先出库后入库
// 使用链式调用确保顺序执行
try { try {
String inboundSyncedFlag = String.valueOf(inboundResult.get("syncedFlag"));
if ("Y".equalsIgnoreCase(inboundSyncedFlag)) {
String inboundTransNo = String.valueOf(inboundResult.get("transNo"));
if (inboundTransNo != null && !inboundTransNo.isEmpty() && !"*".equals(inboundTransNo) && !"null".equals(inboundTransNo)) {
String returnSite = String.valueOf(inboundResult.get("Site"));
String returnBuNo = String.valueOf(inboundResult.get("buNo"));
logger.info("跨区调拨入库存储过程执行成功,synced_flag=Y,准备异步调用ERP接口,site={}, buNo={}, transNo={}",
returnSite, returnBuNo, inboundTransNo);
erpInterfaceService.asyncCallErpInterface(returnSite, returnBuNo, inboundTransNo);
}
boolean needCallOutboundErp = "Y".equalsIgnoreCase(outboundSyncedFlag)
&& outboundTransNo != null && !outboundTransNo.isEmpty()
&& !"*".equals(outboundTransNo) && !"null".equals(outboundTransNo);
boolean needCallInboundErp = "Y".equalsIgnoreCase(inboundSyncedFlag)
&& inboundTransNo != null && !inboundTransNo.isEmpty()
&& !"*".equals(inboundTransNo) && !"null".equals(inboundTransNo);
if (needCallOutboundErp || needCallInboundErp) {
logger.info("跨区调拨需要调用ERP接口 - 出库: {}, 入库: {}", needCallOutboundErp, needCallInboundErp);
// 调用顺序ERP接口服务
erpInterfaceService.asyncCallErpInterfaceSequentially(
returnSite, returnBuNo,
needCallOutboundErp ? outboundTransNo : null,
needCallInboundErp ? inboundTransNo : null
);
} else { } else {
logger.info("跨区调拨入库synced_flag不为'Y',不调用ERP接口,synced_flag={}", inboundSyncedFlag);
logger.info("跨区调拨不需要调用ERP接口 - 出库synced_flag: {}, 入库synced_flag: {}",
outboundSyncedFlag, inboundSyncedFlag);
} }
} catch (Exception e) { } catch (Exception e) {
logger.error("跨区调拨入库异步调用ERP接口触发失败(不影响主流程),错误: {}", e.getMessage(), e);
logger.error("跨区调拨异步调用ERP接口触发失败(不影响主流程),错误: {}", e.getMessage(), e);
} }
logger.info("跨区调拨保存成功,模式: {}, 扫描码: {}, 源库位: {}, 目标库位: {}", transferMode, scanCode, sourceLocation, targetLocation); logger.info("跨区调拨保存成功,模式: {}, 扫描码: {}, 源库位: {}, 目标库位: {}", transferMode, scanCode, sourceLocation, targetLocation);

9
src/main/java/com/gaotao/modules/erp/service/ErpInterfaceService.java

@ -12,6 +12,15 @@ public interface ErpInterfaceService {
* @param transactionId 事务ID * @param transactionId 事务ID
*/ */
void asyncCallErpInterface(String site, String buNo, String transactionId); void asyncCallErpInterface(String site, String buNo, String transactionId);
/**
* 按顺序异步调用ERP接口用于跨区调拨等需要保证顺序的场景
* @param site 工厂
* @param buNo BU编号
* @param outboundTransactionId 出库事务ID如果为null则跳过
* @param inboundTransactionId 入库事务ID如果为null则跳过
*/
void asyncCallErpInterfaceSequentially(String site, String buNo, String outboundTransactionId, String inboundTransactionId);
} }

171
src/main/java/com/gaotao/modules/erp/service/impl/ErpInterfaceServiceImpl.java

@ -187,9 +187,6 @@ public class ErpInterfaceServiceImpl implements ErpInterfaceService {
} else if ("GetSaveroductionIn".equals(interfaceName)) { } else if ("GetSaveroductionIn".equals(interfaceName)) {
// 生产入库 // 生产入库
requestBody = buildProductionInRequestBody(transactionLogs, interfaceName); requestBody = buildProductionInRequestBody(transactionLogs, interfaceName);
} else {
// 默认格式
//requestBody = buildDefaultRequestBody(transactionLogs, interfaceName);
} }
return requestBody; return requestBody;
@ -203,7 +200,7 @@ public class ErpInterfaceServiceImpl implements ErpInterfaceService {
Map<String, Object> requestBody = new LinkedHashMap<>(); Map<String, Object> requestBody = new LinkedHashMap<>();
// 主表字段 // 主表字段
requestBody.put("MESCCode", nullToEmpty(firstLog.getDocumentNo()));
requestBody.put("MESCCode", nullToEmpty(firstLog.getTransactionId()));
requestBody.put("KdType", getKdType(interfaceName)); requestBody.put("KdType", getKdType(interfaceName));
requestBody.put("DDate", formatDate(firstLog.getTransactionDate())); requestBody.put("DDate", formatDate(firstLog.getTransactionDate()));
requestBody.put("CRdCode", nullToEmpty(firstLog.getDocumentNoType())); requestBody.put("CRdCode", nullToEmpty(firstLog.getDocumentNoType()));
@ -248,7 +245,7 @@ public class ErpInterfaceServiceImpl implements ErpInterfaceService {
Map<String, Object> requestBody = new LinkedHashMap<>(); Map<String, Object> requestBody = new LinkedHashMap<>();
// 主表字段 // 主表字段
requestBody.put("MESCCode", nullToEmpty(firstLog.getDocumentNo()));
requestBody.put("MESCCode", nullToEmpty(firstLog.getTransactionId()));
requestBody.put("KdType", getKdType(interfaceName)); requestBody.put("KdType", getKdType(interfaceName));
requestBody.put("DDate", formatDate(firstLog.getTransactionDate())); requestBody.put("DDate", formatDate(firstLog.getTransactionDate()));
requestBody.put("CBusType", ""); requestBody.put("CBusType", "");
@ -327,7 +324,7 @@ public class ErpInterfaceServiceImpl implements ErpInterfaceService {
Map<String, Object> requestBody = new LinkedHashMap<>(); Map<String, Object> requestBody = new LinkedHashMap<>();
// 主表字段 // 主表字段
requestBody.put("MESCCode", nullToEmpty(firstLog.getDocumentNo()));
requestBody.put("MESCCode", nullToEmpty(firstLog.getTransactionId()));
requestBody.put("KdType", getKdType(interfaceName)); requestBody.put("KdType", getKdType(interfaceName));
requestBody.put("DDate", formatDate(firstLog.getTransactionDate())); requestBody.put("DDate", formatDate(firstLog.getTransactionDate()));
requestBody.put("CWhCode", nullToEmpty(firstLog.getWarehouseId())); requestBody.put("CWhCode", nullToEmpty(firstLog.getWarehouseId()));
@ -363,7 +360,7 @@ public class ErpInterfaceServiceImpl implements ErpInterfaceService {
Map<String, Object> requestBody = new LinkedHashMap<>(); Map<String, Object> requestBody = new LinkedHashMap<>();
// 主表字段 // 主表字段
requestBody.put("MESCCode", nullToEmpty(firstLog.getDocumentNo()));
requestBody.put("MESCCode", nullToEmpty(firstLog.getTransactionId()));
requestBody.put("DDate", formatDate(firstLog.getTransactionDate())); requestBody.put("DDate", formatDate(firstLog.getTransactionDate()));
requestBody.put("CDepCode", nullToEmpty(firstLog.getDepartmentId())); requestBody.put("CDepCode", nullToEmpty(firstLog.getDepartmentId()));
requestBody.put("CRdCode", nullToEmpty(firstLog.getDocumentNoType())); requestBody.put("CRdCode", nullToEmpty(firstLog.getDocumentNoType()));
@ -392,45 +389,6 @@ public class ErpInterfaceServiceImpl implements ErpInterfaceService {
return requestBody; return requestBody;
} }
/**
* 默认请求参数格式
*/
private Map<String, Object> buildDefaultRequestBody(List<StockTransactionLogEntity> transactionLogs, String interfaceName) {
StockTransactionLogEntity firstLog = transactionLogs.get(0);
Map<String, Object> requestBody = new LinkedHashMap<>();
// 主表字段
requestBody.put("MESCCode", nullToEmpty(firstLog.getDocumentNo()));
requestBody.put("KdType", getKdType(interfaceName));
requestBody.put("DDate", formatDate(firstLog.getTransactionDate()));
requestBody.put("CRdCode", nullToEmpty(firstLog.getDocumentNoType()));
requestBody.put("CMemo", "");
requestBody.put("CWhCode", nullToEmpty(firstLog.getWarehouseId()));
requestBody.put("CCusOAddress", "");
requestBody.put("CDepCode", nullToEmpty(firstLog.getDepartmentId()));
// 明细列表
List<Map<String, Object>> detailList = new ArrayList<>();
for (StockTransactionLogEntity log : transactionLogs) {
Map<String, Object> detail = new LinkedHashMap<>();
detail.put("MESIrowNo", String.valueOf(log.getRowNo()));
detail.put("OutCode", nullToEmpty(log.getOrderNo()));
detail.put("OutIrowNo", nullToEmpty(log.getOrderLineNo()));
detail.put("CInvCode", nullToEmpty(log.getPartNo()));
detail.put("IQuantity", log.getRollQty() != null ? log.getRollQty().toString() : "0");
detail.put("CBatch", nullToEmpty(log.getBatchFlag()));
detail.put("CbMemo", "");
detail.put("CWhCode", nullToEmpty(log.getWarehouseId()));
detail.put("OutMocode", nullToEmpty(log.getOrderNo()));
detail.put("OutIrowNo_zj", nullToEmpty(log.getBomItemNo()));
detail.put("NumberOfCases", "");
detailList.add(detail);
}
requestBody.put("DetailList", detailList);
return requestBody;
}
/** /**
* 将null转换为空字符串 * 将null转换为空字符串
*/ */
@ -684,6 +642,127 @@ public class ErpInterfaceServiceImpl implements ErpInterfaceService {
return detailEntity; return detailEntity;
} }
/**
* 按顺序异步调用ERP接口用于跨区调拨等需要保证顺序的场景
* 先调用出库接口等待完成后再调用入库接口
*/
@Async("erpInterfaceExecutor")
@Override
public void asyncCallErpInterfaceSequentially(String site, String buNo, String outboundTransactionId, String inboundTransactionId) {
logger.info("开始按顺序异步调用ERP接口 - site: {}, buNo: {}, 出库transactionId: {}, 入库transactionId: {}",
site, buNo, outboundTransactionId, inboundTransactionId);
try {
// 1. 先调用出库接口如果需要
if (outboundTransactionId != null && !outboundTransactionId.trim().isEmpty()) {
logger.info("【顺序调用-步骤1】开始调用出库ERP接口 - transactionId: {}", outboundTransactionId);
callErpInterfaceSync(site, buNo, outboundTransactionId);
logger.info("【顺序调用-步骤1】出库ERP接口调用完成 - transactionId: {}", outboundTransactionId);
} else {
logger.info("【顺序调用-步骤1】跳过出库ERP接口调用(transactionId为空)");
}
// 2. 再调用入库接口如果需要
if (inboundTransactionId != null && !inboundTransactionId.trim().isEmpty()) {
logger.info("【顺序调用-步骤2】开始调用入库ERP接口 - transactionId: {}", inboundTransactionId);
callErpInterfaceSync(site, buNo, inboundTransactionId);
logger.info("【顺序调用-步骤2】入库ERP接口调用完成 - transactionId: {}", inboundTransactionId);
} else {
logger.info("【顺序调用-步骤2】跳过入库ERP接口调用(transactionId为空)");
}
logger.info("按顺序异步调用ERP接口全部完成 - site: {}, buNo: {}", site, buNo);
} catch (Exception e) {
logger.error("按顺序异步调用ERP接口失败 - site: {}, buNo: {}, error: {}", site, buNo, e.getMessage(), e);
}
}
/**
* 同步调用ERP接口内部方法用于顺序调用
* 这个方法不使用@Async注解确保在调用线程中同步执行
*/
private void callErpInterfaceSync(String site, String buNo, String transactionId) {
logger.info("同步调用ERP接口 - site: {}, buNo: {}, transactionId: {}", site, buNo, transactionId);
try {
// 1. 查询StockTransactionLog数据
List<StockTransactionLogEntity> transactionLogs = stockTransactionLogDao.queryByTransactionId(site, buNo, transactionId);
if (transactionLogs == null || transactionLogs.isEmpty()) {
logger.warn("未找到事务记录 - transactionId: {}", transactionId);
return;
}
// 取第一条记录作为主表数据
StockTransactionLogEntity firstLog = transactionLogs.get(0);
String interfaceName = firstLog.getInterfaceName();
if (interfaceName == null || interfaceName.trim().isEmpty()) {
logger.warn("接口名称为空 - transactionId: {}", transactionId);
return;
}
// 2. 获取接口地址
ApiInterfaceEntity apiInterface = apiInterfaceDao.getByInterfaceName(site, buNo, interfaceName);
if (apiInterface == null) {
logger.error("未找到接口配置 - interfaceName: {}", interfaceName);
saveFailureLog(site, buNo, transactionId, interfaceName, transactionLogs, "未找到接口配置");
return;
}
String interfaceUrl = "http://" + apiInterface.getInterfaceIp() + apiInterface.getInterfaceValue();
logger.info("接口地址: {}", interfaceUrl);
// 3. 组装接口参数
Map<String, Object> requestBody = buildRequestBody(transactionLogs);
String requestJson = JSON.toJSONString(requestBody);
logger.info("请求参数: {}", requestJson);
// 4. 调用ERP接口
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity<String> requestEntity = new HttpEntity<>(requestJson, headers);
try {
ResponseEntity<String> response = restTemplate.exchange(
interfaceUrl,
HttpMethod.POST,
requestEntity,
String.class
);
String responseBody = response.getBody();
logger.info("接口返回: {}", responseBody);
// 5. 解析返回结果
JSONObject jsonResponse = JSON.parseObject(responseBody);
String flag = jsonResponse.getString("Flag");
if ("success".equalsIgnoreCase(flag)) {
// 成功更新StockTransactionLog
String u8CCode = jsonResponse.getString("U8CCode");
logger.info("ERP接口调用成功 - U8单号: {}", u8CCode);
stockTransactionLogDao.updateSyncedSuccess(site, buNo, transactionId);
} else {
// 失败记录到api_log
String errMsg = jsonResponse.getString("ErrMsg");
logger.error("ERP接口调用失败 - 错误: {}", errMsg);
saveFailureLog(site, buNo, transactionId, interfaceName, transactionLogs, errMsg);
}
} catch (Exception e) {
logger.error("调用ERP接口异常 - transactionId: {}, error: {}", transactionId, e.getMessage(), e);
saveFailureLog(site, buNo, transactionId, interfaceName, transactionLogs, "接口调用异常: " + e.getMessage());
}
} catch (Exception e) {
logger.error("同步调用ERP接口失败 - transactionId: {}, error: {}", transactionId, e.getMessage(), e);
}
}
/** /**
* 格式化日期 * 格式化日期
*/ */

16
src/main/resources/mapper/stock/StockTransactionLogDao.xml

@ -5,8 +5,7 @@
<!-- 根据transaction_id查询事务记录列表 --> <!-- 根据transaction_id查询事务记录列表 -->
<select id="queryByTransactionId" resultType="com.gaotao.modules.stock.entity.StockTransactionLogEntity"> <select id="queryByTransactionId" resultType="com.gaotao.modules.stock.entity.StockTransactionLogEntity">
SELECT
id,
SELECT
transaction_id AS transactionId, transaction_id AS transactionId,
site, site,
bu_no AS buNo, bu_no AS buNo,
@ -15,8 +14,7 @@
order_line_no AS orderLineNo, order_line_no AS orderLineNo,
order_no AS orderNo, order_no AS orderNo,
part_no AS partNo, part_no AS partNo,
roll_no AS rollNo,
roll_qty AS rollQty,
sum(roll_qty) AS rollQty, -- 数量
transaction_type AS transactionType, transaction_type AS transactionType,
warehouse_id AS warehouseId, warehouse_id AS warehouseId,
location_id AS locationId, location_id AS locationId,
@ -34,14 +32,18 @@
umid, umid,
interface_name AS interfaceName, interface_name AS interfaceName,
batch_flag AS batchFlag, batch_flag AS batchFlag,
piece_qty as pieceQty,
sum(piece_qty) as pieceQty, -- 件数
erp_order_no AS erpOrderNo, erp_order_no AS erpOrderNo,
row_no as rowNo
ROW_NUMBER() OVER (ORDER BY document_no, batch_flag) as rowNo
FROM StockTransactionLog WITH(NOLOCK) FROM StockTransactionLog WITH(NOLOCK)
WHERE site = #{site} WHERE site = #{site}
AND bu_no = #{buNo} AND bu_no = #{buNo}
AND transaction_id = #{transactionId} AND transaction_id = #{transactionId}
ORDER BY id ASC
group by
transaction_id,site, bu_no , document_type , document_no , order_line_no , order_no , part_no , transaction_type ,
warehouse_id , location_id , transaction_date , transaction_by , orderref1, orderref2, remarks,
synced_flag , synced_time , synced_error_msg , department_id , document_no_type , bom_item_no ,
umid, interface_name , batch_flag ,erp_order_no
</select> </select>
<!-- 批量更新同步状态为成功 --> <!-- 批量更新同步状态为成功 -->

Loading…
Cancel
Save