| | |
| | | import com.vincent.rsf.openApi.entity.app.OpenApiOrder; |
| | | import com.vincent.rsf.openApi.entity.app.OpenApiOrderItem; |
| | | import com.vincent.rsf.openApi.entity.app.OpenApiOrderItemMap; |
| | | import com.vincent.rsf.openApi.entity.app.OpenApiOrderReportEvent; |
| | | import com.vincent.rsf.openApi.entity.constant.WmsConstant; |
| | | import com.vincent.rsf.openApi.entity.dto.CommonResponse; |
| | | import com.vincent.rsf.openApi.entity.phyz.*; |
| | |
| | | import com.vincent.rsf.openApi.mapper.OpenApiOrderItemMapMapper; |
| | | import com.vincent.rsf.openApi.mapper.OpenApiOrderItemMapper; |
| | | import com.vincent.rsf.openApi.mapper.OpenApiOrderMapper; |
| | | import com.vincent.rsf.openApi.mapper.OpenApiOrderReportEventMapper; |
| | | import com.vincent.rsf.openApi.service.WmsErpService; |
| | | import com.vincent.rsf.openApi.service.phyz.ErpReportService; |
| | | import com.vincent.rsf.openApi.utils.ParamsMapUtils; |
| | |
| | | private OpenApiOrderItemMapper openApiOrderItemMapper; |
| | | @Resource |
| | | private OpenApiOrderItemMapMapper openApiOrderItemMapMapper; |
| | | @Resource |
| | | private OpenApiOrderReportEventMapper openApiOrderReportEventMapper; |
| | | |
| | | private static final BigDecimal ZERO = BigDecimal.ZERO.setScale(2, RoundingMode.HALF_UP); |
| | | |
| | |
| | | } |
| | | JSONObject root = JSONObject.parseObject(JSON.toJSONString(params)); |
| | | |
| | | String eventId = pickString(root, "eventId", "EventId"); |
| | | String taskNo = pickString(root, "taskNo", "TaskNo"); |
| | | String reportNo = pickString(root, "reportNo", "ReportNo"); |
| | | if (StringUtils.isBlank(eventId) && StringUtils.isBlank(taskNo) && StringUtils.isBlank(reportNo)) { |
| | | throw new CoolException("幂等键不能为空(eventId/taskNo/reportNo)"); |
| | | } |
| | | |
| | | String orderNo = pickString(root, "orderNo", "OrderNo", "WMSNO", "wmsno"); |
| | | if (StringUtils.isBlank(orderNo)) { |
| | | return CommonResponse.error("orderNo不能为空"); |
| | | } |
| | | |
| | | if (existsReportEvent(eventId, taskNo, reportNo)) { |
| | | return CommonResponse.ok("重复回传已忽略"); |
| | | } |
| | | OpenApiOrderReportEvent reportEvent = saveReportEvent(eventId, taskNo, reportNo, orderNo, root.toJSONString()); |
| | | |
| | | // 解析明细:优先取 orderItems(Order格式),兼容 Data/data(ReportParams格式) |
| | | JSONArray dataArray = pickArray(root, "orderItems", "orderItems"); |
| | |
| | | mappedDataArray = dataArray; |
| | | } |
| | | |
| | | // 主单级信息(Order格式上报时携带) |
| | | String orderType = pickString(root, "type", "Type"); |
| | | String wkType = pickString(root, "wkType", "WkType"); |
| | | String poCode = pickString(root, "poCode", "PoCode", "PONO"); |
| | | String editUser = pickString(root, "editUser", "EditUser"); |
| | | Date editDate = null; |
| | | Object editDateObj = root.get("editDate"); |
| | | if (editDateObj instanceof Number) { |
| | | editDate = toDate(((Number) editDateObj).longValue()); |
| | | } |
| | | |
| | | int allocateCount = 0; |
| | | List<String> errors = new ArrayList<>(); |
| | | Set<String> affectedOrderNos = new HashSet<>(); |
| | |
| | | |
| | | for (int i = 0; i < mappedDataArray.size(); i++) { |
| | | JSONObject row = mappedDataArray.getJSONObject(i); |
| | | // Order格式:matNr/anfme/batch/doneQty/lineId |
| | | // ReportParams格式兼容:ItemCode/InQty/OutQty/GoodsNO |
| | | String matnrCode = pickString(row, "matNr", "MatNr", "ItemCode", "itemCode"); |
| | | String batch = pickString(row, "batch", "Batch", "GoodsNO", "goodsNo"); |
| | | String lineId = pickString(row, "lineId", "LineId", "sourceLineId"); |
| | |
| | | refreshOrderFinishStatus(no); |
| | | } |
| | | |
| | | // 组装ReportParams上报ERP(一次性整单上报) |
| | | try { |
| | | ReportParams erpReportParams = buildReportParamsFromOrderData(orderNo, poCode, orderType, wkType, editUser, editDate, mappedDataArray); |
| | | CommonResponse erpResp = wmsErpService.reportOrders(erpReportParams); |
| | | if (Objects.nonNull(erpResp) && Objects.equals(erpResp.getCode(), 200)) { |
| | | log.info("上报ERP成功,orderNo={}", orderNo); |
| | | } else { |
| | | String msg = Objects.isNull(erpResp) ? "ERP响应为空" : erpResp.getMsg(); |
| | | errors.add("上报ERP失败:" + msg); |
| | | } |
| | | } catch (Exception e) { |
| | | log.error("上报ERP异常", e); |
| | | errors.add("上报ERP异常:" + e.getMessage()); |
| | | } |
| | | |
| | | if (!errors.isEmpty()) { |
| | | reportEvent.setStatus(2); |
| | | openApiOrderReportEventMapper.updateById(reportEvent); |
| | | return CommonResponse.error("处理完成,但存在异常:" + String.join(" | ", errors)); |
| | | } |
| | | reportEvent.setStatus(1); |
| | | openApiOrderReportEventMapper.updateById(reportEvent); |
| | | |
| | | Map<String, Object> result = new HashMap<>(); |
| | | result.put("allocatedCount", allocateCount); |
| | |
| | | } |
| | | |
| | | /** |
| | | * 根据Order格式数据组装ReportParams,参照旧链路wmsErpService.reportOrders格式上报ERP |
| | | * 查询已完成但未上报ERP的订单,组装ReportParams上报ERP |
| | | * 由asrs-schedule定时任务触发 |
| | | */ |
| | | private ReportParams buildReportParamsFromOrderData(String orderNo, String poCode, String type, String wkType, |
| | | String editUser, Date editDate, JSONArray dataArray) { |
| | | // 根据wkType/type确定ERP上报的OrderType |
| | | String erpOrderType = resolveErpOrderType(type, wkType); |
| | | @Override |
| | | public CommonResponse reportOrdersToErp() { |
| | | List<OpenApiOrder> pendingOrders = openApiOrderMapper.selectList(new LambdaQueryWrapper<OpenApiOrder>() |
| | | .eq(OpenApiOrder::getExceStatus, 2) |
| | | .eq(OpenApiOrder::getNtyStatus, 0) |
| | | .last("limit 50")); |
| | | if (pendingOrders.isEmpty()) { |
| | | return CommonResponse.ok("无待上报ERP的订单"); |
| | | } |
| | | |
| | | List<String> errors = new ArrayList<>(); |
| | | int successCount = 0; |
| | | for (OpenApiOrder order : pendingOrders) { |
| | | try { |
| | | List<OpenApiOrderItem> items = openApiOrderItemMapper.selectList(new LambdaQueryWrapper<OpenApiOrderItem>() |
| | | .eq(OpenApiOrderItem::getOrderId, order.getId())); |
| | | if (items.isEmpty()) { |
| | | log.warn("订单无明细,跳过上报ERP,orderNo={}", order.getCode()); |
| | | continue; |
| | | } |
| | | |
| | | ReportParams erpParams = buildReportParams(order, items); |
| | | CommonResponse erpResp = wmsErpService.reportOrders(erpParams); |
| | | if (Objects.nonNull(erpResp) && Objects.equals(erpResp.getCode(), 200)) { |
| | | order.setNtyStatus(1); |
| | | openApiOrderMapper.updateById(order); |
| | | successCount++; |
| | | log.info("上报ERP成功,orderNo={}", order.getCode()); |
| | | } else { |
| | | String msg = Objects.isNull(erpResp) ? "ERP响应为空" : erpResp.getMsg(); |
| | | log.warn("上报ERP失败,orderNo={},msg={}", order.getCode(), msg); |
| | | errors.add(order.getCode() + ":" + msg); |
| | | } |
| | | } catch (Exception e) { |
| | | log.error("上报ERP异常,orderNo={}", order.getCode(), e); |
| | | errors.add(order.getCode() + ":" + e.getMessage()); |
| | | } |
| | | } |
| | | |
| | | if (!errors.isEmpty()) { |
| | | Map<String, Object> result = new HashMap<>(); |
| | | result.put("successCount", successCount); |
| | | result.put("totalCount", pendingOrders.size()); |
| | | return CommonResponse.error("部分订单上报ERP失败:" + String.join(" | ", errors)); |
| | | } |
| | | |
| | | Map<String, Object> result = new HashMap<>(); |
| | | result.put("successCount", successCount); |
| | | result.put("totalCount", pendingOrders.size()); |
| | | return CommonResponse.ok(result); |
| | | } |
| | | |
| | | /** |
| | | * 从OpenApiOrder+OpenApiOrderItem组装ReportParams |
| | | */ |
| | | private ReportParams buildReportParams(OpenApiOrder order, List<OpenApiOrderItem> items) { |
| | | String erpOrderType = resolveErpOrderType(order.getType(), order.getWkType()); |
| | | |
| | | List<ReportDataParam> reportDataList = new ArrayList<>(); |
| | | for (int i = 0; i < dataArray.size(); i++) { |
| | | JSONObject row = dataArray.getJSONObject(i); |
| | | String matnrCode = pickString(row, "matNr", "MatNr", "ItemCode", "itemCode"); |
| | | String batch = pickString(row, "batch", "Batch", "GoodsNO", "goodsNo"); |
| | | BigDecimal doneQty = pickDecimal(row, "doneQty", "anfme", "qty", "InQty", "inQty", "OutQty", "outQty"); |
| | | for (OpenApiOrderItem item : items) { |
| | | BigDecimal qty = defaultQty(item.getQty()); |
| | | if (qty.compareTo(ZERO) <= 0) { |
| | | continue; |
| | | } |
| | | |
| | | ReportDataParam dataParam = new ReportDataParam() |
| | | .setWMSNO(orderNo) |
| | | .setPONO(poCode) |
| | | .setOrderNO(orderNo) |
| | | .setGoodsNO(batch) |
| | | .setItemCode(matnrCode) |
| | | .setEditUser(editUser) |
| | | .setEditDate(editDate) |
| | | .setMemoDtl(pickString(row, "memo", "MemoDtl")); |
| | | .setWMSNO(order.getCode()) |
| | | .setPONO(order.getPoCode()) |
| | | .setOrderNO(order.getCode()) |
| | | .setGoodsNO(item.getBatch()) |
| | | .setItemCode(item.getMatnrCode()) |
| | | .setEditUser("schedule") |
| | | .setEditDate(new Date()) |
| | | .setMemoDtl(item.getMemo()); |
| | | |
| | | // 入库类型设InQty,出库类型设OutQty |
| | | if ("in".equalsIgnoreCase(type)) { |
| | | if (doneQty.compareTo(ZERO) > 0) { |
| | | dataParam.setInQty(doneQty.doubleValue()); |
| | | } |
| | | if ("in".equalsIgnoreCase(order.getType())) { |
| | | dataParam.setInQty(qty.doubleValue()); |
| | | } else { |
| | | if (doneQty.compareTo(ZERO) > 0) { |
| | | dataParam.setOutQty(doneQty.doubleValue()); |
| | | } |
| | | dataParam.setOutQty(qty.doubleValue()); |
| | | } |
| | | |
| | | reportDataList.add(dataParam); |
| | |
| | | .setQty(ZERO) |
| | | .setWorkQty(ZERO) |
| | | .setExceStatus(0) |
| | | .setNtyStatus(0) |
| | | .setStatus(1) |
| | | .setBusinessTime(businessTime) |
| | | .setOrderInternalCode(order.getOrderInternalCode()) |
| | |
| | | } |
| | | merged.setOrderItems(mergedItems); |
| | | return merged; |
| | | } |
| | | |
| | | private boolean existsReportEvent(String eventId, String taskNo, String reportNo) { |
| | | return openApiOrderReportEventMapper.selectCount(new LambdaQueryWrapper<OpenApiOrderReportEvent>() |
| | | .eq(OpenApiOrderReportEvent::getEventId, defaultString(eventId)) |
| | | .eq(OpenApiOrderReportEvent::getTaskNo, defaultString(taskNo)) |
| | | .eq(OpenApiOrderReportEvent::getReportNo, defaultString(reportNo)) |
| | | .eq(OpenApiOrderReportEvent::getStatus, 1)) > 0; |
| | | } |
| | | |
| | | private OpenApiOrderReportEvent saveReportEvent(String eventId, String taskNo, String reportNo, String orderCode, String payload) { |
| | | OpenApiOrderReportEvent event = new OpenApiOrderReportEvent() |
| | | .setEventId(defaultString(eventId)) |
| | | .setTaskNo(defaultString(taskNo)) |
| | | .setReportNo(defaultString(reportNo)) |
| | | .setOrderCode(orderCode) |
| | | .setPayload(payload) |
| | | .setStatus(0); |
| | | openApiOrderReportEventMapper.insert(event); |
| | | return event; |
| | | } |
| | | |
| | | private int allocateMergedDoneQty(String orderNo, String matnrCode, String batch, String lineId, BigDecimal mergedDoneQty, Map<String, OpenApiOrder> orderCache) { |