From 9c22135c6767876687db0959163ac13ea0182907 Mon Sep 17 00:00:00 2001
From: cl <1442464845@qq.com>
Date: 星期六, 04 四月 2026 00:36:22 +0800
Subject: [PATCH] 序号控制
---
src/main/java/com/zy/api/service/impl/WcsApiServiceImpl.java | 813 +++++++++++++++++++++++++++++++++++++++++++++++++++++----
1 files changed, 750 insertions(+), 63 deletions(-)
diff --git a/src/main/java/com/zy/api/service/impl/WcsApiServiceImpl.java b/src/main/java/com/zy/api/service/impl/WcsApiServiceImpl.java
index c76c863..5d658fb 100644
--- a/src/main/java/com/zy/api/service/impl/WcsApiServiceImpl.java
+++ b/src/main/java/com/zy/api/service/impl/WcsApiServiceImpl.java
@@ -1,6 +1,7 @@
package com.zy.api.service.impl;
import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.core.common.Cools;
@@ -9,6 +10,9 @@
import com.zy.api.controller.params.ReceviceTaskParams;
import com.zy.api.controller.params.StopOutTaskParams;
import com.zy.api.controller.params.WorkTaskParams;
+import com.zy.api.entity.CrnProtocol;
+import com.zy.api.entity.DeviceStatusVo;
+import com.zy.api.entity.StationProtocol;
import com.zy.api.service.WcsApiService;
import com.zy.asrs.entity.*;
import com.zy.asrs.service.*;
@@ -24,22 +28,29 @@
import org.springframework.transaction.annotation.Transactional;
import java.io.IOException;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
-import java.util.Objects;
-import java.util.Set;
+import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
@Slf4j
@Service
public class WcsApiServiceImpl implements WcsApiService {
+ private static final Long WCS_SYNC_USER = 9999L;
+ private static final String YES = "Y";
+ private static final String NO = "N";
+
+ /** 鍚屼竴 WCS 璺緞銆佸悓涓�鍗曞彿涓嬩竴缁勪笅鍙戠殑浠诲姟鏉℃暟涓婇檺 */
+ private static final int WCS_PUB_BATCH_SIZE = 20;
+
+ /** 涓夋柟鎺ュ彛缁熻锛氭湰绯荤粺璋冪敤 WCS 鐨� namespace 绾﹀畾 */
+ private static final String NS_WMS_TO_WCS = "鏈郴缁熻姹俉CS";
@Autowired
private LocMastService locMastService;
@Autowired
private WrkMastService wrkMastService;
+ @Autowired
+ private WrkMastLogService wrkMastLogService;
@Autowired
private WorkService workService;
@Autowired
@@ -65,8 +76,20 @@
@Value("${wcs.address.stopOutTask}")
private String stopOutTask;
+ @Value("${wcs.address.getDeviceStatus:/openapi/getDeviceStatus}")
+ private String getDeviceStatus;
+ @Value("${wcs.address.queryTask:/openapi/queryTask}")
+ private String queryTaskPath;
+ @Value("${wcs.status-sync.method:GET}")
+ private String deviceStatusMethod;
@Autowired
private CommonService commonService;
+ @Autowired
+ private BasDevpService basDevpService;
+ @Autowired
+ private BasCrnpService basCrnpService;
+ @Autowired
+ private ApiLogService apiLogService;
/**
@@ -79,68 +102,409 @@
*/
@Override
public R pubWrkToWcs(WorkTaskParams params) {
- if (Objects.isNull(params.getTaskNo())) {
- return R.error("浠诲姟鍙蜂笉鑳戒负绌猴紒锛�");
+ if (params == null) {
+ return R.error("鍙傛暟涓嶈兘涓虹┖锛侊紒");
}
- if (Objects.isNull(params.getBarcode())) {
- return R.error("鎵樼洏鐮佷笉鑳戒负绌猴紒锛�");
- }
- if (Objects.isNull(params.getLocNo())) {
- return R.error("鐩爣搴撲綅涓嶈兘涓虹┖锛侊紒");
- }
- String url = createInTask;
- if (!Objects.isNull(params.getType()) && params.getType().equals("out")) {
- url = getWcs_address;
- }else if (!Objects.isNull(params.getType()) && params.getType().equals("move")) {
- url = createLocMoveTask;
- }
- String response;
- R r = R.ok();
WrkMast wrkMast = wrkMastService.selectOne(new EntityWrapper<WrkMast>().eq("wrk_no", params.getTaskNo()));
- if (!Objects.isNull(wrkMast) && "out".equalsIgnoreCase(params.getType())) {
- if ("Y".equalsIgnoreCase(wrkMast.getPauseMk())) {
- return R.error("task paused");
- }
- if (requiresOutboundErpConfirm(wrkMast) && !"Y".equalsIgnoreCase(wrkMast.getPdcType())) {
- return R.error("task not confirmed by erp");
- }
+ String validateMsg = validatePubTask(params, wrkMast);
+ if (!Cools.isEmpty(validateMsg)) {
+ return R.error(validateMsg);
}
+ String url = resolveTaskPath(params);
+ String requestJson = JSON.toJSONString(params);
+ String response = null;
+ R r = R.ok();
+ Throwable wcsThrown = null;
+ boolean wcsBizOk = false;
try {
log.info("涓嬪彂鎼繍浠诲姟缁檞cs="+JSON.toJSONString(params));
response = new HttpHandler.Builder()
.setUri(wcs_address)
.setPath(url)
- .setJson(JSON.toJSONString(params))
+ .setHttps(wcs_address != null && wcs_address.startsWith("https://"))
+ .setTimeout(10, TimeUnit.SECONDS)
+ .setJson(requestJson)
.build()
.doPost();
JSONObject jsonObject = JSON.parseObject(response);
log.info("涓嬪彂浠诲姟缁檞cs鐨勮繑鍥炲��="+response);
Integer code = jsonObject.getInteger("code");
+ wcsBizOk = code != null && code == 200;
if (code==200) {
- if (!Objects.isNull(wrkMast)) {
- if (wrkMast.getIoType()==1 || wrkMast.getIoType()==10) {
- wrkMast.setWrkSts(2L);
- wrkMast.setModiTime(new Date());
- wrkMastService.updateById(wrkMast);
- }else if(wrkMast.getIoType()==2){
- wrkMast.setWrkSts(2L);
- wrkMast.setModiTime(new Date());
- wrkMastService.updateById(wrkMast);
- }else if (wrkMast.getIoType()==101 || wrkMast.getIoType()==110) {
- wrkMast.setWrkSts(12L);
- wrkMast.setModiTime(new Date());
- wrkMastService.updateById(wrkMast);
- }
- }
+ updateWrkMastAfterPublish(wrkMast);
//TODO 涓婃姤鏄惁鎴愬姛
}else {
r =R.error();
}
} catch (IOException e) {
+ wcsThrown = e;
throw new RuntimeException(e);
+ } finally {
+ logWcsToApiLog(url, requestJson, response, wcsThrown, wcsBizOk);
}
return r;
+ }
+
+ @Override
+ public R pubWrksToWcs(List<WorkTaskParams> paramsList) {
+ if (paramsList == null || paramsList.isEmpty()) {
+ return R.error("浠诲姟涓嶈兘涓虹┖锛侊紒");
+ }
+
+ Map<String, WrkMast> wrkMastMap = getWrkMastMap(paramsList);
+ List<WorkTaskParams> accepted = new ArrayList<>();
+ List<String> skipMsgs = new ArrayList<>();
+
+ for (WorkTaskParams params : paramsList) {
+ if (params == null) {
+ skipMsgs.add("浠诲姟涓嶈兘涓虹┖锛侊紒");
+ continue;
+ }
+ WrkMast wrkMast = wrkMastMap.get(params.getTaskNo());
+ String validateMsg = validatePubTask(params, wrkMast);
+ if (!Cools.isEmpty(validateMsg)) {
+ skipMsgs.add(buildTaskMsg(params, validateMsg));
+ continue;
+ }
+ accepted.add(params);
+ }
+
+ if (accepted.isEmpty()) {
+ return R.error(skipMsgs.isEmpty() ? "鏃犲彲涓嬪彂浠诲姟" : skipMsgs.get(0)).add(skipMsgs);
+ }
+
+ accepted = filterOutboundByContiguousPlt(accepted, wrkMastMap, skipMsgs);
+ if (accepted.isEmpty()) {
+ return R.error(skipMsgs.isEmpty() ? "鏃犲彲涓嬪彂浠诲姟" : skipMsgs.get(0)).add(skipMsgs);
+ }
+
+ accepted.sort(pubWcsSortComparator(wrkMastMap));
+ List<List<WorkTaskParams>> chunks = buildPubChunks(accepted, wrkMastMap);
+
+ int successCount = 0;
+ List<String> failMsgs = new ArrayList<>();
+ List<WorkTaskParams> lastSentChunk = null;
+ String skipGroupKey = null;
+
+ for (List<WorkTaskParams> chunk : chunks) {
+ if (chunk == null || chunk.isEmpty()) {
+ continue;
+ }
+ WorkTaskParams head = chunk.get(0);
+ WrkMast headMast = wrkMastMap.get(head.getTaskNo());
+ String key = buildBatchGroupKey(head, headMast);
+
+ if (skipGroupKey != null && skipGroupKey.equals(key)) {
+ continue;
+ }
+
+ if (!outboundChunkPredecessorPltReady(chunk, wrkMastMap)) {
+ skipGroupKey = key;
+ continue;
+ }
+
+ if (lastSentChunk != null) {
+ WorkTaskParams lastHead = lastSentChunk.get(0);
+ String lastKey = buildBatchGroupKey(lastHead, wrkMastMap.get(lastHead.getTaskNo()));
+ if (lastKey.equals(key)) {
+ if (!sameOrderNextChunkAllowed(lastSentChunk)) {
+ skipGroupKey = key;
+ continue;
+ }
+ }
+ if (!sleepOneMinuteBeforeNextChunk()) {
+ break;
+ }
+ }
+
+ int ok = postWcsBatchChunk(chunk, wrkMastMap, failMsgs);
+ if (ok <= 0) {
+ skipGroupKey = key;
+ continue;
+ }
+ successCount += ok;
+ lastSentChunk = chunk;
+ }
+
+ Map<String, Object> result = new HashMap<>();
+ result.put("successCount", successCount);
+ result.put("skipCount", skipMsgs.size());
+ result.put("failCount", failMsgs.size());
+ if (!skipMsgs.isEmpty()) {
+ result.put("skipMsgs", skipMsgs);
+ }
+ if (!failMsgs.isEmpty()) {
+ result.put("failMsgs", failMsgs);
+ }
+
+ if (successCount == 0) {
+ String msg = !failMsgs.isEmpty() ? failMsgs.get(0) : (skipMsgs.isEmpty() ? "WCS涓嬪彂浠诲姟澶辫触" : skipMsgs.get(0));
+ return R.error(msg).add(result);
+ }
+ return R.ok(failMsgs.isEmpty() && skipMsgs.isEmpty() ? "鎿嶄綔鎴愬姛" : "閮ㄥ垎浠诲姟涓嬪彂鎴愬姛").add(result);
+ }
+
+ private int postWcsBatchChunk(List<WorkTaskParams> chunk, Map<String, WrkMast> wrkMastMap, List<String> failMsgs) {
+ if (chunk == null || chunk.isEmpty()) {
+ return 0;
+ }
+ String path = resolveTaskPath(chunk.get(0));
+ Map<String, Object> payload = new HashMap<>();
+ payload.put("taskList", buildTaskPayloads(chunk));
+ String requestJson = JSON.toJSONString(payload);
+ String response = null;
+ Throwable wcsThrown = null;
+ boolean wcsBizOk = false;
+ try {
+ log.info("鎵归噺涓嬪彂鎼繍浠诲姟缁檞cs={}", requestJson);
+ response = new HttpHandler.Builder()
+ .setUri(wcs_address)
+ .setPath(path)
+ .setTimeout(60, TimeUnit.SECONDS)
+ .setJson(requestJson)
+ .build()
+ .doPost();
+ JSONObject jsonObject = JSON.parseObject(response == null ? "{}" : response);
+ log.info("鎵归噺涓嬪彂浠诲姟缁檞cs鐨勮繑鍥炲��={}", response);
+ Integer code = jsonObject.getInteger("code");
+ wcsBizOk = code != null && code == 200;
+ if (wcsBizOk) {
+ for (WorkTaskParams params : chunk) {
+ updateWrkMastAfterPublish(wrkMastMap.get(params.getTaskNo()));
+ }
+ return chunk.size();
+ }
+ String msg = jsonObject.getString("msg");
+ failMsgs.add("path=" + path + ", msg=" + (Cools.isEmpty(msg) ? "WCS涓嬪彂浠诲姟澶辫触" : msg));
+ log.error("鎵归噺涓嬪彂浠诲姟缁檞cs澶辫触, path:{}, request:{}, response:{}", path, requestJson, response);
+ } catch (IOException e) {
+ wcsThrown = e;
+ failMsgs.add("path=" + path + ", msg=" + e.getMessage());
+ log.error("鎵归噺涓嬪彂浠诲姟缁檞cs寮傚父, path:{}, request:{}, response:{}", path, requestJson, response, e);
+ } finally {
+ logWcsToApiLog(path, requestJson, response, wcsThrown, wcsBizOk);
+ }
+ return 0;
+ }
+
+ /**
+ * 鍑哄簱锛氫粎褰撳崟鍙枫�佸簭鍙峰潎鏈夋晥鏃跺仛璺冲彿鏍¢獙锛涘崟鍙风┖鎴栧簭鍙锋棤鏁堜粛涓嬪彂銆傚叆搴�/绉诲簱涓嶅鐞嗐��
+ */
+ private List<WorkTaskParams> filterOutboundByContiguousPlt(List<WorkTaskParams> accepted, Map<String, WrkMast> wrkMastMap, List<String> skipMsgs) {
+ Map<String, Integer> reachCache = new HashMap<>();
+ List<WorkTaskParams> kept = new ArrayList<>();
+ for (WorkTaskParams p : accepted) {
+ if (!"out".equalsIgnoreCase(p.getType())) {
+ kept.add(p);
+ continue;
+ }
+ WrkMast w = wrkMastMap.get(p.getTaskNo());
+ String userNo = sortUserNoForPub(p, w);
+ Integer plt = sortPltForPub(p, w);
+ if (Cools.isEmpty(userNo) || plt == null || plt <= 0) {
+ kept.add(p);
+ continue;
+ }
+ int maxReach = reachCache.computeIfAbsent(userNo, wrkMastService::outboundSeqMaxContiguousPlt);
+ if (plt > maxReach) {
+ skipMsgs.add(buildTaskMsg(p, "鍑哄簱搴忓彿璺冲彿锛岃烦杩�"));
+ continue;
+ }
+ kept.add(p);
+ }
+ return kept;
+ }
+
+ private List<List<WorkTaskParams>> buildPubChunks(List<WorkTaskParams> accepted, Map<String, WrkMast> wrkMastMap) {
+ List<List<WorkTaskParams>> chunks = new ArrayList<>();
+ int index = 0;
+ while (index < accepted.size()) {
+ WorkTaskParams head = accepted.get(index);
+ WrkMast headMast = wrkMastMap.get(head.getTaskNo());
+ String headGroupKey = buildBatchGroupKey(head, headMast);
+ List<WorkTaskParams> chunk = new ArrayList<>();
+ while (index < accepted.size() && chunk.size() < WCS_PUB_BATCH_SIZE) {
+ WorkTaskParams cur = accepted.get(index);
+ WrkMast curMast = wrkMastMap.get(cur.getTaskNo());
+ if (!headGroupKey.equals(buildBatchGroupKey(cur, curMast))) {
+ break;
+ }
+ chunk.add(cur);
+ index++;
+ }
+ chunks.add(chunk);
+ }
+ return chunks;
+ }
+
+ private boolean sleepOneMinuteBeforeNextChunk() {
+ try {
+ TimeUnit.MINUTES.sleep(1);
+ return true;
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
+ log.warn("鎵归噺涓嬪彂WCS缁勯棿绛夊緟琚腑鏂�", e);
+ return false;
+ }
+ }
+
+ /**
+ * 鍚屽崟涓嬩竴缁勶細浼樺厛 WCS queryTask锛涘け璐ユ垨鏃犳暟鎹垯涓昏〃宸查潪 11 鎴栧凡杩涘巻鍙茶〃銆�
+ */
+ private boolean sameOrderNextChunkAllowed(List<WorkTaskParams> lastSentChunk) {
+ if (lastSentChunk == null || lastSentChunk.isEmpty()) {
+ return false;
+ }
+ if (!Boolean.parseBoolean(String.valueOf(switchValue))) {
+ return true;
+ }
+ WorkTaskParams last = lastSentChunk.get(lastSentChunk.size() - 1);
+ if (last != null && !Cools.isEmpty(last.getTaskNo()) && wcsQueryTaskShowsTask(last.getTaskNo())) {
+ return true;
+ }
+ if (last != null && !Cools.isEmpty(last.getTaskNo())) {
+ log.info("WCS queryTask 鏃犳暟鎹垨澶辫触锛屽洖閫� WMS 涓昏〃/鍘嗗彶鏍¢獙, taskNo={}", last.getTaskNo());
+ }
+ return previousChunkTasksReleasedInWms(lastSentChunk);
+ }
+
+ private boolean wcsQueryTaskShowsTask(String taskNo) {
+ Map<String, Object> body = new HashMap<>();
+ body.put("taskNo", taskNo);
+ try {
+ String response = new HttpHandler.Builder()
+ .setUri(wcs_address)
+ .setPath(queryTaskPath)
+ .setHttps(wcs_address != null && wcs_address.startsWith("https://"))
+ .setTimeout(60, TimeUnit.SECONDS)
+ .setJson(JSON.toJSONString(body))
+ .build()
+ .doPost();
+ JSONObject jo = JSON.parseObject(response == null ? "{}" : response);
+ Integer code = jo.getInteger("code");
+ return code != null && code == 200 && queryTaskDataNonEmpty(jo.get("data"));
+ } catch (IOException e) {
+ log.warn("WCS queryTask 寮傚父, taskNo={}", taskNo, e);
+ return false;
+ }
+ }
+
+ /**
+ * 涓婁竴缁勬瘡鏉★細涓昏〃鏃犲垯鐪嬪巻鍙茶〃锛涗富琛ㄦ湁鍒� wrk_sts 涓嶈兘浠嶄负 11銆�
+ */
+ private boolean previousChunkTasksReleasedInWms(List<WorkTaskParams> chunk) {
+ for (WorkTaskParams p : chunk) {
+ if (p == null || Cools.isEmpty(p.getTaskNo())) {
+ return false;
+ }
+ Integer wrkNo = Integer.valueOf(p.getTaskNo());
+ WrkMast m = wrkMastService.selectById(wrkNo);
+ if (m == null) {
+ int logCnt = wrkMastLogService.selectCount(new EntityWrapper<WrkMastLog>().eq("wrk_no", wrkNo));
+ if (logCnt <= 0) {
+ return false;
+ }
+ } else if (m.getWrkSts() != null && Objects.equals(m.getWrkSts(), 11L)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ /**
+ * 鍑哄簱姣忕粍涓嬪彂鍓嶏細鏈粍鏈夋湁鏁堟渶灏忓簭鍙蜂笖>1 鏃讹紝鍙牎楠屻�屾渶灏忓簭鍙�-1銆嶄竴妗o紱搴忓彿鍏ㄦ棤鍒欒烦杩囨湰鏉′欢銆�
+ */
+ private boolean outboundChunkPredecessorPltReady(List<WorkTaskParams> chunk, Map<String, WrkMast> wrkMastMap) {
+ if (chunk == null || chunk.isEmpty()) {
+ return true;
+ }
+ WorkTaskParams head = chunk.get(0);
+ if (!"out".equalsIgnoreCase(head.getType())) {
+ return true;
+ }
+ WrkMast headMast = wrkMastMap.get(head.getTaskNo());
+ String userNo = sortUserNoForPub(head, headMast);
+ if (Cools.isEmpty(userNo)) {
+ return true;
+ }
+ int minPlt = Integer.MAX_VALUE;
+ for (WorkTaskParams p : chunk) {
+ if (!"out".equalsIgnoreCase(p.getType())) {
+ continue;
+ }
+ Integer plt = sortPltForPub(p, wrkMastMap.get(p.getTaskNo()));
+ if (plt != null && plt > 0 && plt < minPlt) {
+ minPlt = plt;
+ }
+ }
+ if (minPlt == Integer.MAX_VALUE || minPlt <= 1) {
+ return true;
+ }
+ return outboundPltSlotReleasedInWms(userNo, minPlt - 1);
+ }
+
+ private boolean outboundPltSlotReleasedInWms(String userNo, int pltType) {
+ List<WrkMast> rows = wrkMastService.selectList(new EntityWrapper<WrkMast>()
+ .eq("user_no", userNo)
+ .eq("io_type", 101)
+ .eq("plt_type", pltType));
+ if (rows != null && !rows.isEmpty()) {
+ for (WrkMast m : rows) {
+ if (m != null && m.getWrkSts() != null && Objects.equals(m.getWrkSts(), 11L)) {
+ return false;
+ }
+ }
+ return true;
+ }
+ int logCnt = wrkMastLogService.selectCount(new EntityWrapper<WrkMastLog>()
+ .eq("user_no", userNo)
+ .eq("io_type", 101)
+ .eq("plt_type", pltType));
+ return logCnt > 0;
+ }
+
+ private static boolean queryTaskDataNonEmpty(Object data) {
+ if (data == null) {
+ return false;
+ }
+ if (data instanceof JSONArray) {
+ return !((JSONArray) data).isEmpty();
+ }
+ if (data instanceof Collection) {
+ return !((Collection<?>) data).isEmpty();
+ }
+ if (data instanceof String) {
+ String s = (String) data;
+ if (Cools.isEmpty(s)) {
+ return false;
+ }
+ JSONArray arr = JSON.parseArray(s);
+ return arr != null && !arr.isEmpty();
+ }
+ return true;
+ }
+
+ private Comparator<WorkTaskParams> pubWcsSortComparator(Map<String, WrkMast> wrkMastMap) {
+ return Comparator
+ .comparing((WorkTaskParams p) -> Optional.ofNullable(p.getType()).orElse(""), String.CASE_INSENSITIVE_ORDER)
+ .thenComparing(p -> sortUserNoForPub(p, wrkMastMap.get(p.getTaskNo())), Comparator.nullsLast(String::compareTo))
+ .thenComparing(p -> sortPltForPub(p, wrkMastMap.get(p.getTaskNo())), Comparator.nullsLast(Integer::compareTo));
+ }
+
+ private static String sortUserNoForPub(WorkTaskParams p, WrkMast wrkMast) {
+ String userNo = wrkMast == null ? null : wrkMast.getUserNo();
+ if (Cools.isEmpty(userNo)) {
+ userNo = p.getBatch();
+ }
+ return Cools.isEmpty(userNo) ? null : userNo;
+ }
+
+ private static Integer sortPltForPub(WorkTaskParams p, WrkMast wrkMast) {
+ if (wrkMast != null && wrkMast.getPltType() != null) {
+ return wrkMast.getPltType();
+ }
+ return p.getBatchSeq();
}
/**
@@ -206,51 +570,374 @@
return R.ok();
}
+ @Override
+ public R syncDeviceStatusFromWcs(boolean logOnFailure) {
+ if (!Boolean.parseBoolean(String.valueOf(switchValue))) {
+ return R.ok("WCS寮�鍏冲叧闂�");
+ }
+ String response = null;
+ try {
+ response = requestDeviceStatusFromWcs();
+ JSONObject jsonObject = JSON.parseObject(response == null ? "{}" : response);
+ Integer code = jsonObject.getInteger("code");
+ if (!Objects.equals(code, 200)) {
+ String msg = jsonObject.getString("msg");
+ return R.error(Cools.isEmpty(msg) ? "鑾峰彇WCS璁惧鐘舵�佸け璐�" : msg);
+ }
+ JSONObject data = jsonObject.getJSONObject("data");
+ DeviceStatusVo deviceStatusVo = data == null
+ ? new DeviceStatusVo()
+ : JSON.parseObject(data.toJSONString(), DeviceStatusVo.class);
+
+ int stationCount = syncStationStatus(deviceStatusVo.getStationList());
+ int crnCount = syncCrnStatus(deviceStatusVo.getCrnList());
+
+ Map<String, Object> result = new LinkedHashMap<>();
+ result.put("stationCount", stationCount);
+ result.put("crnCount", crnCount);
+ log.info("鍚屾WCS璁惧鐘舵�佹垚鍔�, stationCount={}, crnCount={}", stationCount, crnCount);
+ return R.ok("鍚屾鎴愬姛").add(result);
+ } catch (Exception e) {
+ if (logOnFailure) {
+ log.error("鍚屾WCS璁惧鐘舵�佸紓甯�, response={}", response, e);
+ } else {
+ log.debug("鍚屾WCS璁惧鐘舵�佸紓甯�, response={}", response, e);
+ }
+ return R.error("鍚屾WCS璁惧鐘舵�佸け璐�: " + e.getMessage());
+ }
+ }
+
private boolean requiresOutboundErpConfirm(WrkMast wrkMast) {
Integer ioType = wrkMast == null ? null : wrkMast.getIoType();
return ioType != null && (ioType == 101 || ioType == 103 || ioType == 104 || ioType == 107 || ioType == 110);
}
+
+ /**
+ * 鏍¢獙鍗曟潯浠诲姟鏄惁婊¤冻涓嬪彂鍓嶆彁銆�
+ * <p>
+ * 杩欓噷鏃㈡牎楠屾帴鍙e繀濉」锛屼篃鏍¢獙涓氬姟绾︽潫锛屼緥濡傦細
+ * 1. 鍑哄簱浠诲姟鏄惁琚殏鍋滐紱
+ * 2. 闇�瑕� ERP 纭鐨勫嚭搴撲换鍔℃槸鍚﹀凡纭銆�
+ */
+ private String validatePubTask(WorkTaskParams params, WrkMast wrkMast) {
+ if (params == null) {
+ return "鍙傛暟涓嶈兘涓虹┖锛侊紒";
+ }
+ if (Cools.isEmpty(params.getTaskNo())) {
+ return "浠诲姟鍙蜂笉鑳戒负绌猴紒锛�";
+ }
+ if (Cools.isEmpty(params.getBarcode())) {
+ return "鎵樼洏鐮佷笉鑳戒负绌猴紒锛�";
+ }
+ if (Cools.isEmpty(params.getLocNo())) {
+ return "鐩爣搴撲綅涓嶈兘涓虹┖锛侊紒";
+ }
+ if (!Objects.isNull(wrkMast) && "out".equalsIgnoreCase(params.getType())) {
+ if ("Y".equalsIgnoreCase(wrkMast.getPauseMk())) {
+ return "task paused";
+ }
+ if (requiresOutboundErpConfirm(wrkMast) && !"Y".equalsIgnoreCase(wrkMast.getPdcType())) {
+ return "task not confirmed by erp";
+ }
+ }
+ return null;
+ }
+
+ /**
+ * 鎸変换鍔$被鍨嬮�夋嫨 WCS 鎺ュ彛鍦板潃銆�
+ * in -> 鍏ュ簱鎺ュ彛
+ * out -> 鍑哄簱鎺ュ彛
+ * move -> 绉诲簱鎺ュ彛
+ */
+ private String resolveTaskPath(WorkTaskParams params) {
+ if (!Objects.isNull(params.getType()) && params.getType().equals("out")) {
+ return getWcs_address;
+ }
+ if (!Objects.isNull(params.getType()) && params.getType().equals("move")) {
+ return createLocMoveTask;
+ }
+ return createInTask;
+ }
+
+ /**
+ * WCS 涓嬪彂鎴愬姛鍚庢帹杩涙湰鍦板伐浣滄。鐘舵�併��
+ * <p>
+ * 杩欓噷鍙鐞嗏�滃凡涓嬪彂鈥濊繖涓�灞傜姸鎬侊紝涓嶅鐞嗚澶囨墽琛屽畬鎴愮姸鎬侊紱
+ * 璁惧鎵ц瀹屾垚渚濈劧浠� WCS 鍥炲啓涓哄噯銆�
+ */
+ private void updateWrkMastAfterPublish(WrkMast wrkMast) {
+ if (Objects.isNull(wrkMast)) {
+ return;
+ }
+ if (wrkMast.getIoType()==1 || wrkMast.getIoType()==10) {
+ wrkMast.setWrkSts(2L);
+ wrkMast.setModiTime(new Date());
+ wrkMastService.updateById(wrkMast);
+ }else if(wrkMast.getIoType()==2){
+ wrkMast.setWrkSts(2L);
+ wrkMast.setModiTime(new Date());
+ wrkMastService.updateById(wrkMast);
+ }else if (wrkMast.getIoType()==101 || wrkMast.getIoType()==110) {
+ wrkMast.setWrkSts(12L);
+ wrkMast.setModiTime(new Date());
+ wrkMastService.updateById(wrkMast);
+ }
+ }
+
+ /**
+ * 鎶婃湰娆″緟涓嬪彂鐨� taskNo 鎵归噺鏄犲皠鎴愬伐浣滄。锛屼緵鍚庣画鏍¢獙銆佹寜 userNo 鍒嗙粍銆佺姸鎬佸洖鍐欏鐢ㄣ��
+ */
+ private Map<String, WrkMast> getWrkMastMap(List<WorkTaskParams> paramsList) {
+ List<String> taskNos = paramsList.stream()
+ .filter(Objects::nonNull)
+ .map(WorkTaskParams::getTaskNo)
+ .filter(taskNo -> !Cools.isEmpty(taskNo))
+ .distinct()
+ .collect(Collectors.toList());
+ if (taskNos.isEmpty()) {
+ return Collections.emptyMap();
+ }
+ List<WrkMast> wrkMasts = wrkMastService.selectList(new EntityWrapper<WrkMast>().in("wrk_no", taskNos));
+ if (wrkMasts == null || wrkMasts.isEmpty()) {
+ return Collections.emptyMap();
+ }
+ return wrkMasts.stream()
+ .filter(Objects::nonNull)
+ .collect(Collectors.toMap(mast -> String.valueOf(mast.getWrkNo()), mast -> mast, (left, right) -> left, LinkedHashMap::new));
+ }
+
+ /**
+ * 鏋勯�犳壒閲忎笅鍙戠殑鍒嗙粍閿��
+ * <p>
+ * 鍒嗙粍瑙勫垯锛�
+ * 1. 鍏堟寜鎺ュ彛璺緞鍖哄垎锛岄伩鍏嶄笉鍚屼换鍔$被鍨嬫贩鐢ㄥ悓涓�涓� WCS 鎺ュ彛锛�
+ * 2. 鍐嶆寜 userNo 鍖哄垎锛岀‘淇濈浉鍚� userNo 鐨勪换鍔′竴璧蜂笂鎶ャ��
+ * <p>
+ * 姝e父鎯呭喌涓� userNo 鍙栬嚜 work_mast.user_no锛�
+ * 濡傛灉褰撳墠娌℃煡鍒板伐浣滄。锛屽垯鍥為��鍒拌姹傞噷鐨� batch 瀛楁锛屼繚璇佸吋瀹瑰凡鏈夎皟鐢ㄣ��
+ */
+ private String buildBatchGroupKey(WorkTaskParams params, WrkMast wrkMast) {
+ String path = resolveTaskPath(params);
+ String userNo = wrkMast == null ? null : wrkMast.getUserNo();
+ if (Cools.isEmpty(userNo)) {
+ userNo = params.getBatch();
+ }
+ if (Cools.isEmpty(userNo)) {
+ userNo = "_NO_USER_";
+ }
+ return path + "#" + userNo;
+ }
+
+ /**
+ * 灏嗕竴缁勪笟鍔″弬鏁拌浆鎹㈡垚 WCS 鎵归噺鎺ュ彛鐨� tasks 鏁扮粍銆�
+ */
+ private List<Map<String, Object>> buildTaskPayloads(List<WorkTaskParams> tasks) {
+ List<Map<String, Object>> payloads = new ArrayList<>();
+ for (WorkTaskParams task : tasks) {
+ payloads.add(buildTaskPayload(task));
+ }
+ return payloads;
+ }
+
+ /**
+ * 缁勮鍗曟潯浠诲姟鐨� WCS 璇锋眰浣撱��
+ * 鍙斁褰撳墠浠诲姟绫诲瀷瀹為檯闇�瑕佺殑瀛楁锛涚┖瀛楁涓嶉�忎紶锛岄伩鍏嶇粰 WCS 閫犳垚姝т箟銆�
+ */
+ private Map<String, Object> buildTaskPayload(WorkTaskParams params) {
+ Map<String, Object> task = new LinkedHashMap<>();
+ if (!Cools.isEmpty(params.getTaskNo())) {
+ task.put("taskNo", params.getTaskNo());
+ }
+ if (!Cools.isEmpty(params.getLocNo())) {
+ task.put("locNo", params.getLocNo());
+ }
+ if (!Cools.isEmpty(params.getSourceLocNo())) {
+ task.put("sourceLocNo", params.getSourceLocNo());
+ }
+ if (!Cools.isEmpty(params.getSourceStaNo())) {
+ task.put("sourceStaNo", params.getSourceStaNo());
+ }
+ if (!Cools.isEmpty(params.getBarcode())) {
+ task.put("barcode", params.getBarcode());
+ }
+ if (!Objects.isNull(params.getTaskPri())) {
+ task.put("taskPri", params.getTaskPri());
+ }
+ if (!Cools.isEmpty(params.getStaNo())) {
+ task.put("staNo", params.getStaNo());
+ }
+ if (!Cools.isEmpty(params.getBatch())) {
+ task.put("batch", params.getBatch());
+ }
+ if (!Objects.isNull(params.getBatchSeq())) {
+ task.put("batchSeq", params.getBatchSeq());
+ }
+ return task;
+ }
+
+ /**
+ * 鏋勯�犺烦杩�/澶辫触淇℃伅鏃剁粺涓�甯︿笂 taskNo锛屼究浜庢帓鏌ュ叿浣撴槸鍝竴鏉″伐浣滄。鏈涓嬪彂銆�
+ */
+ private String buildTaskMsg(WorkTaskParams params, String msg) {
+ if (params == null || Cools.isEmpty(params.getTaskNo())) {
+ return msg;
+ }
+ return "taskNo=" + params.getTaskNo() + ", msg=" + msg;
+ }
+
@Override
- public R pauseOutTasks(StopOutTaskParams params) {
- if (params == null || params.getTasks() == null || params.getTasks().isEmpty()) {
+ public R pauseOutTasks(List<HashMap<String,Object>> params) {
+ if (params == null || params.size() == 0) {
return R.ok("鏃犱换鍔¢渶瑕佸彇娑�");
}
if (!Boolean.parseBoolean(String.valueOf(switchValue))) {
return R.ok("WCS寮�鍏冲叧闂�");
}
- String response;
+ HashMap<String,Object> map = new HashMap<>();
+ map.put("taskList", params);
+ String requestJson = JSON.toJSONString(map);
+ String response = null;
+ Throwable wcsThrown = null;
+ boolean wcsBizOk = false;
try {
- log.info("璋冪敤WCS鍙栨秷鍑哄簱浠诲姟, request={}", JSON.toJSONString(params));
+ log.info("璋冪敤WCS鍙栨秷鍑哄簱浠诲姟, request={}", requestJson);
response = new HttpHandler.Builder()
.setUri(wcs_address)
.setPath(stopOutTask)
- .setHttps(wcs_address != null && wcs_address.startsWith("https://"))
+// .setHttps(wcs_address != null && wcs_address.startsWith("https://"))
.setTimeout(10, TimeUnit.SECONDS)
- .setJson(JSON.toJSONString(params))
+ .setJson(requestJson)
.build()
.doPost();
JSONObject jsonObject = JSON.parseObject(response == null ? "{}" : response);
log.info("WCS鍙栨秷鍑哄簱浠诲姟杩斿洖, response={}", response);
Integer code = jsonObject.getInteger("code");
- if (code == null || !Objects.equals(code, 200)) {
+ wcsBizOk = code != null && Objects.equals(code, 200);
+ if (!wcsBizOk) {
String msg = jsonObject.getString("msg");
throw new CoolException(Cools.isEmpty(msg) ? "WCS鍙栨秷鍑哄簱浠诲姟澶辫触" : msg);
}
- JSONObject data = jsonObject.getJSONObject("data");
- List<String> successList = data == null || data.getJSONArray("successList") == null
- ? Collections.emptyList()
- : data.getJSONArray("successList").toJavaList(String.class);
- List<String> failList = data == null || data.getJSONArray("failList") == null
- ? Collections.emptyList()
- : data.getJSONArray("failList").toJavaList(String.class);
- R result = R.ok(Cools.isEmpty(jsonObject.getString("msg")) ? "鎿嶄綔鎴愬姛" : jsonObject.getString("msg"));
- result.put("data", data);
- result.put("successList", successList);
- result.put("failList", failList);
- return result;
+ return R.ok(Cools.isEmpty(jsonObject.getString("msg")) ? "鎿嶄綔鎴愬姛" : jsonObject.getString("msg"));
} catch (IOException e) {
+ wcsThrown = e;
throw new CoolException("璋冪敤WCS鍙栨秷鍑哄簱浠诲姟澶辫触: " + e.getMessage());
+ } finally {
+ logWcsToApiLog(stopOutTask, requestJson, response, wcsThrown, wcsBizOk);
}
}
+ private void logWcsToApiLog(String path, String requestJson, String response, Throwable thrown, boolean wcsBizOk) {
+ String fullUrl = (wcs_address == null ? "" : wcs_address) + (path == null ? "" : path);
+ boolean success = thrown == null && wcsBizOk;
+ String resp = response == null ? "" : response;
+ if (thrown != null && Cools.isEmpty(resp)) {
+ resp = thrown.getMessage() == null ? "" : thrown.getMessage();
+ }
+ apiLogService.save(NS_WMS_TO_WCS, fullUrl, "-", "-",
+ requestJson == null ? "" : requestJson, resp, success);
+ }
+
+ private String requestDeviceStatusFromWcs() throws IOException {
+ HttpHandler.Builder builder = new HttpHandler.Builder()
+ .setUri(wcs_address)
+ .setPath(getDeviceStatus)
+ .setTimeout(10, TimeUnit.SECONDS);
+ String method = Cools.isEmpty(deviceStatusMethod) ? "POST" : deviceStatusMethod.trim().toUpperCase(Locale.ROOT);
+ if ("POST".equals(method)) {
+ return builder.setJson("{}").build().doPost();
+ }
+ return builder.build().doGet();
+ }
+
+ private int syncStationStatus(List<StationProtocol> stationList) {
+ if (stationList == null || stationList.isEmpty()) {
+ return 0;
+ }
+ int count = 0;
+ Date now = new Date();
+ for (StationProtocol stationProtocol : stationList) {
+ if (stationProtocol == null || stationProtocol.getStationId() == null) {
+ continue;
+ }
+ BasDevp basDevp = basDevpService.selectById(stationProtocol.getStationId());
+ boolean isNew = Objects.isNull(basDevp);
+ if (isNew) {
+ basDevp = new BasDevp();
+ basDevp.setDevNo(stationProtocol.getStationId());
+ basDevp.setAppeUser(WCS_SYNC_USER);
+ basDevp.setAppeTime(now);
+ }
+ basDevp.setInEnable(toFlag(stationProtocol.isInEnable()));
+ basDevp.setOutEnable(toFlag(stationProtocol.isOutEnable()));
+ basDevp.setAutoing(toFlag(stationProtocol.isAutoing()));
+ basDevp.setLoading(toFlag(stationProtocol.isLoading()));
+ basDevp.setCanining(toFlag(stationProtocol.isEnableIn()));
+ basDevp.setCanouting(toFlag(!stationProtocol.isRunBlock()));
+ basDevp.setWrkNo(defaultZero(stationProtocol.getTaskNo()));
+ basDevp.setBarcode(normalizeText(stationProtocol.getBarcode()));
+ basDevp.setGrossWt(stationProtocol.getWeight() == null ? 0D : stationProtocol.getWeight());
+ basDevp.setModiUser(WCS_SYNC_USER);
+ basDevp.setModiTime(now);
+ if (isNew) {
+ if (!basDevpService.insert(basDevp)) {
+ throw new CoolException("鏂板绔欑偣鐘舵�佸け璐�, stationId=" + stationProtocol.getStationId());
+ }
+ } else if (!basDevpService.updateById(basDevp)) {
+ throw new CoolException("鏇存柊绔欑偣鐘舵�佸け璐�, stationId=" + stationProtocol.getStationId());
+ }
+ count++;
+ }
+ return count;
+ }
+
+ private int syncCrnStatus(List<CrnProtocol> crnList) {
+ if (crnList == null || crnList.isEmpty()) {
+ return 0;
+ }
+ int count = 0;
+ Date now = new Date();
+ for (CrnProtocol crnProtocol : crnList) {
+ if (crnProtocol == null || crnProtocol.getCrnNo() == null) {
+ continue;
+ }
+ BasCrnp basCrnp = basCrnpService.selectById(crnProtocol.getCrnNo());
+ boolean isNew = Objects.isNull(basCrnp);
+ if (isNew) {
+ basCrnp = new BasCrnp();
+ basCrnp.setCrnNo(crnProtocol.getCrnNo());
+ basCrnp.setInEnable(YES);
+ basCrnp.setOutEnable(YES);
+ basCrnp.setAppeUser(WCS_SYNC_USER);
+ basCrnp.setAppeTime(now);
+ }
+ // crn_sts 鏈湴琛ㄥ瓨鐨勬槸鈥滃爢鍨涙満妯″紡(鎵嬪姩/鑷姩/鐢佃剳)鈥濓紝鍥犳蹇呴』鍐� mode锛屼笉鑳藉啓 status銆�
+ basCrnp.setCrnSts(defaultZero(crnProtocol.getMode()));
+ basCrnp.setWrkNo(defaultZero(crnProtocol.getTaskNo()));
+ basCrnp.setCrnErr(crnProtocol.getAlarm() == null ? 0L : Long.valueOf(crnProtocol.getAlarm()));
+ basCrnp.setModiUser(WCS_SYNC_USER);
+ basCrnp.setModiTime(now);
+ if (isNew) {
+ if (!basCrnpService.insert(basCrnp)) {
+ throw new CoolException("鏂板鍫嗗灈鏈虹姸鎬佸け璐�, crnNo=" + crnProtocol.getCrnNo());
+ }
+ } else if (!basCrnpService.updateById(basCrnp)) {
+ throw new CoolException("鏇存柊鍫嗗灈鏈虹姸鎬佸け璐�, crnNo=" + crnProtocol.getCrnNo());
+ }
+ count++;
+ }
+ return count;
+ }
+
+ private Integer defaultZero(Integer value) {
+ return value == null ? 0 : value;
+ }
+
+ private String normalizeText(String value) {
+ return Cools.isEmpty(value) ? "" : value;
+ }
+
+ private String toFlag(boolean value) {
+ return value ? YES : NO;
+ }
+
}
--
Gitblit v1.9.1