| | |
| | | import com.vincent.rsf.framework.common.R; |
| | | import com.vincent.rsf.framework.exception.CoolException; |
| | | import com.vincent.rsf.server.api.utils.LocUtils; |
| | | import com.vincent.rsf.server.manager.constant.CloudWmsInoutReportMode; |
| | | import com.vincent.rsf.server.manager.controller.params.GenerateTaskParams; |
| | | import com.vincent.rsf.server.manager.entity.CloudWmsNotifyLog; |
| | | import com.vincent.rsf.server.manager.entity.*; |
| | |
| | | import org.springframework.http.ResponseEntity; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | import org.springframework.transaction.support.TransactionSynchronization; |
| | | import org.springframework.transaction.support.TransactionSynchronizationManager; |
| | | import org.springframework.web.client.HttpStatusCodeException; |
| | | import org.springframework.web.client.RestTemplate; |
| | | |
| | |
| | | throw new CoolException("组托明细修执行数量修改失败!!"); |
| | | } |
| | | }); |
| | | syncAsnOrderItemBarcodeByPakin(waitPakinItems, pakin.getBarcode(), loginUserId); |
| | | }); |
| | | |
| | | if (!waitPakinService.update(new LambdaUpdateWrapper<WaitPakin>() |
| | |
| | | throw new CoolException("组托明细修执行数量修改失败!!"); |
| | | } |
| | | }); |
| | | syncAsnOrderItemBarcodeByPakin(waitPakinItems, pakin.getBarcode(), loginUserId); |
| | | }); |
| | | |
| | | if (!waitPakinService.update(new LambdaUpdateWrapper<WaitPakin>() |
| | |
| | | throw new CoolException("组托明细修执行数量修改失败!!"); |
| | | } |
| | | }); |
| | | syncAsnOrderItemBarcodeByPakin(waitPakinItems, pakin.getBarcode(), loginUserId); |
| | | }); |
| | | |
| | | if (!waitPakinService.update(new LambdaUpdateWrapper<WaitPakin>() |
| | |
| | | throw new CoolException("组拖状态修改失败!!"); |
| | | } |
| | | return R.ok("任务生成完毕!"); |
| | | } |
| | | |
| | | /** 组托后将通知单明细条码回写为料箱码 */ |
| | | private void syncAsnOrderItemBarcodeByPakin(List<WaitPakinItem> waitPakinItems, String pakinBarcode, Long loginUserId) { |
| | | if (waitPakinItems == null || waitPakinItems.isEmpty() || StringUtils.isBlank(pakinBarcode)) { |
| | | return; |
| | | } |
| | | Set<Long> asnItemIds = waitPakinItems.stream() |
| | | .map(WaitPakinItem::getAsnItemId) |
| | | .filter(Objects::nonNull) |
| | | .collect(Collectors.toSet()); |
| | | if (asnItemIds.isEmpty()) { |
| | | return; |
| | | } |
| | | if (!asnOrderItemService.update(new LambdaUpdateWrapper<WkOrderItem>() |
| | | .in(WkOrderItem::getId, asnItemIds) |
| | | .set(WkOrderItem::getBarcode, pakinBarcode) |
| | | .set(WkOrderItem::getUpdateBy, loginUserId) |
| | | .set(WkOrderItem::getUpdateTime, new Date()))) { |
| | | throw new CoolException("通知单明细条码回写失败!!"); |
| | | } |
| | | } |
| | | |
| | | /** |
| | |
| | | if (StringUtils.isNotBlank(task.getTaskCode())) { |
| | | rcsBusTaskNoticeService.notifyTaskStatus(task.getTaskCode(), task.getTaskStatus()); |
| | | } |
| | | final Long taskIdForFinish = task.getId(); |
| | | if (TransactionSynchronizationManager.isSynchronizationActive()) { |
| | | TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization() { |
| | | @Override |
| | | public void afterCommit() { |
| | | taskService.runStockFinishAfterManualComplete(taskIdForFinish); |
| | | } |
| | | }); |
| | | } |
| | | return task; |
| | | } |
| | | |
| | | @Override |
| | | public void runStockFinishAfterManualComplete(Long taskId) { |
| | | if (taskId == null) { |
| | | return; |
| | | } |
| | | try { |
| | | Task t = taskService.getById(taskId); |
| | | if (t == null) { |
| | | return; |
| | | } |
| | | if (Objects.equals(t.getTaskStatus(), TaskStsType.COMPLETE_IN.id)) { |
| | | taskService.complateInTask(Collections.singletonList(t)); |
| | | } else if (Objects.equals(t.getTaskStatus(), TaskStsType.COMPLETE_OUT.id)) { |
| | | taskService.completeTask(Collections.singletonList(t)); |
| | | } |
| | | } catch (Exception e) { |
| | | log.warn("手动完结后立即库存收尾失败,将由定时任务重试,taskId={}:{}", taskId, e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 全版出库完结:扣除库位数量,将库位状态设为空 |
| | | * 全板出库完结:扣除库位数量,将库位状态设为空 |
| | | * |
| | | * @param id 任务ID |
| | | * @param loginUserId 登录用户ID |
| | | * @param notifyRcsFromAdmin 管理后台全版出库完结接口为 true 时通知 RCS;定时/PDA 等为 false |
| | | * @param notifyRcsFromAdmin 管理后台全板出库完结接口为 true 时通知 RCS;定时/PDA 等为 false |
| | | * @return 任务对象 |
| | | */ |
| | | @Override |
| | |
| | | throw new CoolException("任务不存在!!"); |
| | | } |
| | | |
| | | // 检查任务类型是否为全版出库 |
| | | // 检查任务类型是否为全板出库 |
| | | if (!task.getTaskType().equals(TaskType.TASK_TYPE_OUT.type)) { |
| | | throw new CoolException("当前任务不是全版出库任务,无法执行此操作!!"); |
| | | throw new CoolException("当前任务不是全板出库任务,无法执行此操作!!"); |
| | | } |
| | | |
| | | // 检查任务状态:必须是199(WAVE_SEED)状态才能手动完结 |
| | |
| | | if (!taskService.updateById(task)) { |
| | | throw new CoolException("任务状态修改失败!!"); |
| | | } |
| | | // 9.1 入/出库结果上报:拣料再入库/盘点再入库完成后通知云仓(与定时任务闭环一致) |
| | | reportInOutResultToCloud(task, loc, taskItems, null, true); |
| | | // 盘点再入库上报云仓入库完成;拣料再入库跳过(入库侧 qty 取 anfme 为托盘余量;云仓出库实发在出库完成侧) |
| | | // reportInOutResultToCloud(task, loc, taskItems, null, true); |
| | | if (!TaskType.TASK_TYPE_PICK_IN.type.equals(task.getTaskType())) { |
| | | reportInOutResultToCloud(task, loc, taskItems, null, true); |
| | | } |
| | | } |
| | | |
| | | /** |
| | |
| | | log.debug("[拣料入库] 计算后 pickedQty={}, minQty(剩余)={}, 将更新 taskItem.anfme={}, taskItem.qty={}", |
| | | pickedQty, minQty, minQty, pickedQty); |
| | | if (QuantityUtils.isNonNegative(minQty)) { |
| | | enqueueCloudWmsOutNotifyLogEarly(task, taskItem, QuantityUtils.toScaledBigDecimal(pickedQty)); |
| | | taskItem.setAnfme(minQty); |
| | | taskItem.setQty(pickedQty); |
| | | if (!taskItemService.updateById(taskItem)) { |
| | |
| | | if (allItems.isEmpty()) { |
| | | throw new CoolException("任务明细为空"); |
| | | } |
| | | List<Long> allItemIds = allItems.stream().map(TaskItem::getId).filter(Objects::nonNull).collect(Collectors.toList()); |
| | | Map<Long, BigDecimal> preQtyByItem = cloudWmsNotifyLogService.mapOutQtyFromInOutNotifyLogByTaskItemIds(allItemIds); |
| | | Long loginUserId = SystemAuthUtils.getLoginUserId(); |
| | | if (loginUserId == null) { |
| | | loginUserId = 1L; |
| | |
| | | Map<String, Double> remainderByKey = new LinkedHashMap<>(); |
| | | for (Map.Entry<String, List<TaskItem>> e : byKey.entrySet()) { |
| | | List<TaskItem> group = e.getValue(); |
| | | double totalQty = group.stream().mapToDouble(ti -> ti.getQty() != null && ti.getQty() > 0 ? ti.getQty() : (ti.getAnfme() != null ? ti.getAnfme() : 0)).sum(); |
| | | BigDecimal totalBd = BigDecimal.ZERO; |
| | | for (TaskItem ti : group) { |
| | | BigDecimal q = preQtyByItem.get(ti.getId()); |
| | | if (q == null) { |
| | | throw new CoolException("云仓待办无出库数量,taskItemId=" + ti.getId()); |
| | | } |
| | | totalBd = totalBd.add(q); |
| | | } |
| | | double totalQty = totalBd.setScale(6, RoundingMode.HALF_UP).doubleValue(); |
| | | TaskItem rep = group.get(0); |
| | | TaskItem forDeduct = new TaskItem(); |
| | | forDeduct.setMatnrId(rep.getMatnrId()).setBatch(rep.getBatch()).setFieldsIndex(rep.getFieldsIndex()).setQty(totalQty); |
| | |
| | | if (group == null || group.isEmpty()) continue; |
| | | TaskItem rep = group.get(0); |
| | | TaskItem ti = new TaskItem(); |
| | | ti.setTaskId(pickInTask.getId()); |
| | | ti.setMatnrId(rep.getMatnrId()).setMaktx(rep.getMaktx()).setMatnrCode(rep.getMatnrCode()); |
| | | ti.setBatch(rep.getBatch()).setFieldsIndex(rep.getFieldsIndex()).setUnit(rep.getUnit()).setSpec(rep.getSpec()).setModel(rep.getModel()); |
| | | ti.setAnfme(rem).setQty(0.0); |
| | | BeanUtils.copyProperties(rep, ti); |
| | | ti.setId(null) |
| | | .setTaskId(pickInTask.getId()) |
| | | .setAnfme(rem) |
| | | .setQty(0.0) |
| | | .setWorkQty(0.0) |
| | | .setCreateBy(loginUserId) |
| | | .setUpdateBy(loginUserId) |
| | | .setCreateTime(new Date()) |
| | | .setUpdateTime(new Date()); |
| | | taskItemService.save(ti); |
| | | LocItemWorking w = new LocItemWorking(); |
| | | w.setTaskId(pickInTask.getId()); |
| | |
| | | try { |
| | | // 根据任务类型更新库位明细 |
| | | if (task.getTaskType().equals(TaskType.TASK_TYPE_OUT.type)) { |
| | | // 全版出库:不删除库位明细,等待PDA快速拣货确认时再删除 |
| | | // 全板出库:不删除库位明细,等待PDA快速拣货确认时再删除 |
| | | // subtractLocItem(loc); // 已移除,改为在completeFullOutStock中删除 |
| | | } else if (!TaskType.TASK_TYPE_PICK_AGAIN_OUT.type.equals(task.getTaskType())) { |
| | | // 部分出库(如盘点出库):根据TaskItem数量扣减库位明细;拣料出库在生成拣料入库单时扣减 |
| | |
| | | // 拣料出库/盘点出库:在未生成拣料入库单之前保持 R.预约出库,否则下发任务时查不到该库位(只查 F+R)导致“库存不足” |
| | | // 等 PDA 确认并生成拣料入库任务时,再在 pickOrCheckTask 中将目标库位改为 S.预约入库 |
| | | } else if (task.getTaskType().equals(TaskType.TASK_TYPE_OUT.type)) { |
| | | // 全版出库:不更新库位状态为O,等待PDA快速拣货确认时再更新 |
| | | // 全板出库:不更新库位状态为O,等待PDA快速拣货确认时再更新 |
| | | // 库位状态保持原样(R.出库预约状态) |
| | | } else { |
| | | /**修改为库位状态为O.空库*/ |
| | |
| | | if (StringUtils.isBlank(ruleCode)) { |
| | | throw new CoolException("当前业务:" + SerialRuleCode.SYS_STOCK_CODE + ",编码规则不存在!!"); |
| | | } |
| | | Double sum = taskItems.stream().mapToDouble(TaskItem::getAnfme).sum(); |
| | | List<Long> itemIds = taskItems.stream().map(TaskItem::getId).filter(Objects::nonNull).collect(Collectors.toList()); |
| | | Map<Long, BigDecimal> preMap = cloudWmsNotifyLogService.mapOutQtyFromInOutNotifyLogByTaskItemIds(itemIds); |
| | | BigDecimal sumBd = BigDecimal.ZERO; |
| | | for (TaskItem ti : taskItems) { |
| | | BigDecimal q = preMap.get(ti.getId()); |
| | | if (q == null) { |
| | | throw new CoolException("云仓待办无出库数量,taskItemId=" + ti.getId()); |
| | | } |
| | | sumBd = sumBd.add(q); |
| | | } |
| | | sumBd = sumBd.setScale(6, RoundingMode.HALF_UP); |
| | | Double sum = sumBd.doubleValue(); |
| | | stock.setCode(ruleCode) |
| | | .setUpdateBy(loginUserId) |
| | | .setUpdateTime(new Date()) |
| | |
| | | WkOrder wkOrder = asnOrderService.getById(orderId); |
| | | if (wkOrder != null) { |
| | | Double curQty = wkOrder.getQty() != null ? wkOrder.getQty() : 0.0; |
| | | Double newQty = QuantityUtils.roundToScale(curQty + sum); |
| | | wkOrder.setExceStatus(AsnExceStatus.OUT_STOCK_STATUS_TASK_WORKING.val).setQty(newQty); |
| | | BigDecimal newQtyBd = BigDecimal.valueOf(curQty).add(sumBd).setScale(6, RoundingMode.HALF_UP); |
| | | wkOrder.setExceStatus(AsnExceStatus.OUT_STOCK_STATUS_TASK_WORKING.val).setQty(newQtyBd.doubleValue()); |
| | | if (!asnOrderService.updateById(wkOrder)) { |
| | | throw new CoolException("出库单完成数量更新失败!!"); |
| | | } |
| | | } |
| | | // 按出库单明细汇总本次任务数量,更新各明细 workQty |
| | | Map<Long, Double> sumByOrderItemId = taskItems.stream() |
| | | .filter(ti -> ti.getOrderItemId() != null) |
| | | .collect(Collectors.groupingBy(TaskItem::getOrderItemId, |
| | | Collectors.summingDouble(ti -> ti.getAnfme() != null ? ti.getAnfme() : 0.0))); |
| | | for (Map.Entry<Long, Double> e : sumByOrderItemId.entrySet()) { |
| | | Map<Long, BigDecimal> sumByOrderItemId = new HashMap<>(); |
| | | for (TaskItem ti : taskItems) { |
| | | if (ti.getOrderItemId() == null) { |
| | | continue; |
| | | } |
| | | BigDecimal q = preMap.get(ti.getId()); |
| | | sumByOrderItemId.merge(ti.getOrderItemId(), q, BigDecimal::add); |
| | | } |
| | | for (Map.Entry<Long, BigDecimal> e : sumByOrderItemId.entrySet()) { |
| | | WkOrderItem oi = outStockItemService.getById(e.getKey()); |
| | | if (oi != null) { |
| | | Double wq = oi.getWorkQty() != null ? oi.getWorkQty() : 0.0; |
| | | oi.setWorkQty(QuantityUtils.roundToScale(wq + e.getValue())); |
| | | BigDecimal nwq = BigDecimal.valueOf(wq).add(e.getValue()).setScale(6, RoundingMode.HALF_UP); |
| | | oi.setWorkQty(nwq.doubleValue()); |
| | | if (!outStockItemService.updateById(oi)) { |
| | | throw new CoolException("出库单明细执行数量更新失败!!"); |
| | | } |
| | |
| | | } |
| | | } else if (!Objects.isNull(orderItem) && StringUtils.isNotBlank(orderItem.getId() + "")) { |
| | | WkOrder wkOrder = asnOrderService.getById(orderItem.getOrderId()); |
| | | Double qty = Math.round((wkOrder.getQty() + sum) * 1000000) / 1000000.0; |
| | | double curHeaderQty = wkOrder.getQty() != null ? wkOrder.getQty() : 0.0; |
| | | Double qty = QuantityUtils.roundToScale(QuantityUtils.add(curHeaderQty, sum)); |
| | | wkOrder.setExceStatus(AsnExceStatus.OUT_STOCK_STATUS_TASK_WORKING.val) |
| | | .setQty(qty); |
| | | if (!asnOrderService.updateById(wkOrder)) { |
| | |
| | | /**通过任务明细中的taskId查询,获取TASK的目标库位信息*/ |
| | | StockItem stockItem = new StockItem(); |
| | | BeanUtils.copyProperties(item, stockItem); |
| | | stockItem.setAnfme(QuantityUtils.roundToScale(preMap.get(item.getId()))); |
| | | stockItem.setSourceItemId(item.getOrderItemId()) |
| | | .setUpdateBy(loginUserId) |
| | | .setUpdateTime(new Date()) |
| | |
| | | /** |
| | | * @author Ryan |
| | | * @date 2025/5/20 |
| | | * @description: 扣减库存明细(全版出库:删除所有库位明细) |
| | | * @description: 扣减库存明细(全板出库:删除所有库位明细) |
| | | * @version 1.0 |
| | | */ |
| | | @Transactional(rollbackFor = Exception.class) |
| | |
| | | WkOrder o = asnOrderService.getById(e.getKey()); |
| | | if (o != null) { |
| | | Double newQty = QuantityUtils.roundToScale(QuantityUtils.add(o.getQty() != null ? o.getQty() : 0.0, e.getValue())); |
| | | Double planQty = QuantityUtils.roundToScale(o.getAnfme() != null ? o.getAnfme() : 0.0); |
| | | if (QuantityUtils.compare(newQty, planQty) > 0) { |
| | | newQty = planQty; |
| | | } |
| | | o.setQty(newQty); |
| | | if (!asnOrderService.updateById(o)) { |
| | | throw new CoolException("入库单完成数量更新失败!!"); |
| | |
| | | WkOrderItem oi = asnOrderItemService.getById(e.getKey()); |
| | | if (oi != null) { |
| | | Double newQty = QuantityUtils.roundToScale(QuantityUtils.add(oi.getQty() != null ? oi.getQty() : 0.0, e.getValue())); |
| | | Double planQty = QuantityUtils.roundToScale(oi.getAnfme() != null ? oi.getAnfme() : 0.0); |
| | | if (QuantityUtils.compare(newQty, planQty) > 0) { |
| | | newQty = planQty; |
| | | } |
| | | oi.setQty(newQty); |
| | | if (!asnOrderItemService.updateById(oi)) { |
| | | throw new CoolException("入库单明细完成数量更新失败!!"); |
| | |
| | | } |
| | | } |
| | | |
| | | @Override |
| | | public void enqueueCloudWmsOutNotifyLogEarly(Task task, TaskItem taskItem, BigDecimal outQty) { |
| | | if (task == null || taskItem == null || outQty == null) { |
| | | return; |
| | | } |
| | | try { |
| | | Loc loc = locService.getOne(new LambdaQueryWrapper<Loc>().eq(Loc::getCode, task.getOrgLoc())); |
| | | if (loc == null) { |
| | | return; |
| | | } |
| | | CloudInOutReportContext ctx = loadCloudInOutReportContext(task, loc, Collections.singletonList(taskItem), null, false); |
| | | if (ctx == null) { |
| | | return; |
| | | } |
| | | InOutResultReportParam param = buildInOutParamForItem(task, taskItem, false, outQty, ctx); |
| | | if (param == null) { |
| | | return; |
| | | } |
| | | String mode = resolveCloudWmsInoutReportMode(); |
| | | boolean sendHold = CloudWmsInoutReportMode.MANUAL.equals(mode) || CloudWmsInoutReportMode.WAIT_ORDER.equals(mode); |
| | | cloudWmsNotifyLogService.saveOrUpdateInOutNotifyEarly(param, task.getId(), taskItem.getId(), sendHold, taskItem.getTenantId()); |
| | | } catch (Exception e) { |
| | | log.warn("云仓9.1早Enqueue失败 taskId={} taskItemId={}:{}", task.getId(), taskItem.getId(), e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 9.1 入/出库结果上报待办 |
| | | * @param isInbound true 入库完成,false 出库完成 |
| | |
| | | */ |
| | | private void reportInOutResultToCloud(Task task, Loc loc, List<TaskItem> taskItems, Set<Long> pkinItemIds, boolean isInbound) { |
| | | try { |
| | | String locId = isInbound ? task.getTargLoc() : task.getOrgLoc(); |
| | | String wareHouseId = null; |
| | | if (loc.getWarehouseId() != null) { |
| | | Warehouse wh = warehouseService.getById(loc.getWarehouseId()); |
| | | if (wh != null) { |
| | | wareHouseId = wh.getCode(); |
| | | } |
| | | } |
| | | if (wareHouseId == null) { |
| | | log.warn("入/出库结果上报待办跳过:仓库编码为空,taskId={}", task.getId()); |
| | | CloudInOutReportContext ctx = loadCloudInOutReportContext(task, loc, taskItems, pkinItemIds, isInbound); |
| | | if (ctx == null) { |
| | | return; |
| | | } |
| | | Map<Long, String> sourceToOrderNo = new HashMap<>(); |
| | | if (isInbound && pkinItemIds != null && !pkinItemIds.isEmpty()) { |
| | | List<WaitPakinItem> pakinItems = waitPakinItemService.list(new LambdaQueryWrapper<WaitPakinItem>().in(WaitPakinItem::getId, pkinItemIds)); |
| | | for (WaitPakinItem p : pakinItems) { |
| | | if (p.getAsnCode() != null) { |
| | | sourceToOrderNo.put(p.getId(), p.getAsnCode()); |
| | | } |
| | | } |
| | | } |
| | | // 出库仅云仓来源单据参与上报 |
| | | if (!isInbound) { |
| | | boolean hasCloudSource = taskItems.stream().anyMatch(this::hasCloudOrderRef); |
| | | if (!hasCloudSource) { |
| | | // log.info("入/出库结果上报待办跳过:无云仓来源单据,taskId={}", task.getId()); |
| | | log.info("入/出库结果上报待办跳过:手动创建出库单据不通知云仓,taskId={}", task.getId()); |
| | | return; |
| | | } |
| | | } |
| | | List<Long> reportItemIds = taskItems.stream().map(TaskItem::getId).filter(Objects::nonNull).collect(Collectors.toList()); |
| | | Map<Long, BigDecimal> outQtyByItem = isInbound ? Collections.emptyMap() |
| | | : cloudWmsNotifyLogService.mapOutQtyFromInOutNotifyLogByTaskItemIds(reportItemIds); |
| | | ObjectMapper om = new ObjectMapper(); |
| | | Date now = new Date(); |
| | | String mode = resolveCloudWmsInoutReportMode(); |
| | | boolean sendHold = CloudWmsInoutReportMode.MANUAL.equals(mode) || CloudWmsInoutReportMode.WAIT_ORDER.equals(mode); |
| | | for (TaskItem item : taskItems) { |
| | | if (!isInbound && !hasCloudOrderRef(item)) { |
| | | if (item == null || item.getId() == null) { |
| | | continue; |
| | | } |
| | | String orderNo = isInbound ? sourceToOrderNo.get(item.getSource()) : (item.getPlatOrderCode() != null ? item.getPlatOrderCode() : item.getPlatWorkCode()); |
| | | if (orderNo == null && isInbound) { |
| | | orderNo = item.getPlatOrderCode() != null ? item.getPlatOrderCode() : item.getPlatWorkCode(); |
| | | } |
| | | if (orderNo == null || item.getMatnrCode() == null) { |
| | | BigDecimal outboundQty = isInbound ? null : outQtyByItem.get(item.getId()); |
| | | if (!isInbound && outboundQty == null) { |
| | | log.warn("云仓9.1跳过:待办无出库数量,taskId={},taskItemId={}", task.getId(), item.getId()); |
| | | continue; |
| | | } |
| | | InOutResultReportParam param = new InOutResultReportParam() |
| | | .setOrderNo(orderNo) |
| | | .setPlanNo(item.getPlatWorkCode()) |
| | | .setLineId(item.getPlatItemId()) |
| | | .setWareHouseId(wareHouseId) |
| | | .setLocId(locId) |
| | | .setMatNr(item.getMatnrCode()) |
| | | .setQty(item.getAnfme() != null ? String.valueOf(item.getAnfme()) : "0") |
| | | .setBatch(item.getBatch()) |
| | | .setInbound(isInbound) |
| | | .setBarcode(task.getBarcode()); |
| | | InOutResultReportParam param = buildInOutParamForItem(task, item, isInbound, outboundQty, ctx); |
| | | if (param == null) { |
| | | continue; |
| | | } |
| | | if (!isInbound && cloudWmsNotifyLogService.hasInOutNotifyRowForTaskItem(item.getId(), false)) { |
| | | continue; |
| | | } |
| | | if (isInbound && cloudWmsNotifyLogService.hasInOutNotifyRowForTaskItem(item.getId(), true)) { |
| | | continue; |
| | | } |
| | | String orderNo = param.getOrderNo(); |
| | | try { |
| | | String requestBody = om.writeValueAsString(param); |
| | | String bizRef = "taskId=" + task.getId() + ",taskItemId=" + item.getId() + ",orderNo=" + orderNo; |
| | | CloudWmsNotifyLog notifyLog = new CloudWmsNotifyLog() |
| | | .setReportType(cloudWmsNotifyLogService.getReportTypeInOutResult()) |
| | | .setRequestBody(requestBody) |
| | | .setNotifyStatus(cloudWmsNotifyLogService.getNotifyStatusPending()) |
| | | .setRetryCount(0) |
| | | .setBizRef("taskId=" + task.getId() + ",orderNo=" + orderNo) |
| | | .setBizRef(bizRef) |
| | | .setCreateTime(now) |
| | | .setUpdateTime(now); |
| | | .setUpdateTime(now) |
| | | .setSourceOrderNo(orderNo) |
| | | .setInboundFlag(isInbound ? 1 : 0) |
| | | .setWareHouseCode(ctx.wareHouseId) |
| | | .setSendHold(sendHold ? 1 : 0) |
| | | .setSending(0); |
| | | cloudWmsNotifyLogService.fillFromConfig(notifyLog); |
| | | cloudWmsNotifyLogService.save(notifyLog); |
| | | } catch (JsonProcessingException e) { |
| | | log.warn("入/出库结果上报待办落库失败(不影响主流程),taskId={},orderNo={}:{}", task.getId(), orderNo, e.getMessage()); |
| | | } catch (JsonProcessingException ex) { |
| | | log.warn("入/出库结果上报待办落库失败(不影响主流程),taskId={},orderNo={}:{}", task.getId(), orderNo, ex.getMessage()); |
| | | } |
| | | } |
| | | } catch (Exception e) { |
| | | log.warn("入/出库结果上报待办失败,taskId={},isInbound={}:{}", task.getId(), isInbound, e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | private CloudInOutReportContext loadCloudInOutReportContext(Task task, Loc loc, List<TaskItem> taskItems, Set<Long> pkinItemIds, boolean isInbound) { |
| | | if (task == null || loc == null || taskItems == null || taskItems.isEmpty()) { |
| | | return null; |
| | | } |
| | | String locId = isInbound ? task.getTargLoc() : task.getOrgLoc(); |
| | | String wareHouseId = null; |
| | | if (loc.getWarehouseId() != null) { |
| | | Warehouse wh = warehouseService.getById(loc.getWarehouseId()); |
| | | if (wh != null) { |
| | | wareHouseId = wh.getCode(); |
| | | } |
| | | } |
| | | if (wareHouseId == null) { |
| | | log.warn("入/出库结果上报待办跳过:仓库编码为空,taskId={}", task.getId()); |
| | | return null; |
| | | } |
| | | Map<Long, String> sourceToOrderNo = new HashMap<>(); |
| | | if (isInbound && pkinItemIds != null && !pkinItemIds.isEmpty()) { |
| | | List<WaitPakinItem> pakinItems = waitPakinItemService.list(new LambdaQueryWrapper<WaitPakinItem>().in(WaitPakinItem::getId, pkinItemIds)); |
| | | for (WaitPakinItem p : pakinItems) { |
| | | if (p.getAsnCode() != null) { |
| | | sourceToOrderNo.put(p.getId(), p.getAsnCode()); |
| | | } |
| | | } |
| | | } |
| | | boolean hasOutboundCloudLine = !isInbound && taskItems.stream().anyMatch(ti -> |
| | | ti != null && ti.getOrderId() != null && StringUtils.isNotBlank(ti.getPlatItemId())); |
| | | boolean hasCloudSource = taskItems.stream().anyMatch(this::hasCloudOrderRef) |
| | | || (isInbound && !sourceToOrderNo.isEmpty()) |
| | | || hasOutboundCloudLine; |
| | | if (!hasCloudSource) { |
| | | log.info("入/出库结果上报待办跳过:无云仓来源单据,taskId={}", task.getId()); |
| | | return null; |
| | | } |
| | | Set<Long> orderIdSet = taskItems.stream() |
| | | .filter(Objects::nonNull) |
| | | .map(TaskItem::getOrderId) |
| | | .filter(Objects::nonNull) |
| | | .collect(Collectors.toSet()); |
| | | Map<Long, WkOrder> orderById = new HashMap<>(); |
| | | if (!orderIdSet.isEmpty()) { |
| | | for (WkOrder o : asnOrderService.listByIds(orderIdSet)) { |
| | | if (o != null && o.getId() != null) { |
| | | orderById.put(o.getId(), o); |
| | | } |
| | | } |
| | | } |
| | | Set<String> orderCodeSet = new HashSet<>(); |
| | | for (TaskItem ti : taskItems) { |
| | | if (ti == null) { |
| | | continue; |
| | | } |
| | | String on = isInbound && ti.getSource() != null |
| | | ? sourceToOrderNo.get(ti.getSource()) |
| | | : (ti.getPlatOrderCode() != null ? ti.getPlatOrderCode() : ti.getPlatWorkCode()); |
| | | if (on == null && isInbound) { |
| | | on = ti.getPlatOrderCode() != null ? ti.getPlatOrderCode() : ti.getPlatWorkCode(); |
| | | } |
| | | if (on == null && !isInbound && ti.getOrderId() != null) { |
| | | WkOrder o = orderById.get(ti.getOrderId()); |
| | | if (o != null) { |
| | | on = StringUtils.isNotBlank(o.getPoCode()) ? o.getPoCode() : o.getCode(); |
| | | } |
| | | } |
| | | if (StringUtils.isNotBlank(on)) { |
| | | orderCodeSet.add(on); |
| | | } |
| | | } |
| | | Map<String, WkOrder> orderByCode = new HashMap<>(); |
| | | if (!orderCodeSet.isEmpty()) { |
| | | for (WkOrder o : asnOrderService.list(new LambdaQueryWrapper<WkOrder>().in(WkOrder::getCode, orderCodeSet))) { |
| | | if (o != null && StringUtils.isNotBlank(o.getCode())) { |
| | | orderByCode.put(o.getCode(), o); |
| | | } |
| | | } |
| | | for (WkOrder o : asnOrderService.list(new LambdaQueryWrapper<WkOrder>().in(WkOrder::getPoCode, orderCodeSet))) { |
| | | if (o != null && StringUtils.isNotBlank(o.getPoCode())) { |
| | | orderByCode.putIfAbsent(o.getPoCode(), o); |
| | | } |
| | | } |
| | | } |
| | | return new CloudInOutReportContext(wareHouseId, locId, sourceToOrderNo, orderById, orderByCode); |
| | | } |
| | | |
| | | private InOutResultReportParam buildInOutParamForItem(Task task, TaskItem item, boolean isInbound, |
| | | BigDecimal outboundQtyResolved, CloudInOutReportContext ctx) { |
| | | if (task == null || item == null || ctx == null) { |
| | | return null; |
| | | } |
| | | boolean hasTaskItemCloudRef = hasCloudOrderRef(item); |
| | | boolean hasInboundAsnFallbackRef = isInbound |
| | | && item.getSource() != null |
| | | && StringUtils.isNotBlank(ctx.sourceToOrderNo.get(item.getSource())); |
| | | boolean hasOutboundCloudLineRef = !isInbound && item.getOrderId() != null && StringUtils.isNotBlank(item.getPlatItemId()); |
| | | if (!hasTaskItemCloudRef && !hasInboundAsnFallbackRef && !hasOutboundCloudLineRef) { |
| | | return null; |
| | | } |
| | | WkOrder asnOrder = null; |
| | | if (item.getOrderId() != null) { |
| | | asnOrder = ctx.orderById.get(item.getOrderId()); |
| | | } |
| | | String orderNo = isInbound ? ctx.sourceToOrderNo.get(item.getSource()) : (item.getPlatOrderCode() != null ? item.getPlatOrderCode() : item.getPlatWorkCode()); |
| | | if (orderNo == null && isInbound) { |
| | | orderNo = item.getPlatOrderCode() != null ? item.getPlatOrderCode() : item.getPlatWorkCode(); |
| | | } |
| | | if (orderNo == null && !isInbound && asnOrder != null) { |
| | | orderNo = StringUtils.isNotBlank(asnOrder.getPoCode()) ? asnOrder.getPoCode() : asnOrder.getCode(); |
| | | } |
| | | if (orderNo == null || item.getMatnrCode() == null) { |
| | | return null; |
| | | } |
| | | if (!isInbound && outboundQtyResolved == null) { |
| | | return null; |
| | | } |
| | | if (asnOrder == null) { |
| | | asnOrder = ctx.orderByCode.get(orderNo); |
| | | } |
| | | String qtyStr; |
| | | if (isInbound) { |
| | | qtyStr = item.getAnfme() != null ? QuantityUtils.toPlainQtyString(QuantityUtils.toScaledBigDecimal(item.getAnfme())) : "0"; |
| | | } else { |
| | | qtyStr = QuantityUtils.toPlainQtyString(outboundQtyResolved); |
| | | } |
| | | return new InOutResultReportParam() |
| | | .setOrderNo(orderNo) |
| | | .setPlanNo(item.getPlatWorkCode()) |
| | | .setWkType(item.getWkType()) |
| | | .setUnitNo(item.getUnit()) |
| | | .setLineId(item.getPlatItemId()) |
| | | .setWareHouseId(ctx.wareHouseId) |
| | | .setDocWarehouseNo(asnOrder != null ? asnOrder.getDocTaskWarehouseNo() : null) |
| | | .setOrgNo(asnOrder != null ? asnOrder.getDocOrgNo() : null) |
| | | .setInWarehouseNo(isInbound && asnOrder != null ? asnOrder.getDocInWarehouseNo() : null) |
| | | .setOutWarehouseNo(!isInbound && asnOrder != null ? asnOrder.getDocOutWarehouseNo() : null) |
| | | .setLocId(ctx.locId) |
| | | .setMatNr(item.getMatnrCode()) |
| | | .setQty(qtyStr) |
| | | .setBatch(item.getBatch()) |
| | | .setInbound(isInbound) |
| | | .setBarcode(task.getBarcode()); |
| | | } |
| | | |
| | | private static final class CloudInOutReportContext { |
| | | final String wareHouseId; |
| | | final String locId; |
| | | final Map<Long, String> sourceToOrderNo; |
| | | final Map<Long, WkOrder> orderById; |
| | | final Map<String, WkOrder> orderByCode; |
| | | |
| | | private CloudInOutReportContext(String wareHouseId, String locId, Map<Long, String> sourceToOrderNo, |
| | | Map<Long, WkOrder> orderById, Map<String, WkOrder> orderByCode) { |
| | | this.wareHouseId = wareHouseId; |
| | | this.locId = locId; |
| | | this.sourceToOrderNo = sourceToOrderNo; |
| | | this.orderById = orderById; |
| | | this.orderByCode = orderByCode; |
| | | } |
| | | } |
| | | |
| | |
| | | return StringUtils.isNotBlank(item.getPlatOrderCode()) |
| | | || StringUtils.isNotBlank(item.getPlatWorkCode()); |
| | | } |
| | | |
| | | /** sys_config CLOUD_WMS_INOUT_REPORT_MODE:immediate / wait_order / manual / single */ |
| | | private String resolveCloudWmsInoutReportMode() { |
| | | try { |
| | | Config cfg = configService.getCachedOrLoad(GlobalConfigCode.CLOUD_WMS_INOUT_REPORT_MODE); |
| | | if (cfg != null && StringUtils.isNotBlank(cfg.getVal())) { |
| | | return cfg.getVal().trim().toLowerCase(); |
| | | } |
| | | } catch (Exception ignored) { |
| | | } |
| | | return CloudWmsInoutReportMode.IMMEDIATE; |
| | | } |
| | | } |