diff --git a/src/main/java/com/gaotao/modules/check/controller/PhysicalInventoryController.java b/src/main/java/com/gaotao/modules/check/controller/PhysicalInventoryController.java index 9e08069..486982c 100644 --- a/src/main/java/com/gaotao/modules/check/controller/PhysicalInventoryController.java +++ b/src/main/java/com/gaotao/modules/check/controller/PhysicalInventoryController.java @@ -310,4 +310,70 @@ public class PhysicalInventoryController { String taskNo = physicalInventoryService.createReviewTask(site, countNo, reviewType, palletIds, username); return R.ok().put("taskNo", taskNo); } + + // ==================== PDA手工盘点 ==================== + + /** + * @Description PDA扫描栈板 - 验证并返回盘点信息 - rqrq + * @param query 包含site、palletId + * @return R + * @author rqrq + */ + @PostMapping("/pda/scanPallet") + public R pdaScanPallet(@RequestBody java.util.Map query) { + String site = query.get("site"); + String palletId = query.get("palletId"); + java.util.Map result = physicalInventoryService.pdaScanPallet(site, palletId); + return R.ok().put("data", result); + } + + /** + * @Description PDA扫描标签 - 获取标签信息 - rqrq + * @param query 包含site、unitId + * @return R + * @author rqrq + */ + @PostMapping("/pda/scanLabel") + public R pdaScanLabel(@RequestBody java.util.Map query) { + String site = query.get("site"); + String unitId = query.get("unitId"); + CountLabelData result = physicalInventoryService.pdaScanLabel(site, unitId); + return R.ok().put("row", result); + } + + /** + * @Description PDA一键提交盘点(默认全部OK)- rqrq + * @param query 包含site、countNo、palletId、username + * @return R + * @author rqrq + */ + @PostMapping("/pda/quickSubmitCount") + public R pdaQuickSubmitCount(@RequestBody java.util.Map query) { + String site = query.get("site"); + String countNo = query.get("countNo"); + String palletId = query.get("palletId"); + String username = query.get("username"); + int result = physicalInventoryService.pdaQuickSubmitCount(site, countNo, palletId, username); + return R.ok().put("result", result); + } + + /** + * @Description PDA提交盘点结果 - rqrq + * @param query 包含site、countNo、palletId、scannedLabels、username + * @return R + * @author rqrq + */ + @PostMapping("/pda/submitCount") + @SuppressWarnings("unchecked") + public R pdaSubmitCount(@RequestBody java.util.Map query) { + String site = (String) query.get("site"); + String countNo = (String) query.get("countNo"); + String palletId = (String) query.get("palletId"); + java.util.List> scannedLabels = + (java.util.List>) query.get("scannedLabels"); + String username = (String) query.get("username"); + + int result = physicalInventoryService.pdaSubmitCount(site, countNo, palletId, scannedLabels, username); + return R.ok().put("result", result); + } } diff --git a/src/main/java/com/gaotao/modules/check/mapper/PhysicalInventoryMapper.java b/src/main/java/com/gaotao/modules/check/mapper/PhysicalInventoryMapper.java index 83fcb9e..5db0a3f 100644 --- a/src/main/java/com/gaotao/modules/check/mapper/PhysicalInventoryMapper.java +++ b/src/main/java/com/gaotao/modules/check/mapper/PhysicalInventoryMapper.java @@ -336,6 +336,36 @@ public interface PhysicalInventoryMapper extends BaseMapper { */ int batchUpdateHandlingUnitCountFlagByCountNo(@Param("site") String site, @Param("countNo") String countNo, @Param("countDate") String countDate); + // ==================== PDA手工盘点 ==================== + + /** + * @Description 根据栈板号查询盘点栈板信息 - rqrq + * @param site 工厂编码 + * @param palletId 栈板号 + * @return CountPalletData + * @author rqrq + */ + CountPalletData getCountPalletByPalletId(@Param("site") String site, @Param("palletId") String palletId); + + /** + * @Description 根据栈板号查询盘点标签明细列表 - rqrq + * @param site 工厂编码 + * @param countNo 盘点单号 + * @param palletId 栈板号 + * @return List + * @author rqrq + */ + List getCountLabelsByPalletId(@Param("site") String site, @Param("countNo") String countNo, @Param("palletId") String palletId); + + /** + * @Description 根据标签号查询标签信息 - rqrq + * @param site 工厂编码 + * @param unitId 标签号 + * @return CountLabelData + * @author rqrq + */ + CountLabelData getLabelInfoByUnitId(@Param("site") String site, @Param("unitId") String unitId); + // ==================== 物料汇总查询 ==================== /** @@ -497,4 +527,14 @@ public interface PhysicalInventoryMapper extends BaseMapper { * @author rqrq */ String getCountType(@Param("site") String site, @Param("countNo") String countNo); + + /** + * @Description 根据栈板号查询关联的任务单号 - rqrq + * @param site 工厂编码 + * @param countNo 盘点单号 + * @param palletId 栈板号 + * @return String 任务号(可能为空) + * @author rqrq + */ + String getTaskNoByPallet(@Param("site") String site, @Param("countNo") String countNo, @Param("palletId") String palletId); } diff --git a/src/main/java/com/gaotao/modules/check/service/PhysicalInventoryService.java b/src/main/java/com/gaotao/modules/check/service/PhysicalInventoryService.java index 9fb74b7..57e6b30 100644 --- a/src/main/java/com/gaotao/modules/check/service/PhysicalInventoryService.java +++ b/src/main/java/com/gaotao/modules/check/service/PhysicalInventoryService.java @@ -254,4 +254,76 @@ public interface PhysicalInventoryService { * @author rqrq */ boolean hasUncompletedTask(String site, String countNo); + + // ==================== PDA手工盘点 ==================== + + /** + * @Description PDA扫描栈板 - 验证并返回盘点信息 - rqrq + * + *

