|
|
|
@ -36,6 +36,21 @@ public class InventoryDiscrepancyServiceImpl implements InventoryDiscrepancyServ |
|
|
|
@Autowired |
|
|
|
private WcsIntegrationMapper wcsIntegrationMapper; |
|
|
|
|
|
|
|
/** |
|
|
|
* @Description 位置信息内部类(用于自动分拣)- rqrq |
|
|
|
*/ |
|
|
|
private static class PositionInfo { |
|
|
|
String position; |
|
|
|
Integer layer; |
|
|
|
String partNo; |
|
|
|
|
|
|
|
public PositionInfo(String position, Integer layer, String partNo) { |
|
|
|
this.position = position; |
|
|
|
this.layer = layer; |
|
|
|
this.partNo = partNo; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/** |
|
|
|
* @Description 处理WCS回调扫描记录,对比库存差异 - rqrq |
|
|
|
* @Title processCallbackScan |
|
|
|
@ -52,86 +67,240 @@ public class InventoryDiscrepancyServiceImpl implements InventoryDiscrepancyServ |
|
|
|
try { |
|
|
|
// 1. 更新回调记录状态为处理中 - rqrq |
|
|
|
wcsCallbackPalletScanMapper.updateProcessStatus(callback.getId(), "PROCESSING", null); |
|
|
|
|
|
|
|
// 2. 从pallet_detail表查询WMS账面数据 - rqrq |
|
|
|
List<PalletDetailData> wmsDetailList = wcsIntegrationMapper.getPalletDetailsData( |
|
|
|
callback.getSite(), callback.getPalletId()); |
|
|
|
|
|
|
|
// 3. 提取WMS所有条码 - rqrq |
|
|
|
List<String> wmsBarcodeList = wmsDetailList.stream() |
|
|
|
.map(PalletDetailData::getSerialNo) |
|
|
|
.collect(Collectors.toList()); |
|
|
|
|
|
|
|
// 4. 解析WCS扫描的条码列表 - rqrq |
|
|
|
List<String> wcsBarcodeList = new ArrayList<>(); |
|
|
|
if (callback.getWcsBarcodeList() != null && !callback.getWcsBarcodeList().isEmpty()) { |
|
|
|
try { |
|
|
|
JSONArray jsonArray = JSONArray.parseArray(callback.getWcsBarcodeList()); |
|
|
|
for (int i = 0; i < jsonArray.size(); i++) { |
|
|
|
wcsBarcodeList.add(jsonArray.getString(i)); |
|
|
|
if(callback.getSoreType()==0) { |
|
|
|
// 2. 从pallet_detail表查询WMS账面数据 - rqrq |
|
|
|
List<PalletDetailData> wmsDetailList = wcsIntegrationMapper.getPalletDetailsData( |
|
|
|
callback.getSite(), callback.getPalletId()); |
|
|
|
|
|
|
|
// 3. 提取WMS所有条码 - rqrq |
|
|
|
List<String> wmsBarcodeList = wmsDetailList.stream() |
|
|
|
.map(PalletDetailData::getSerialNo) |
|
|
|
.collect(Collectors.toList()); |
|
|
|
|
|
|
|
// 4. 解析WCS扫描的条码列表 - rqrq |
|
|
|
List<String> wcsBarcodeList = new ArrayList<>(); |
|
|
|
if (callback.getWcsBarcodeList() != null && !callback.getWcsBarcodeList().isEmpty()) { |
|
|
|
try { |
|
|
|
JSONArray jsonArray = JSONArray.parseArray(callback.getWcsBarcodeList()); |
|
|
|
for (int i = 0; i < jsonArray.size(); i++) { |
|
|
|
wcsBarcodeList.add(jsonArray.getString(i)); |
|
|
|
} |
|
|
|
} catch (Exception e) { |
|
|
|
System.err.println("解析WCS条码列表失败 - rqrq:" + e.getMessage()); |
|
|
|
} |
|
|
|
} catch (Exception e) { |
|
|
|
System.err.println("解析WCS条码列表失败 - rqrq:" + e.getMessage()); |
|
|
|
} |
|
|
|
|
|
|
|
// 5. 对比整个栈板的差异(不按物料分组)- rqrq |
|
|
|
Set<String> wmsSet = new HashSet<>(wmsBarcodeList); |
|
|
|
Set<String> wcsSet = new HashSet<>(wcsBarcodeList); |
|
|
|
|
|
|
|
// WMS有但WCS没有的条码 - rqrq |
|
|
|
Set<String> missingBarcodes = new HashSet<>(wmsSet); |
|
|
|
missingBarcodes.removeAll(wcsSet); |
|
|
|
|
|
|
|
// WCS有但WMS没有的条码 - rqrq |
|
|
|
Set<String> extraBarcodes = new HashSet<>(wcsSet); |
|
|
|
extraBarcodes.removeAll(wmsSet); |
|
|
|
|
|
|
|
// 6. 生成一条差异记录(无论是否有差异都记录,便于追踪)- rqrq |
|
|
|
WmsWcsInventoryDiscrepancy discrepancy = new WmsWcsInventoryDiscrepancy(); |
|
|
|
discrepancy.setSite(callback.getSite()); |
|
|
|
discrepancy.setCallbackId(callback.getId()); |
|
|
|
discrepancy.setPalletId(callback.getPalletId()); |
|
|
|
discrepancy.setTaskNo(callback.getTaskNo()); |
|
|
|
discrepancy.setItemNo(callback.getItemNo()); |
|
|
|
discrepancy.setOperationType("picking"); |
|
|
|
discrepancy.setOperationTime(callback.getWcsScanTime()); |
|
|
|
discrepancy.setPartNo(""); // 不再按物料分组,留空 - rqrq |
|
|
|
|
|
|
|
discrepancy.setWmsTotalQuantity(wmsBarcodeList.size()); |
|
|
|
discrepancy.setWcsTotalQuantity(wcsBarcodeList.size()); |
|
|
|
|
|
|
|
discrepancy.setWmsBarcodeList(JSONObject.toJSONString(wmsBarcodeList)); |
|
|
|
discrepancy.setWcsBarcodeList(JSONObject.toJSONString(wcsBarcodeList)); |
|
|
|
discrepancy.setWmsMissingBarcodes(JSONObject.toJSONString(new ArrayList<>(missingBarcodes))); |
|
|
|
discrepancy.setWcsExtraBarcodes(JSONObject.toJSONString(new ArrayList<>(extraBarcodes))); |
|
|
|
|
|
|
|
// 如果有差异,标记为待处理;无差异,标记为已处理 - rqrq |
|
|
|
if (!missingBarcodes.isEmpty() || !extraBarcodes.isEmpty()) { |
|
|
|
discrepancy.setStatus(0); // 待处理 - rqrq |
|
|
|
discrepancy.setRemark("系统自动对账生成 - 发现差异"); |
|
|
|
} else { |
|
|
|
discrepancy.setStatus(2); // 已处理(无差异)- rqrq |
|
|
|
discrepancy.setRemark("系统自动对账生成 - 无差异"); |
|
|
|
} |
|
|
|
|
|
|
|
// 7. 插入差异记录(改为单条插入)- rqrq |
|
|
|
List<WmsWcsInventoryDiscrepancy> discrepancyList = new ArrayList<>(); |
|
|
|
discrepancyList.add(discrepancy); |
|
|
|
wmsWcsInventoryDiscrepancyMapper.batchInsert(discrepancyList); |
|
|
|
|
|
|
|
System.out.println("生成库存差异记录 - rqrq,栈板=" + callback.getPalletId() |
|
|
|
+ ",WMS条码数=" + wmsBarcodeList.size() |
|
|
|
+ ",WCS条码数=" + wcsBarcodeList.size() |
|
|
|
+ ",缺失=" + missingBarcodes.size() |
|
|
|
+ ",多余=" + extraBarcodes.size()); |
|
|
|
|
|
|
|
// 8. 更新回调记录状态为已完成 - rqrq |
|
|
|
wcsCallbackPalletScanMapper.updateProcessStatus(callback.getId(), "COMPLETED", null); |
|
|
|
|
|
|
|
System.out.println("WCS回调扫描记录对账完成 - rqrq,palletId=" + callback.getPalletId() |
|
|
|
+ ",分拣方式=" + callback.getSoreType()); |
|
|
|
} else if(callback.getSoreType()==1||callback.getSoreType()==2) { |
|
|
|
// 自动分拣逻辑(气胀轴或抱箱)- rqrq |
|
|
|
System.out.println("执行自动分拣逻辑 - rqrq,分拣方式=" + (callback.getSoreType()==1 ? "气胀轴" : "抱箱")); |
|
|
|
|
|
|
|
// 1. 解析jsonStr为PushPalletDetailDto对象 - rqrq |
|
|
|
if (!StringUtils.hasText(callback.getJsonStr())) { |
|
|
|
throw new Exception("jsonStr为空,无法解析栈板和明细信息"); |
|
|
|
} |
|
|
|
|
|
|
|
com.gaotao.modules.api.entity.PushPalletDetailDto pushData = JSONObject.parseObject( |
|
|
|
callback.getJsonStr(), |
|
|
|
com.gaotao.modules.api.entity.PushPalletDetailDto.class |
|
|
|
); |
|
|
|
|
|
|
|
if (pushData == null) { |
|
|
|
throw new Exception("jsonStr解析为PushPalletDetailDto失败"); |
|
|
|
} |
|
|
|
|
|
|
|
String originalPalletId = pushData.getPalletBarcode(); |
|
|
|
if (!StringUtils.hasText(originalPalletId)) { |
|
|
|
throw new Exception("PushPalletDetailDto中未找到栈板编码(palletBarcode)"); |
|
|
|
} |
|
|
|
|
|
|
|
System.out.println("解析成功 - rqrq,原栈板=" + originalPalletId |
|
|
|
+ ",taskNo=" + pushData.getTaskNo() |
|
|
|
+ ",itemNo=" + pushData.getItemNo()); |
|
|
|
|
|
|
|
// 2. 查询原栈板的pallet_detail数据(WMS账面)- rqrq |
|
|
|
List<PalletDetailData> wmsDetailList = wcsIntegrationMapper.getPalletDetailsData( |
|
|
|
callback.getSite(), originalPalletId); |
|
|
|
|
|
|
|
// 提取WMS所有条码(当前账面)- rqrq |
|
|
|
Set<String> wmsSerialNoSet = wmsDetailList.stream() |
|
|
|
.map(PalletDetailData::getSerialNo) |
|
|
|
.collect(Collectors.toSet()); |
|
|
|
|
|
|
|
System.out.println("WMS当前明细数量 - rqrq:" + wmsDetailList.size() + "条"); |
|
|
|
|
|
|
|
// 3. 提取WCS回传的所有条码和位置信息 - rqrq |
|
|
|
Map<String, PositionInfo> wcsSerialNoMap = new HashMap<>(); |
|
|
|
int totalWcsCount = 0; |
|
|
|
|
|
|
|
List<com.gaotao.modules.api.entity.PalletStationVo> cargoInfos = pushData.getCargoInfos(); |
|
|
|
if (cargoInfos != null && !cargoInfos.isEmpty()) { |
|
|
|
for (com.gaotao.modules.api.entity.PalletStationVo cargoInfo : cargoInfos) { |
|
|
|
Integer position = cargoInfo.getPosition(); |
|
|
|
Integer layer = cargoInfo.getLayer(); |
|
|
|
List<com.gaotao.modules.api.entity.PalletStationDetailVo> productInfos = cargoInfo.getProductInfos(); |
|
|
|
|
|
|
|
if (productInfos != null && !productInfos.isEmpty()) { |
|
|
|
for (com.gaotao.modules.api.entity.PalletStationDetailVo product : productInfos) { |
|
|
|
totalWcsCount++; |
|
|
|
String serialNo = product.getSerialNo(); |
|
|
|
wcsSerialNoMap.put(serialNo, new PositionInfo( |
|
|
|
String.valueOf(position), |
|
|
|
layer, |
|
|
|
product.getSku() |
|
|
|
)); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
System.out.println("WCS回传明细总数 - rqrq:" + totalWcsCount + "条"); |
|
|
|
|
|
|
|
// 4. 找出被拿走的物料(WMS有但WCS没有的)- rqrq |
|
|
|
Set<String> removedSerialNos = new HashSet<>(wmsSerialNoSet); |
|
|
|
removedSerialNos.removeAll(wcsSerialNoMap.keySet()); |
|
|
|
|
|
|
|
System.out.println("被拿走的物料数量 - rqrq:" + removedSerialNos.size() + "条"); |
|
|
|
|
|
|
|
// 5. 将拿走的物料转移到虚拟栈板"ZIDONGFENJIAN" - rqrq |
|
|
|
String virtualPalletId = "ZIDONGFENJIAN"; |
|
|
|
String virtualPosition = pushData.getTaskNo(); // position = taskNo |
|
|
|
Integer virtualLayer = pushData.getItemNo(); // layer = itemNo |
|
|
|
String username = "WCS"; |
|
|
|
|
|
|
|
for (String removedSerialNo : removedSerialNos) { |
|
|
|
// 查找原明细信息(获取partNo)- rqrq |
|
|
|
PalletDetailData originalDetail = wmsDetailList.stream() |
|
|
|
.filter(d -> removedSerialNo.equals(d.getSerialNo())) |
|
|
|
.findFirst() |
|
|
|
.orElse(null); |
|
|
|
|
|
|
|
if (originalDetail == null) { |
|
|
|
System.err.println("未找到原明细信息 - rqrq:serialNo=" + removedSerialNo); |
|
|
|
continue; |
|
|
|
} |
|
|
|
|
|
|
|
// 从原栈板删除 - rqrq |
|
|
|
wcsIntegrationMapper.deletePalletDetailBySerialNo(callback.getSite(), removedSerialNo); |
|
|
|
|
|
|
|
// 添加到虚拟栈板 - rqrq |
|
|
|
wcsIntegrationMapper.savePalletDetailNoValidation( |
|
|
|
callback.getSite(), |
|
|
|
virtualPalletId, |
|
|
|
virtualPosition, |
|
|
|
virtualLayer, |
|
|
|
removedSerialNo, |
|
|
|
originalDetail.getPartNo(), |
|
|
|
username, |
|
|
|
1 // wcsFlag=1(待推送) |
|
|
|
); |
|
|
|
|
|
|
|
System.out.println("物料已转移到虚拟栈板 - rqrq:serialNo=" + removedSerialNo |
|
|
|
+ ",虚拟栈板=" + virtualPalletId |
|
|
|
+ ",position=" + virtualPosition |
|
|
|
+ ",layer=" + virtualLayer); |
|
|
|
} |
|
|
|
|
|
|
|
// 6. 更新还在原栈板上的物料的position和layer - rqrq |
|
|
|
Set<String> remainingSerialNos = new HashSet<>(wmsSerialNoSet); |
|
|
|
remainingSerialNos.retainAll(wcsSerialNoMap.keySet()); // WMS和WCS都有的 |
|
|
|
|
|
|
|
System.out.println("还在原栈板上的物料数量 - rqrq:" + remainingSerialNos.size() + "条,开始更新位置"); |
|
|
|
|
|
|
|
for (String remainingSerialNo : remainingSerialNos) { |
|
|
|
PositionInfo newPosInfo = wcsSerialNoMap.get(remainingSerialNo); |
|
|
|
|
|
|
|
// 更新位置和层数 - rqrq |
|
|
|
wcsIntegrationMapper.updatePalletDetailPosition( |
|
|
|
callback.getSite(), |
|
|
|
originalPalletId, |
|
|
|
remainingSerialNo, |
|
|
|
newPosInfo.position, |
|
|
|
newPosInfo.layer, |
|
|
|
"JiXieShouBi" |
|
|
|
); |
|
|
|
|
|
|
|
System.out.println("更新物料位置 - rqrq:serialNo=" + remainingSerialNo |
|
|
|
+ ",newPosition=" + newPosInfo.position |
|
|
|
+ ",newLayer=" + newPosInfo.layer); |
|
|
|
} |
|
|
|
|
|
|
|
// 7. 更新空栈板标记(如果原栈板已无明细,则标记为空)- rqrq |
|
|
|
if (remainingSerialNos.isEmpty()) { |
|
|
|
wcsIntegrationMapper.updatePalletEmptyFlag(callback.getSite(), originalPalletId, "Y", username); |
|
|
|
System.out.println("原栈板已空,更新empty_flag='Y' - rqrq"); |
|
|
|
} else { |
|
|
|
wcsIntegrationMapper.updatePalletEmptyFlag(callback.getSite(), originalPalletId, "N", username); |
|
|
|
System.out.println("原栈板非空,更新empty_flag='N' - rqrq"); |
|
|
|
} |
|
|
|
|
|
|
|
// 8. 更新回调记录状态为已完成 - rqrq |
|
|
|
wcsCallbackPalletScanMapper.updateProcessStatus( |
|
|
|
callback.getId(), |
|
|
|
"COMPLETED", |
|
|
|
"自动分拣处理完成,转移" + removedSerialNos.size() + "条,更新" + remainingSerialNos.size() + "条" |
|
|
|
); |
|
|
|
|
|
|
|
System.out.println("自动分拣处理完成 - rqrq,原栈板=" + originalPalletId |
|
|
|
+ ",转移到虚拟栈板=" + removedSerialNos.size() + "条" |
|
|
|
+ ",更新位置=" + remainingSerialNos.size() + "条"); |
|
|
|
} |
|
|
|
|
|
|
|
// 5. 对比整个栈板的差异(不按物料分组)- rqrq |
|
|
|
Set<String> wmsSet = new HashSet<>(wmsBarcodeList); |
|
|
|
Set<String> wcsSet = new HashSet<>(wcsBarcodeList); |
|
|
|
|
|
|
|
// WMS有但WCS没有的条码 - rqrq |
|
|
|
Set<String> missingBarcodes = new HashSet<>(wmsSet); |
|
|
|
missingBarcodes.removeAll(wcsSet); |
|
|
|
|
|
|
|
// WCS有但WMS没有的条码 - rqrq |
|
|
|
Set<String> extraBarcodes = new HashSet<>(wcsSet); |
|
|
|
extraBarcodes.removeAll(wmsSet); |
|
|
|
|
|
|
|
// 6. 生成一条差异记录(无论是否有差异都记录,便于追踪)- rqrq |
|
|
|
WmsWcsInventoryDiscrepancy discrepancy = new WmsWcsInventoryDiscrepancy(); |
|
|
|
discrepancy.setSite(callback.getSite()); |
|
|
|
discrepancy.setCallbackId(callback.getId()); |
|
|
|
discrepancy.setPalletId(callback.getPalletId()); |
|
|
|
discrepancy.setTaskNo(callback.getTaskNo()); |
|
|
|
discrepancy.setItemNo(callback.getItemNo()); |
|
|
|
discrepancy.setOperationType("picking"); |
|
|
|
discrepancy.setOperationTime(callback.getWcsScanTime()); |
|
|
|
discrepancy.setPartNo(""); // 不再按物料分组,留空 - rqrq |
|
|
|
|
|
|
|
discrepancy.setWmsTotalQuantity(wmsBarcodeList.size()); |
|
|
|
discrepancy.setWcsTotalQuantity(wcsBarcodeList.size()); |
|
|
|
|
|
|
|
discrepancy.setWmsBarcodeList(JSONObject.toJSONString(wmsBarcodeList)); |
|
|
|
discrepancy.setWcsBarcodeList(JSONObject.toJSONString(wcsBarcodeList)); |
|
|
|
discrepancy.setWmsMissingBarcodes(JSONObject.toJSONString(new ArrayList<>(missingBarcodes))); |
|
|
|
discrepancy.setWcsExtraBarcodes(JSONObject.toJSONString(new ArrayList<>(extraBarcodes))); |
|
|
|
|
|
|
|
// 如果有差异,标记为待处理;无差异,标记为已处理 - rqrq |
|
|
|
if (!missingBarcodes.isEmpty() || !extraBarcodes.isEmpty()) { |
|
|
|
discrepancy.setStatus(0); // 待处理 - rqrq |
|
|
|
discrepancy.setRemark("系统自动对账生成 - 发现差异"); |
|
|
|
} else { |
|
|
|
discrepancy.setStatus(2); // 已处理(无差异)- rqrq |
|
|
|
discrepancy.setRemark("系统自动对账生成 - 无差异"); |
|
|
|
} |
|
|
|
|
|
|
|
// 7. 插入差异记录(改为单条插入)- rqrq |
|
|
|
List<WmsWcsInventoryDiscrepancy> discrepancyList = new ArrayList<>(); |
|
|
|
discrepancyList.add(discrepancy); |
|
|
|
wmsWcsInventoryDiscrepancyMapper.batchInsert(discrepancyList); |
|
|
|
|
|
|
|
System.out.println("生成库存差异记录 - rqrq,栈板=" + callback.getPalletId() |
|
|
|
+ ",WMS条码数=" + wmsBarcodeList.size() |
|
|
|
+ ",WCS条码数=" + wcsBarcodeList.size() |
|
|
|
+ ",缺失=" + missingBarcodes.size() |
|
|
|
+ ",多余=" + extraBarcodes.size()); |
|
|
|
|
|
|
|
// 8. 更新回调记录状态为已完成 - rqrq |
|
|
|
wcsCallbackPalletScanMapper.updateProcessStatus(callback.getId(), "COMPLETED", null); |
|
|
|
|
|
|
|
System.out.println("WCS回调扫描记录对账完成 - rqrq,palletId=" + callback.getPalletId() |
|
|
|
+ ",分拣方式=" + callback.getSoreType()); |
|
|
|
|
|
|
|
} catch (Exception e) { |
|
|
|
System.err.println("处理WCS回调扫描记录对账失败 - rqrq,palletId=" + callback.getPalletId() |
|
|
|
+ ",错误:" + e.getMessage()); |
|
|
|
|