| | |
| | | import com.vincent.rsf.server.api.entity.params.WcsTaskParams; |
| | | import com.vincent.rsf.server.api.service.WcsService; |
| | | import com.vincent.rsf.server.common.constant.Constants; |
| | | import com.vincent.rsf.server.common.utils.QuantityUtils; |
| | | import com.vincent.rsf.server.manager.controller.params.LocToTaskParams; |
| | | import com.vincent.rsf.server.manager.controller.params.PakinItem; |
| | | import com.vincent.rsf.server.manager.enums.*; |
| | |
| | | } |
| | | |
| | | /** |
| | | * 全版出库完结:扣除库位数量,将库位状态设为空 |
| | | * |
| | | * @param id 任务ID |
| | | * @param loginUserId 登录用户ID |
| | | * @return 任务对象 |
| | | */ |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public Task completeFullOutStock(Long id, Long loginUserId) { |
| | | // 查询任务 |
| | | Task task = taskService.getOne(new LambdaQueryWrapper<Task>() |
| | | .eq(Task::getId, id)); |
| | | |
| | | if (Objects.isNull(task)) { |
| | | throw new CoolException("任务不存在!!"); |
| | | } |
| | | |
| | | // 检查任务类型是否为全版出库 |
| | | if (!task.getTaskType().equals(TaskType.TASK_TYPE_OUT.type)) { |
| | | throw new CoolException("当前任务不是全版出库任务,无法执行此操作!!"); |
| | | } |
| | | |
| | | // 检查任务状态:必须是199(WAVE_SEED)状态才能手动完结 |
| | | if (!task.getTaskStatus().equals(TaskStsType.WAVE_SEED.id)) { |
| | | throw new CoolException("任务状态不是等待确认状态(199),无法执行此操作!!当前状态:" + task.getTaskStatus()); |
| | | } |
| | | |
| | | // 查询库位 |
| | | Loc loc = locService.getOne(new LambdaQueryWrapper<Loc>().eq(Loc::getCode, task.getOrgLoc())); |
| | | if (Objects.isNull(loc)) { |
| | | throw new CoolException("库位不存在!!"); |
| | | } |
| | | |
| | | // 删除库位明细(扣除数量) |
| | | try { |
| | | subtractLocItem(loc); |
| | | } catch (Exception e) { |
| | | logger.error("删除库位明细失败", e); |
| | | throw new CoolException("删除库位明细失败:" + e.getMessage()); |
| | | } |
| | | |
| | | // 删除作业中库存记录(LocItemWorking) |
| | | locItemWorkingService.remove(new LambdaQueryWrapper<LocItemWorking>() |
| | | .eq(LocItemWorking::getTaskId, task.getId())); |
| | | |
| | | // 将库位状态设为空(O状态) |
| | | if (!locService.update(new LambdaUpdateWrapper<Loc>() |
| | | .set(Loc::getBarcode, null) |
| | | .set(Loc::getUseStatus, LocStsType.LOC_STS_TYPE_O.type) |
| | | .set(Loc::getUpdateBy, loginUserId) |
| | | .set(Loc::getUpdateTime, new Date()) |
| | | .eq(Loc::getCode, task.getOrgLoc()))) { |
| | | throw new CoolException("库位状态修改失败!!"); |
| | | } |
| | | |
| | | // 更新出库站点状态(如果有目标站点) |
| | | if (StringUtils.isNotBlank(task.getTargSite())) { |
| | | BasStation station = basStationService.getOne(new LambdaQueryWrapper<BasStation>() |
| | | .eq(BasStation::getStationName, task.getTargSite())); |
| | | if (Objects.nonNull(station) && station.getType().equals(StationTypeEnum.STATION_TYPE_NORMAL.type)) { |
| | | station.setUseStatus(LocStsType.LOC_STS_TYPE_F.type); |
| | | if (!basStationService.updateById(station)) { |
| | | throw new CoolException("出库站点状态修改失败!!"); |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 更新任务状态为库存更新完成(200) |
| | | task.setTaskStatus(TaskStsType.UPDATED_OUT.id) |
| | | .setUpdateBy(loginUserId) |
| | | .setUpdateTime(new Date()); |
| | | |
| | | if (!this.updateById(task)) { |
| | | throw new CoolException("任务状态更新失败!!"); |
| | | } |
| | | |
| | | return task; |
| | | } |
| | | |
| | | /** |
| | | * 修改任务优先级 |
| | | * |
| | | * @param task |
| | |
| | | throw new CoolException("任务明细不存在!!"); |
| | | } |
| | | |
| | | List<LocItem> items = new ArrayList<>(); |
| | | for (TaskItem taskItem : taskItems) { |
| | | LocItem locItem = new LocItem(); |
| | | LocItemWorking locWorking = locItemWorkingService.getOne(new LambdaQueryWrapper<LocItemWorking>() |
| | | .eq(LocItemWorking::getTaskId, taskItem.getTaskId()) |
| | | .eq(StringUtils.isNotBlank(taskItem.getFieldsIndex()), LocItemWorking::getFieldsIndex, taskItem.getFieldsIndex()) |
| | | .eq(StringUtils.isNotEmpty(taskItem.getBatch()), LocItemWorking::getBatch, taskItem.getBatch()) |
| | | .eq(LocItemWorking::getMatnrId, taskItem.getMatnrId())); |
| | | if (Objects.isNull(locWorking)) { |
| | | continue; |
| | | if (TaskType.TASK_TYPE_PICK_IN.type.equals(task.getTaskType())) { |
| | | // 拣料再入库:出库时已在 pickOrCheckTask 中扣减原库位(1100 -> 1089.899), |
| | | // 入库完成时不再回写/累加库位明细,保持 1 条 1089.899,避免出现两条 1100 |
| | | // 仅更新库位状态、清理 LocItemWorking、任务状态及流水 |
| | | } else { |
| | | // 盘点入库等:沿用原逻辑,从 LocItemWorking 回写并 saveBatch |
| | | List<LocItem> items = new ArrayList<>(); |
| | | for (TaskItem taskItem : taskItems) { |
| | | LocItem locItem = new LocItem(); |
| | | LocItemWorking locWorking = locItemWorkingService.getOne(new LambdaQueryWrapper<LocItemWorking>() |
| | | .eq(LocItemWorking::getTaskId, taskItem.getTaskId()) |
| | | .eq(StringUtils.isNotBlank(taskItem.getFieldsIndex()), LocItemWorking::getFieldsIndex, taskItem.getFieldsIndex()) |
| | | .eq(StringUtils.isNotEmpty(taskItem.getBatch()), LocItemWorking::getBatch, taskItem.getBatch()) |
| | | .eq(LocItemWorking::getMatnrId, taskItem.getMatnrId())); |
| | | if (Objects.isNull(locWorking)) { |
| | | continue; |
| | | } |
| | | if (task.getTaskType().equals(TaskType.TASK_TYPE_CHECK_IN.type)) { |
| | | locWorking.setAnfme(taskItem.getAnfme()); |
| | | } |
| | | BeanUtils.copyProperties(locWorking, locItem); |
| | | locItem.setWorkQty(0.0).setQty(0.0).setLocCode(loc.getCode()).setLocId(loc.getId()).setId(null).setUpdateBy(loginUserId).setUpdateTime(new Date()); |
| | | //数量为零的不入库 |
| | | if (locItem.getAnfme().compareTo(0.0) > 0) { |
| | | items.add(locItem); |
| | | } |
| | | } |
| | | if (task.getTaskType().equals(TaskType.TASK_TYPE_CHECK_IN.type)) { |
| | | locWorking.setAnfme(taskItem.getAnfme()); |
| | | } |
| | | BeanUtils.copyProperties(locWorking, locItem); |
| | | locItem.setWorkQty(0.0).setQty(0.0).setLocCode(loc.getCode()).setLocId(loc.getId()).setId(null).setUpdateBy(loginUserId).setUpdateTime(new Date()); |
| | | //数量为零的不入库 |
| | | if (locItem.getAnfme().compareTo(0.0) > 0) { |
| | | items.add(locItem); |
| | | } |
| | | } |
| | | |
| | | if (!locItemService.saveBatch(items)) { |
| | | if (!items.isEmpty() && !locItemService.saveBatch(items)) { |
| | | // throw new CoolException("作业库存回写失败!!"); |
| | | } |
| | | } |
| | | |
| | | TaskItem taskItem = taskItems.stream().findFirst().get(); |
| | |
| | | // 如果有任务已下发到RCS,先调用RCS取消接口 |
| | | boolean rcsCancelSuccess = false; |
| | | if (!rcsTaskCodes.isEmpty()) { |
| | | try { |
| | | log.info("========== 开始取消RCS任务 =========="); |
| | | log.info("需要取消的RCS任务编号:{}", rcsTaskCodes); |
| | | String rcsUrl = rcsApi.getHost() + ":" + rcsApi.getPort() + RcsConstant.cancelTask; |
| | | log.info("RCS取消任务请求地址:{}", rcsUrl); |
| | | // 检查 RCS API 配置是否有效 |
| | | if (rcsApi == null || StringUtils.isBlank(rcsApi.getHost()) || StringUtils.isBlank(rcsApi.getPort())) { |
| | | log.error("========== RCS任务取消失败 =========="); |
| | | log.error("RCS API 配置无效!host: {}, port: {}", |
| | | rcsApi != null ? rcsApi.getHost() : "null", |
| | | rcsApi != null ? rcsApi.getPort() : "null"); |
| | | // 即使配置无效,也继续执行任务删除操作 |
| | | } else { |
| | | try { |
| | | log.info("========== 开始取消RCS任务 =========="); |
| | | log.info("需要取消的RCS任务编号:{}", rcsTaskCodes); |
| | | String rcsUrl = rcsApi.getHost() + ":" + rcsApi.getPort() + RcsConstant.cancelTask; |
| | | log.info("RCS取消任务请求地址:{}", rcsUrl); |
| | | |
| | | // 如果没有批次编号,使用第一个任务编号作为批次编号 |
| | | if (StringUtils.isBlank(batchNo) && !rcsTaskCodes.isEmpty()) { |
| | |
| | | log.error("RCS取消任务失败:{}", result.getMsg()); |
| | | throw new CoolException("RCS取消任务失败:" + result.getMsg()); |
| | | } |
| | | } catch (JsonProcessingException e) { |
| | | log.error("RCS取消任务响应解析失败:{}", e.getMessage(), e); |
| | | throw new CoolException("RCS取消任务响应解析失败:" + e.getMessage()); |
| | | } catch (Exception e) { |
| | | log.error("RCS取消任务异常:{}", e.getMessage(), e); |
| | | throw new CoolException("RCS取消任务异常:" + e.getMessage()); |
| | | } catch (JsonProcessingException e) { |
| | | log.error("RCS取消任务响应解析失败:{}", e.getMessage(), e); |
| | | throw new CoolException("RCS取消任务响应解析失败:" + e.getMessage()); |
| | | } catch (Exception e) { |
| | | log.error("RCS取消任务异常:{}", e.getMessage(), e); |
| | | throw new CoolException("RCS取消任务异常:" + e.getMessage()); |
| | | } |
| | | } |
| | | } |
| | | |
| | |
| | | // if (Objects.isNull(locInfo)) { |
| | | // throw new CoolException("获取库位失败!!"); |
| | | // } |
| | | //希日上报物有情况,不需要获取新库位 |
| | | //上报物有情况,不需要获取新库位 |
| | | task.setTargLoc(task.getOrgLoc()) |
| | | .setOrgSite(task.getTargSite()); |
| | | |
| | |
| | | } |
| | | //获取因当前任务出库的所有物料信息 |
| | | List<LocItemWorking> tempLocs = locItemWorkingService.list(new LambdaQueryWrapper<LocItemWorking>().eq(LocItemWorking::getTaskId, task.getId())); |
| | | if (tempLocs.isEmpty()) { |
| | | throw new CoolException("数据错误,作业中库存数据丢失!!"); |
| | | } |
| | | List<TaskItem> taskItems = taskItemService.list(new LambdaQueryWrapper<TaskItem>().eq(TaskItem::getTaskId, task.getId())); |
| | | if (taskItems.isEmpty()) { |
| | | throw new CoolException("数据错误:任务明细为空!!"); |
| | | } |
| | | // 与查询一致:若无作业中库存但存在任务明细,用任务明细在内存中兜底,避免“能查到却无法确认” |
| | | if (tempLocs.isEmpty()) { |
| | | tempLocs = taskItems.stream().map(ti -> { |
| | | LocItemWorking w = new LocItemWorking(); |
| | | w.setTaskId(task.getId()); |
| | | w.setFieldsIndex(ti.getFieldsIndex()); |
| | | w.setAnfme(ti.getAnfme()); |
| | | w.setMatnrId(ti.getMatnrId()); |
| | | w.setMaktx(ti.getMaktx()); |
| | | w.setMatnrCode(ti.getMatnrCode()); |
| | | w.setSpec(ti.getSpec()); |
| | | w.setBatch(ti.getBatch()); |
| | | w.setUnit(ti.getUnit()); |
| | | w.setModel(ti.getModel()); |
| | | return w; |
| | | }).collect(Collectors.toList()); |
| | | } |
| | | |
| | | // 拣料入库:先算剩余数量并更新 taskItem.anfme,已拣数量 taskItem.qty = 原库位 - 剩余(保证 数量=100、已拣数量=1、库存明细=100) |
| | | if (TaskType.TASK_TYPE_PICK_IN.type.equals(type)) { |
| | | log.debug("[拣料入库] 开始处理 taskId={}, taskCode={}, orgLoc={}, tempLocs.size={}, taskItems.size={}", |
| | | task.getId(), task.getTaskCode(), task.getOrgLoc(), tempLocs.size(), taskItems.size()); |
| | | tempLocs.forEach(working -> { |
| | | taskItems.forEach(taskItem -> { |
| | | if (Objects.equals(taskItem.getFieldsIndex(), working.getFieldsIndex())) { |
| | | // 已拣数量:优先用 taskItem.qty;为 0 时从出库单明细取 执行数(workQty) 或 订单数量(anfme),避免手动完结未填 qty 导致不扣减 |
| | | Double pickedQty = taskItem.getQty() != null && QuantityUtils.isPositive(taskItem.getQty()) |
| | | ? taskItem.getQty() |
| | | : 0.0; |
| | | log.debug("[拣料入库] taskItemId={}, fieldsIndex={}, working.anfme={}, taskItem.qty={}, taskItem.orderItemId={}, pickedQty(初)={}", |
| | | taskItem.getId(), taskItem.getFieldsIndex(), working.getAnfme(), taskItem.getQty(), taskItem.getOrderItemId(), pickedQty); |
| | | if (pickedQty <= 0 && taskItem.getOrderItemId() != null) { |
| | | WkOrderItem orderItem = asnOrderItemService.getById(taskItem.getOrderItemId()); |
| | | log.debug("[拣料入库] 查出库单明细 orderItemId={}, orderItem={}, workQty={}, anfme={}", |
| | | taskItem.getOrderItemId(), orderItem != null ? "存在" : "null", |
| | | orderItem != null ? orderItem.getWorkQty() : null, orderItem != null ? orderItem.getAnfme() : null); |
| | | if (orderItem != null) { |
| | | if (orderItem.getWorkQty() != null && QuantityUtils.isPositive(orderItem.getWorkQty())) { |
| | | pickedQty = orderItem.getWorkQty(); |
| | | } else if (orderItem.getAnfme() != null && QuantityUtils.isPositive(orderItem.getAnfme())) { |
| | | pickedQty = orderItem.getAnfme(); |
| | | } |
| | | } |
| | | } |
| | | Double minQty = QuantityUtils.subtract(working.getAnfme(), pickedQty); |
| | | log.debug("[拣料入库] 计算后 pickedQty={}, minQty(剩余)={}, 将更新 taskItem.anfme={}, taskItem.qty={}", |
| | | pickedQty, minQty, minQty, pickedQty); |
| | | if (QuantityUtils.isNonNegative(minQty)) { |
| | | taskItem.setAnfme(minQty); |
| | | taskItem.setQty(pickedQty); |
| | | if (!taskItemService.updateById(taskItem)) { |
| | | throw new CoolException("任务明细修改失败!!"); |
| | | } |
| | | } else { |
| | | log.warn("[拣料入库] minQty<0 未更新 taskItem, taskItemId={}", taskItem.getId()); |
| | | } |
| | | } |
| | | }); |
| | | }); |
| | | log.debug("[拣料入库] 即将扣减库位 locId={}, locCode={}", loc.getId(), loc.getCode()); |
| | | subtractLocItemByTaskItems(loc, taskItems, SystemAuthUtils.getLoginUserId()); |
| | | } |
| | | |
| | | tempLocs.forEach(working -> { |
| | |
| | | if (Objects.equals(taskItem.getFieldsIndex(), working.getFieldsIndex())) { |
| | | Double minQty = taskItem.getAnfme(); |
| | | if (!task.getTaskType().equals(TaskType.TASK_TYPE_CHECK_IN.type)) { |
| | | minQty = Math.round((working.getAnfme() - taskItem.getQty()) * 1000000) / 1000000.0; |
| | | // 计算剩余数量 |
| | | minQty = QuantityUtils.subtract(working.getAnfme(), taskItem.getQty()); |
| | | } |
| | | if (minQty.compareTo(0.0) >= 0) { |
| | | if (QuantityUtils.isNonNegative(minQty)) { |
| | | // 更新TaskItem的剩余数量 |
| | | taskItem.setAnfme(minQty); |
| | | if (!taskItemService.updateById(taskItem)) { |
| | | throw new CoolException("任务明细修改失败!!"); |
| | | } |
| | | // 更新LocItemWorking的剩余数量(非盘点入库时需要更新);仅持久化记录才写库 |
| | | if (!task.getTaskType().equals(TaskType.TASK_TYPE_CHECK_IN.type)) { |
| | | working.setAnfme(minQty); |
| | | if (working.getId() != null && !locItemWorkingService.updateById(working)) { |
| | | throw new CoolException("作业库存数量更新失败!!"); |
| | | } |
| | | } |
| | | } else { |
| | | // 剩余数量小于0,删除任务明细 |
| | | if (!taskItemService.removeById(taskItem)) { |
| | | log.error("任务明细修改失败!!"); |
| | | } |
| | |
| | | .setQty(0.0) |
| | | .setLocId(loc1.getId()) |
| | | .setLocCode(loc1.getCode()); |
| | | // 拣料再入库:目标库位数量应为回库的剩余数量(taskItem.anfme),即原库位减掉本次拣出后的数量(如 1000 出库 10 → 990) |
| | | if (TaskType.TASK_TYPE_PICK_IN.type.equals(task.getTaskType()) && taskItem.getAnfme() != null && taskItem.getAnfme().compareTo(0.0) > 0) { |
| | | itemWorking.setAnfme(taskItem.getAnfme()); |
| | | } |
| | | workings.add(itemWorking); |
| | | }); |
| | | |
| | |
| | | if (Objects.isNull(loc)) { |
| | | throw new CoolException("库位不存在!!"); |
| | | } |
| | | if (!loc.getUseStatus().equals(LocStsType.LOC_STS_TYPE_R.type)) { |
| | | throw new CoolException("库位状态不处理于R.出库预约!!"); |
| | | } |
| | | |
| | | |
| | | List<TaskItem> taskItems = taskItemService.list(new LambdaQueryWrapper<TaskItem>().eq(TaskItem::getTaskId, task.getId())); |
| | | if (taskItems.isEmpty()) { |
| | | throw new CoolException("任务明细不存在!!"); |
| | | } |
| | | |
| | | List<LocItem> locItems = locItemService.list(new LambdaQueryWrapper<LocItem>().eq(LocItem::getLocId, loc.getId())); |
| | | |
| | | // 如果库位状态不是R,检查是否已经处理过 |
| | | if (!loc.getUseStatus().equals(LocStsType.LOC_STS_TYPE_R.type)) { |
| | | // 如果库位明细为空,说明已经处理过了,直接更新任务状态为199 |
| | | if (locItems.isEmpty()) { |
| | | logger.warn("任务{}的库位{}状态为{},但库位明细为空,可能已经处理过,直接更新任务状态为199", |
| | | task.getId(), loc.getCode(), loc.getUseStatus()); |
| | | if (!this.update(new LambdaUpdateWrapper<Task>() |
| | | .eq(Task::getId, task.getId()) |
| | | .set(Task::getUpdateBy, loginUserId) |
| | | .set(Task::getUpdateTime, new Date()) |
| | | .set(Task::getTaskStatus, TaskStsType.WAVE_SEED.id))) { |
| | | throw new CoolException("任务状态更新失败!!"); |
| | | } |
| | | return; // 跳过后续处理 |
| | | } else { |
| | | // 库位明细不为空但状态不是R,跳过处理 |
| | | logger.error("任务{}的库位{}状态为{},不是R.出库预约状态,但库位明细不为空,跳过处理。任务编码:{},库位编码:{}", |
| | | task.getId(), loc.getCode(), loc.getUseStatus(), task.getTaskCode(), loc.getCode()); |
| | | return; |
| | | } |
| | | } |
| | | |
| | | // 如果库位明细为空,可能是已经被处理过了,允许继续执行 |
| | | if (!locItems.isEmpty()) { |
| | | List<LocItemWorking> workings = new ArrayList<>(); |
| | |
| | | } |
| | | |
| | | try { |
| | | //更新库位明细 |
| | | subtractLocItem(loc); |
| | | // 根据任务类型更新库位明细 |
| | | if (task.getTaskType().equals(TaskType.TASK_TYPE_OUT.type)) { |
| | | // 全版出库:不删除库位明细,等待PDA快速拣货确认时再删除 |
| | | // subtractLocItem(loc); // 已移除,改为在completeFullOutStock中删除 |
| | | } else if (!TaskType.TASK_TYPE_PICK_AGAIN_OUT.type.equals(task.getTaskType())) { |
| | | // 部分出库(如盘点出库):根据TaskItem数量扣减库位明细;拣料出库在生成拣料入库单时扣减 |
| | | subtractLocItemByTaskItems(loc, taskItems, loginUserId); |
| | | } |
| | | } catch (Exception e) { |
| | | logger.error("<UNK>", e); |
| | | throw new CoolException(e.getMessage()); |
| | |
| | | throw new CoolException(e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | // 根据任务类型更新库位状态 |
| | | if (task.getTaskType().equals(TaskType.TASK_TYPE_PICK_AGAIN_OUT.type) || task.getTaskType().equals(TaskType.TASK_TYPE_CHECK_OUT.type)) { |
| | | /**修改为库位状态为S.预约入库,保留原有库位*/ |
| | | if (!locService.update(new LambdaUpdateWrapper<Loc>() |
| | |
| | | .eq(Loc::getId, loc.getId()))) { |
| | | throw new CoolException("库位状态修改失败!!"); |
| | | } |
| | | } else if (task.getTaskType().equals(TaskType.TASK_TYPE_OUT.type)) { |
| | | // 全版出库:不更新库位状态为O,等待PDA快速拣货确认时再更新 |
| | | // 库位状态保持原样(R.出库预约状态) |
| | | } else { |
| | | /**修改为库位状态为O.空库*/ |
| | | if (!locService.update(new LambdaUpdateWrapper<Loc>() |
| | |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void pubTaskToWcs(List<Task> tasks) { |
| | | /**任务下发接口*/ |
| | | // 检查 RCS API 配置是否有效 |
| | | if (rcsApi == null || StringUtils.isBlank(rcsApi.getHost()) || StringUtils.isBlank(rcsApi.getPort())) { |
| | | log.error("========== RCS任务下发失败 =========="); |
| | | log.error("RCS API 配置无效!host: {}, port: {}", |
| | | rcsApi != null ? rcsApi.getHost() : "null", |
| | | rcsApi != null ? rcsApi.getPort() : "null"); |
| | | return; |
| | | } |
| | | |
| | | String pubTakUrl = rcsApi.getHost() + ":" + rcsApi.getPort() + RcsConstant.pubTask; |
| | | |
| | | for (Task task : tasks) { |
| | |
| | | // 为每个不同的库位创建一个TaskItemParam |
| | | for (String locCode : locCodes) { |
| | | TaskItemParam outItemParam = new TaskItemParam(); |
| | | outItemParam.setTaskNo(task.getTaskCode()); |
| | | String taskNo = locCodes.size() > 1 |
| | | ? task.getTaskCode() + "_" + locCode |
| | | : task.getTaskCode(); |
| | | outItemParam.setTaskNo(taskNo); |
| | | outItemParam.setPriority(1); |
| | | outItemParam.setOriLoc(locCode); |
| | | outItemParam.setDestSta(task.getTargSite()); |
| | |
| | | } catch (org.springframework.web.client.ResourceAccessException e) { |
| | | long endTime = System.currentTimeMillis(); |
| | | log.error("========== RCS任务下发资源访问异常 =========="); |
| | | log.error("请求RCS-资源访问异常(可能包含连接超时),耗时:{}ms,任务编码:{}", (endTime - startTime), task.getTaskCode(), e); |
| | | log.error("请求RCS-资源访问异常,耗时:{}ms,任务编码:{}", (endTime - startTime), task.getTaskCode(), e); |
| | | log.error("请求RCS-请求地址:{}", pubTakUrl); |
| | | log.error("请求RCS-请求参数:{}", JSONObject.toJSONString(taskParams)); |
| | | // 检查是否是连接超时异常 |
| | |
| | | } catch (Exception e) { |
| | | long endTime = System.currentTimeMillis(); |
| | | log.error("========== RCS任务下发异常 =========="); |
| | | log.error("请求RCS-异常,耗时:{}ms,任务编码:{}", (endTime - startTime), task.getTaskCode(), e); |
| | | log.error("请求RCS-地址:{}", pubTakUrl); |
| | | log.error("请求RCS-参数:{}", JSONObject.toJSONString(taskParams)); |
| | | String errorMsg = e.getMessage(); |
| | | // 检查是否是连接超时相关的异常 |
| | | if (errorMsg != null && (errorMsg.contains("Connection timed out") || errorMsg.contains("timed out") || errorMsg.contains("timeout"))) { |
| | | log.error("RCS连接超时,任务下发失败!任务编码:{},错误信息:{}", task.getTaskCode(), errorMsg); |
| | | log.error("请求RCS-连接超时异常,耗时:{}ms,任务编码:{},错误信息:{}-{}", (endTime - startTime), task.getTaskCode(), e, errorMsg); |
| | | } else { |
| | | log.error("RCS任务下发异常!任务编码:{},错误信息:{}", task.getTaskCode(), errorMsg); |
| | | log.error("请求RCS-异常,耗时:{}ms,任务编码:{},错误信息:{}-{}", (endTime - startTime), task.getTaskCode(), e, errorMsg); |
| | | } |
| | | log.error("请求RCS-地址:{}", pubTakUrl); |
| | | log.error("请求RCS-参数:{}", JSONObject.toJSONString(taskParams)); |
| | | continue; |
| | | } |
| | | |
| | |
| | | /** |
| | | * @author Ryan |
| | | * @date 2025/5/20 |
| | | * @description: 扣减库存明细 |
| | | * @description: 扣减库存明细(全版出库:删除所有库位明细) |
| | | * @version 1.0 |
| | | */ |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void subtractLocItem(Loc loc) throws Exception { |
| | | // 删除库位明细,如果没有记录则忽略(可能已经被删除过了) |
| | | locItemService.remove(new LambdaQueryWrapper<LocItem>().eq(LocItem::getLocId, loc.getId())); |
| | | } |
| | | |
| | | /** |
| | | * 根据任务明细扣减库位明细数量(部分出库) |
| | | * |
| | | * @param loc 库位 |
| | | * @param taskItems 任务明细列表 |
| | | * @param loginUserId 登录用户ID |
| | | */ |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void subtractLocItemByTaskItems(Loc loc, List<TaskItem> taskItems, Long loginUserId) { |
| | | for (TaskItem taskItem : taskItems) { |
| | | LambdaQueryWrapper<LocItem> locItemWrapper = new LambdaQueryWrapper<LocItem>() |
| | | .eq(LocItem::getLocId, loc.getId()) |
| | | .eq(LocItem::getMatnrId, taskItem.getMatnrId()); |
| | | if (StringUtils.isNotBlank(taskItem.getBatch())) { |
| | | locItemWrapper.eq(LocItem::getBatch, taskItem.getBatch()); |
| | | } else { |
| | | locItemWrapper.and(w -> w.isNull(LocItem::getBatch).or().eq(LocItem::getBatch, "")); |
| | | } |
| | | if (StringUtils.isNotBlank(taskItem.getFieldsIndex())) { |
| | | locItemWrapper.eq(LocItem::getFieldsIndex, taskItem.getFieldsIndex()); |
| | | } else { |
| | | locItemWrapper.and(w -> w.isNull(LocItem::getFieldsIndex).or().eq(LocItem::getFieldsIndex, "")); |
| | | } |
| | | LocItem locItem = locItemService.getOne(locItemWrapper); |
| | | |
| | | log.info("[拣料入库-扣减库位] taskItemId={}, locId={}, matnrId={}, batch={}, fieldsIndex={}, locItem={}, locItem.anfme={}, taskItem.qty={}, taskItem.anfme={}", |
| | | taskItem.getId(), loc.getId(), taskItem.getMatnrId(), taskItem.getBatch(), taskItem.getFieldsIndex(), |
| | | locItem != null ? "存在" : "null", locItem != null ? locItem.getAnfme() : null, taskItem.getQty(), taskItem.getAnfme()); |
| | | |
| | | if (Objects.nonNull(locItem)) { |
| | | // 扣减量:优先用本次拣料数量 taskItem.getQty();若为 0 且 taskItem.anfme 已为剩余数量,则扣减 = 原库位 - 剩余(用 BigDecimal 避免 Double 精度问题) |
| | | Double deductQty = QuantityUtils.isPositive(taskItem.getQty()) |
| | | ? taskItem.getQty() |
| | | : (taskItem.getAnfme() != null && QuantityUtils.compare(taskItem.getAnfme(), locItem.getAnfme()) < 0 |
| | | ? QuantityUtils.subtract(locItem.getAnfme(), taskItem.getAnfme()) |
| | | : 0.0); |
| | | Double newAnfme = QuantityUtils.subtract(locItem.getAnfme(), deductQty); |
| | | log.info("[拣料入库-扣减库位] locItemId={}, deductQty={}, 原anfme={}, newAnfme={}, 操作={}", |
| | | locItem.getId(), deductQty, locItem.getAnfme(), newAnfme, QuantityUtils.isNonPositive(newAnfme) ? "删除" : "更新"); |
| | | |
| | | if (QuantityUtils.isNonPositive(newAnfme)) { |
| | | // 数量小于等于0,删除库位明细 |
| | | locItemService.removeById(locItem.getId()); |
| | | } else { |
| | | // 更新库位明细数量 |
| | | locItem.setAnfme(newAnfme) |
| | | .setUpdateBy(loginUserId) |
| | | .setUpdateTime(new Date()); |
| | | if (!locItemService.updateById(locItem)) { |
| | | throw new CoolException("库位明细数量扣减失败!!"); |
| | | } |
| | | } |
| | | } else { |
| | | log.warn("[拣料入库-扣减库位] 未查到库位明细 locId={}, matnrId={}, batch={}, fieldsIndex={},未扣减", |
| | | loc.getId(), taskItem.getMatnrId(), taskItem.getBatch(), taskItem.getFieldsIndex()); |
| | | } |
| | | } |
| | | } |
| | | |
| | | /** |
| | |
| | | throw new CoolException("库位不存在!!"); |
| | | } |
| | | LocItem item = new LocItem(); |
| | | LocItem locItem = locItemService.getOne(new LambdaQueryWrapper<LocItem>() |
| | | // 构建查询条件:需要同时匹配物料ID、库位ID、批次和票号 |
| | | LambdaQueryWrapper<LocItem> locItemWrapper = new LambdaQueryWrapper<LocItem>() |
| | | .eq(LocItem::getMatnrId, taskItem.getMatnrId()) |
| | | .eq(LocItem::getLocId, loc.getId()) |
| | | .eq(StringUtils.isNotBlank(taskItem.getBatch()), LocItem::getBatch, taskItem.getBatch()) |
| | | .eq(StringUtils.isNotBlank(taskItem.getFieldsIndex()), LocItem::getFieldsIndex, taskItem.getFieldsIndex()) |
| | | ); |
| | | .eq(LocItem::getLocId, loc.getId()); |
| | | |
| | | // 批次匹配:如果taskItem有批次,则必须匹配;如果taskItem没有批次,则查询批次为null或空字符串的记录 |
| | | if (StringUtils.isNotBlank(taskItem.getBatch())) { |
| | | locItemWrapper.eq(LocItem::getBatch, taskItem.getBatch()); |
| | | } else { |
| | | locItemWrapper.and(wrapper -> wrapper.isNull(LocItem::getBatch).or().eq(LocItem::getBatch, "")); |
| | | } |
| | | |
| | | // 票号匹配:如果taskItem有票号,则必须匹配;如果taskItem没有票号,则查询票号为null或空字符串的记录 |
| | | if (StringUtils.isNotBlank(taskItem.getFieldsIndex())) { |
| | | locItemWrapper.eq(LocItem::getFieldsIndex, taskItem.getFieldsIndex()); |
| | | } else { |
| | | locItemWrapper.and(wrapper -> wrapper.isNull(LocItem::getFieldsIndex).or().eq(LocItem::getFieldsIndex, "")); |
| | | } |
| | | |
| | | LocItem locItem = locItemService.getOne(locItemWrapper); |
| | | if (Objects.isNull(locItem)) { |
| | | // 库位明细不存在,创建新的库位明细 |
| | | BeanUtils.copyProperties(taskItem, item); |
| | | item.setLocCode(loc.getCode()) |
| | | .setId(null) |
| | |
| | | throw new CoolException("库位明细更新失败!!"); |
| | | } |
| | | } else { |
| | | // logger.error("当前票号:" + locItem.getFieldsIndex() + " 已在库内,请检查后再操作!!"); |
| | | // throw new CoolException("当前票号已在库内,请检查后再操作!!"); |
| | | // locItem.setAnfme(Math.round((locItem.getAnfme() + taskItem.getAnfme()) * 1000000) / 1000000.0) |
| | | // .setUpdateTime(new Date()); |
| | | // if (!locItemService.saveOrUpdate(locItem)) { |
| | | // throw new CoolException("库位明细更新失败!!"); |
| | | // } |
| | | // 库位明细已存在,累加数量 |
| | | Double newAnfme = Math.round((locItem.getAnfme() + taskItem.getAnfme()) * 1000000) / 1000000.0; |
| | | locItem.setAnfme(newAnfme) |
| | | .setUpdateBy(loginUserId) |
| | | .setUpdateTime(new Date()); |
| | | if (!locItemService.updateById(locItem)) { |
| | | throw new CoolException("库位明细数量更新失败!!"); |
| | | } |
| | | } |
| | | }); |
| | | |