业务逻辑:

+ *
+     * 1. 清洗栈板编码(去掉末尾L/R)
+     * 2. 检查是否有状态为CHECKING的盘点单
+     * 3. 验证栈板是否在盘点栈板明细中
+     * 4. 返回栈板的盘点标签明细
+     * 
+ * + * @param site 工厂编码 + * @param palletId 栈板号(可能带L/R后缀) + * @return Map 包含:cleanPalletId, countNo, labelList + * @author rqrq + */ + java.util.Map pdaScanPallet(String site, String palletId); + + /** + * @Description PDA扫描标签 - 获取标签信息 - rqrq + * @param site 工厂编码 + * @param unitId 标签号 + * @return CountLabelData 标签信息 + * @author rqrq + */ + CountLabelData pdaScanLabel(String site, String unitId); + + /** + * @Description PDA一键提交盘点(默认全部OK)- rqrq + * + *

业务逻辑:

+ *
+     * 1. 查询栈板的盘点标签明细
+     * 2. 删除本栈板已有的盘点结果
+     * 3. 插入全部OK的盘点结果
+     * 4. 更新标签和栈板的盘点状态
+     * 
+ * + * @param site 工厂编码 + * @param countNo 盘点单号 + * @param palletId 栈板号 + * @param username 操作人 + * @return int 处理的标签数 + * @author rqrq + */ + int pdaQuickSubmitCount(String site, String countNo, String palletId, String username); + + /** + * @Description PDA提交盘点结果 - rqrq + * + *

业务逻辑:

+ *
+     * 1. 查询栈板的盘点标签明细
+     * 2. 对比本地扫描记录,忽略不在明细中的标签
+     * 3. 删除本栈板已有的盘点结果
+     * 4. 插入盘点结果(OK/MISSING/SURPLUS)
+     * 5. 更新标签和栈板的盘点状态
+     * 
+ * + * @param site 工厂编码 + * @param countNo 盘点单号 + * @param palletId 栈板号 + * @param scannedLabels 扫描的标签列表(包含unitId, partNo, qty) + * @param username 操作人 + * @return int 处理的标签数 + * @author rqrq + */ + int pdaSubmitCount(String site, String countNo, String palletId, + java.util.List> scannedLabels, String username); } diff --git a/src/main/java/com/gaotao/modules/check/service/impl/PhysicalInventoryServiceImpl.java b/src/main/java/com/gaotao/modules/check/service/impl/PhysicalInventoryServiceImpl.java index 2523976..755acbc 100644 --- a/src/main/java/com/gaotao/modules/check/service/impl/PhysicalInventoryServiceImpl.java +++ b/src/main/java/com/gaotao/modules/check/service/impl/PhysicalInventoryServiceImpl.java @@ -470,23 +470,7 @@ public class PhysicalInventoryServiceImpl extends ServiceImpl assignedUnitIds = selectedLabels.stream() - .map(CountLabelInfo::getUnitId) - .collect(Collectors.toSet()); - // 合并已存在的标签ID - rqrq - assignedUnitIds.addAll(existingUnitIds); - - List extraLabels = new ArrayList<>(); - for (String palletId : selectedPallets) { - List extras = baseMapper.queryExtraLabelsByPallet( - query.getSite(), palletId, new ArrayList<>(assignedUnitIds)); - extraLabels.addAll(extras); - } - - log.info("同托盘关联标签数: {}", extraLabels.size()); - - // 6. 创建盘点标签子表 - rqrq + // 5. 创建盘点标签子表(只添加勾选的物料,不再附带同托盘其他物料)- rqrq List countLabels = new ArrayList<>(); // 添加指定物料标签(ASSIGNED)- rqrq @@ -496,13 +480,6 @@ public class PhysicalInventoryServiceImpl extends ServiceImpl allLabelInfos = new ArrayList<>(); allLabelInfos.addAll(selectedLabels); - allLabelInfos.addAll(extraLabels); + // allLabelInfos.addAll(extraLabels); List countPallets = new ArrayList<>(); for (String palletId : selectedPallets) { @@ -1501,4 +1478,258 @@ public class PhysicalInventoryServiceImpl extends ServiceImpl pdaScanPallet(String site, String palletId) { + log.info("pdaScanPallet 开始,site: {}, palletId: {}", site, palletId); + + // 1. 清洗栈板编码(去掉末尾L/R)- rqrq + String cleanPalletId = palletId; + if (palletId != null && palletId.length() > 0) { + char lastChar = palletId.charAt(palletId.length() - 1); + if (lastChar == 'R' || lastChar == 'L' || lastChar == 'r' || lastChar == 'l') { + cleanPalletId = palletId.substring(0, palletId.length() - 1); + log.info("栈板码最后一位是R或L,已自动去除,原始={}, 处理后={}", palletId, cleanPalletId); + } + } + + // 2. 检查是否有状态为CHECKING的盘点单 - rqrq + CountHeaderData activeCount = getCurrentActiveCount(site); + if (activeCount == null || !CountHeader.STATUS_CHECKING.equals(activeCount.getStatus())) { + throw new RuntimeException("当前没有进行中的盘点单据"); + } + String countNo = activeCount.getCountNo(); + log.info("找到进行中的盘点单: {}", countNo); + + // 3. 验证栈板是否在盘点栈板明细中 - rqrq + CountPalletData countPallet = baseMapper.getCountPalletByPalletId(site, cleanPalletId); + if (countPallet == null) { + throw new RuntimeException("该栈板不在当前盘点单的盘点范围内"); + } + + // 4. 查询栈板的盘点标签明细 - rqrq + List labelList = baseMapper.getCountLabelsByPalletId(site, countNo, cleanPalletId); + + log.info("pdaScanPallet 结束,栈板: {}, 标签数: {}", cleanPalletId, labelList.size()); + + java.util.Map result = new java.util.HashMap<>(); + result.put("cleanPalletId", cleanPalletId); + result.put("countNo", countNo); + result.put("labelList", labelList); + result.put("countPallet", countPallet); + return result; + } + + @Override + public CountLabelData pdaScanLabel(String site, String unitId) { + log.info("pdaScanLabel 开始,site: {}, unitId: {}", site, unitId); + + CountLabelData label = baseMapper.getLabelInfoByUnitId(site, unitId); + if (label == null) { + throw new RuntimeException("标签不存在: " + unitId); + } + + log.info("pdaScanLabel 结束,unitId: {}, partNo: {}", unitId, label.getPartNo()); + return label; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public int pdaQuickSubmitCount(String site, String countNo, String palletId, String username) { + log.info("pdaQuickSubmitCount 开始,site: {}, countNo: {}, palletId: {}", site, countNo, palletId); + + // 1. 查询栈板的盘点标签明细 - rqrq + List labelList = baseMapper.getCountLabelsByPalletId(site, countNo, palletId); + if (labelList.isEmpty()) { + throw new RuntimeException("该栈板没有盘点标签明细"); + } + + Date now = new Date(); + + // 2. 删除本栈板已有的盘点结果 - rqrq + baseMapper.deleteCountResultByPallet(site, countNo, palletId); + log.info("已删除栈板已有的盘点结果"); + + // 3. 插入全部OK的盘点结果 - rqrq + List resultList = new ArrayList<>(); + for (CountLabelData label : labelList) { + CountResult result = new CountResult(); + result.setSite(site); + result.setCountNo(countNo); + result.setUnitId(label.getUnitId()); + result.setPalletId(palletId); + result.setPartNo(label.getPartNo()); + result.setQty(label.getQty()); + result.setBatchNo(label.getBatchNo()); + result.setLocationId(label.getLocationId()); + result.setWarehouseId(label.getWarehouseId()); + result.setWdr(label.getWdr()); + result.setCountResult(CountResult.RESULT_OK); + result.setCountDate(now); + result.setCountUser(username); + result.setRemark("PDA一键提交-全部OK"); + result.setCreatedBy(username); + resultList.add(result); + } + + if (!resultList.isEmpty()) { + baseMapper.batchInsertCountResult(resultList); + log.info("已插入盘点结果,数量: {}", resultList.size()); + } + + // 4. 更新标签盘点状态 - rqrq + baseMapper.updateCountLabelFlagByPallet(site, countNo, palletId, username); + + // 5. 更新栈板盘点状态 - rqrq + baseMapper.updateCountPalletFlag(site, countNo, palletId, username); + + // 6. 处理任务单(与RFID接口一致)- rqrq + handleTaskAfterCount(site, countNo, palletId, username); + + log.info("pdaQuickSubmitCount 结束,处理标签数: {}", labelList.size()); + return labelList.size(); + } + + @Override + @Transactional(rollbackFor = Exception.class) + public int pdaSubmitCount(String site, String countNo, String palletId, + java.util.List> scannedLabels, String username) { + log.info("pdaSubmitCount 开始,site: {}, countNo: {}, palletId: {}, 扫描标签数: {}", + site, countNo, palletId, scannedLabels != null ? scannedLabels.size() : 0); + + // 1. 查询栈板的盘点标签明细 - rqrq + List labelList = baseMapper.getCountLabelsByPalletId(site, countNo, palletId); + if (labelList.isEmpty()) { + throw new RuntimeException("该栈板没有盘点标签明细"); + } + + // 2. 构建明细unitId集合 - rqrq + Set expectedUnitIds = labelList.stream() + .map(CountLabelData::getUnitId) + .collect(Collectors.toSet()); + + // 3. 构建扫描记录Map(只保留在明细中的)- rqrq + java.util.Map> scannedMap = new java.util.HashMap<>(); + if (scannedLabels != null) { + for (java.util.Map scanned : scannedLabels) { + String unitId = (String) scanned.get("unitId"); + if (expectedUnitIds.contains(unitId)) { + scannedMap.put(unitId, scanned); + } else { + log.info("忽略不在明细中的标签(多扫了): {}", unitId); + } + } + } + + Date now = new Date(); + + // 4. 删除本栈板已有的盘点结果 - rqrq + baseMapper.deleteCountResultByPallet(site, countNo, palletId); + log.info("已删除栈板已有的盘点结果"); + + // 5. 生成盘点结果 - rqrq + List resultList = new ArrayList<>(); + for (CountLabelData label : labelList) { + CountResult result = new CountResult(); + result.setSite(site); + result.setCountNo(countNo); + result.setUnitId(label.getUnitId()); + result.setPalletId(palletId); + result.setPartNo(label.getPartNo()); + result.setQty(label.getQty()); + result.setBatchNo(label.getBatchNo()); + result.setLocationId(label.getLocationId()); + result.setWarehouseId(label.getWarehouseId()); + result.setWdr(label.getWdr()); + result.setCountDate(now); + result.setCountUser(username); + result.setCreatedBy(username); + + if (scannedMap.containsKey(label.getUnitId())) { + // 扫描到了,OK + result.setCountResult(CountResult.RESULT_OK); + result.setRemark("PDA扫描确认存在"); + } else { + // 没扫描到,MISSING + result.setCountResult(CountResult.RESULT_MISSING); + result.setRemark("PDA扫描未发现该标签(盘亏)"); + } + resultList.add(result); + } + + if (!resultList.isEmpty()) { + baseMapper.batchInsertCountResult(resultList); + log.info("已插入盘点结果,数量: {}", resultList.size()); + } + + // 6. 更新标签盘点状态 - rqrq + baseMapper.updateCountLabelFlagByPallet(site, countNo, palletId, username); + + // 7. 更新栈板盘点状态 - rqrq + baseMapper.updateCountPalletFlag(site, countNo, palletId, username); + + // 8. 处理任务单(与RFID接口一致)- rqrq + handleTaskAfterCount(site, countNo, palletId, username); + + log.info("pdaSubmitCount 结束,处理标签数: {}", labelList.size()); + return labelList.size(); + } + + /** + * @Description 盘点完成后处理任务单(与RFID接口逻辑一致)- rqrq + * + *

处理逻辑:

+ *
    + *
  1. 查询该栈板关联的任务号(task_no)
  2. + *
  3. 如果有任务号,更新wms_order_task_detail状态为已完成
  4. + *
  5. 检查该任务的所有明细是否都已完成
  6. + *
  7. 如果都完成了,更新主表状态为"已完成",并触发下一批推送
  8. + *
+ * + * @param site 工厂编码 + * @param countNo 盘点单号 + * @param palletId 栈板号 + * @param username 操作人 + * @author rqrq + */ + private void handleTaskAfterCount(String site, String countNo, String palletId, String username) { + // 1. 查询该栈板关联的任务号 - rqrq + String taskNo = baseMapper.getTaskNoByPallet(site, countNo, palletId); + + if (!StringUtils.hasText(taskNo)) { + // 没有任务号,说明不是通过推送出库的,不需要处理任务单 - rqrq + log.info("该栈板没有关联任务号,跳过任务单处理,palletId: {}", palletId); + return; + } + + log.info("开始处理任务单,taskNo: {}, palletId: {}", taskNo, palletId); + + // 2. 更新wms_order_task_detail状态为已完成 - rqrq + baseMapper.updateTaskDetailStatusByPallet(site, taskNo, palletId); + log.info("已更新wms_order_task_detail状态为已完成,palletId: {}", palletId); + + // 3. 检查该任务的所有明细是否都已完成,且主表状态未完成时才触发下一批推送 - rqrq + String taskStatus = baseMapper.getWmsOrderTaskStatus(site, taskNo); + if ("已完成".equals(taskStatus)) { + // 任务已完成,说明是重复调用,不再触发下一批推送 - rqrq + log.info("wms_order_task已是已完成状态,跳过触发下一批推送(可能是重复调用)"); + } else { + int uncompleteCount = baseMapper.checkAllTaskDetailCompletedByTaskNo(site, taskNo); + if (uncompleteCount == 0) { + // 所有明细都已完成,更新主表状态 - rqrq + baseMapper.updateTaskStatusCompleted(site, taskNo); + log.info("该任务所有明细已完成,主表状态已更新为已完成"); + + // 4. 触发下一批推送 - rqrq + CountHeaderData query = new CountHeaderData(); + query.setSite(site); + query.setCountNo(countNo); + query.setUsername(username); + int pushedCount = continuePushCount(query); + log.info("触发下一批推送,推送数量: {}", pushedCount); + } + } + } } diff --git a/src/main/resources/mapper/check/PhysicalInventoryMapper.xml b/src/main/resources/mapper/check/PhysicalInventoryMapper.xml index 191f254..04f50cc 100644 --- a/src/main/resources/mapper/check/PhysicalInventoryMapper.xml +++ b/src/main/resources/mapper/check/PhysicalInventoryMapper.xml @@ -544,6 +544,58 @@ WHERE cr.site = #{site} AND cr.count_no = #{countNo} ) + + + + + + + + + SELECT count_type FROM count_header WHERE site = #{site} AND count_no = #{countNo} + + +