rsf-open-api/pom.xml
@@ -14,6 +14,7 @@ <maven.compiler.source>17</maven.compiler.source> <maven.compiler.target>17</maven.compiler.target> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.proc>full</maven.compiler.proc> </properties> <dependencies> <dependency> @@ -44,6 +45,18 @@ <artifactId>httpclient</artifactId> <version>4.5.13</version> </dependency> <!-- OpenFeign依赖 --> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-openfeign</artifactId> </dependency> <!-- Lombok依赖 --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.30</version> <scope>provided</scope> </dependency> </dependencies> <build> <finalName>rsf-open-api</finalName> @@ -64,6 +77,22 @@ </nonFilteredFileExtensions> </configuration> </plugin> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>17</source> <target>17</target> <encoding>UTF-8</encoding> <annotationProcessorPaths> <path> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>1.18.30</version> </path> </annotationProcessorPaths> </configuration> </plugin> </plugins> </build> rsf-open-api/src/main/java/com/vincent/rsf/openApi/OpenApi.java
@@ -4,8 +4,12 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration; import org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration; import org.springframework.cloud.openfeign.EnableFeignClients; @SpringBootApplication(exclude = {SecurityAutoConfiguration.class, UserDetailsServiceAutoConfiguration.class }) @SpringBootApplication( exclude = {SecurityAutoConfiguration.class, UserDetailsServiceAutoConfiguration.class} ) @EnableFeignClients(basePackages = "com.vincent.rsf.openApi.feign") public class OpenApi { public static void main(String[] args) { SpringApplication.run(OpenApi.class, args); rsf-open-api/src/main/java/com/vincent/rsf/openApi/controller/phyz/ERPController.java
@@ -3,21 +3,26 @@ import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.vincent.rsf.framework.common.R; import com.vincent.rsf.framework.exception.CoolException; import com.vincent.rsf.openApi.entity.dto.CommonResponse; import com.vincent.rsf.openApi.entity.phyz.*; import com.vincent.rsf.openApi.feign.wms.WmsServerFeignClient; import com.vincent.rsf.openApi.service.phyz.ErpReportService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import lombok.extern.slf4j.Slf4j; import org.apache.commons.compress.utils.Lists; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.annotation.Resource; import java.util.ArrayList; import java.util.List; import java.util.Map; import java.util.Objects; import static com.vincent.rsf.openApi.controller.AuthController.SIMULATED_DATA_ENABLE; @@ -32,6 +37,9 @@ @Resource private ErpReportService erpReportService; @Autowired(required = false) private WmsServerFeignClient wmsServerFeignClient; @ApiOperation("仓库信息同步") @@ -147,7 +155,7 @@ @ApiOperation("库存查询明细") @PostMapping("/inventory/details") public CommonResponse queryInventoryDetails(@RequestBody JSONObject params) { public CommonResponse queryInventoryDetails(@RequestBody InventoryQueryCondition condition) { if (SIMULATED_DATA_ENABLE.equals("1")) { String x = "[\n" + " {\n" + @@ -193,10 +201,77 @@ return CommonResponse.ok(JSONArray.parseArray(map.toJSONString(), InventoryDetails.class)); } InventoryQueryCondition condition = JSON.parseObject(params.toJSONString(), InventoryQueryCondition.class); // 数据处理,转发server List<InventoryDetails> inventoryDetails = Lists.newArrayList(); return new CommonResponse().setCode(200).setData(inventoryDetails); try { if (wmsServerFeignClient == null) { log.warn("WmsServerFeignClient未注入,无法进行调用"); return CommonResponse.error("服务未初始化"); } // 参数验证 if (condition == null) { return CommonResponse.error("查询条件不能为空"); } log.info("库存查询明细请求参数: {}", JSON.toJSONString(condition)); // 直接传递实体类,Feign会自动序列化为JSON R result = wmsServerFeignClient.queryInventoryDetails(condition); log.info("库存查询明细返回结果: {}", JSON.toJSONString(result)); if (result != null) { // R类继承自HashMap,使用get方法获取值 Integer code = (Integer) result.get("code"); String msg = (String) result.get("msg"); Object data = result.get("data"); if (code != null && code == 200) { // 将Map列表转换为InventoryDetails列表 if (data != null) { @SuppressWarnings("unchecked") List<Map<String, Object>> dataList = (List<Map<String, Object>>) data; List<InventoryDetails> inventoryDetails = new ArrayList<>(); for (Map<String, Object> item : dataList) { InventoryDetails details = JSON.parseObject(JSON.toJSONString(item), InventoryDetails.class); inventoryDetails.add(details); } return CommonResponse.ok(inventoryDetails); } else { return CommonResponse.ok(new ArrayList<>()); } } else { return CommonResponse.error(msg != null ? msg : "查询失败"); } } else { return CommonResponse.error("查询失败:返回结果为空"); } } catch (Exception e) { log.error("库存查询明细失败", e); // 过滤错误消息中的URL,只保留错误类型 String errorMessage = e.getMessage(); if (errorMessage != null) { // 如果包含"executing",说明是HTTP请求错误,去掉URL部分 if (errorMessage.contains("executing")) { int executingIndex = errorMessage.indexOf("executing"); if (executingIndex > 0) { // 提取"executing"之前的部分(如"Read timed out") errorMessage = errorMessage.substring(0, executingIndex).trim(); } else { // 如果"executing"在开头,使用默认错误消息 errorMessage = "请求超时"; } } // 如果包含"http://"或"https://",也尝试去掉URL部分 else if (errorMessage.contains("http://") || errorMessage.contains("https://")) { // 使用正则表达式去掉URL errorMessage = errorMessage.replaceAll("https?://[^\\s]+", "").trim(); if (errorMessage.isEmpty()) { errorMessage = "请求失败"; } } } return CommonResponse.error("查询失败:" + (errorMessage != null && !errorMessage.isEmpty() ? errorMessage : "未知错误")); } } @ApiOperation("库存查询汇总") rsf-open-api/src/main/java/com/vincent/rsf/openApi/entity/constant/WmsConstant.java
@@ -40,6 +40,8 @@ //移库任务申请 public static String WCS_CREATE_LOC_MOVE_TASK = "/rsf-server/wcs/createLocMoveTask"; //库存查询明细(ERP接口,对应open-api的/inventory/details) public static final String QUERY_INVENTORY_DETAILS = "/rsf-server/erp/inventory/details"; } rsf-open-api/src/main/java/com/vincent/rsf/openApi/entity/phyz/Station.java
@@ -47,5 +47,5 @@ // 是否可用 @JsonProperty("IsValid") @JSONField(name = "IsValid") private boolean isValid; private Boolean valid; } rsf-open-api/src/main/java/com/vincent/rsf/openApi/feign/wms/WmsServerFeignClient.java
New file @@ -0,0 +1,34 @@ package com.vincent.rsf.openApi.feign.wms; import com.vincent.rsf.framework.common.R; import com.vincent.rsf.openApi.entity.constant.WmsConstant; import com.vincent.rsf.openApi.entity.phyz.InventoryQueryCondition; import com.vincent.rsf.openApi.feign.wms.fallback.WmsServerFeignClientFallback; import org.springframework.cloud.openfeign.FeignClient; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; /** * WMS Server模块Feign客户端 * 用于调用rsf-server模块的接口 * * 注意:url配置从application.yml中读取platform.wms.host和platform.wms.port * 如果open-api和server在同一应用中运行,可以配置为本地地址 * 如果分开部署,url应该配置为server模块的实际地址,如:http://127.0.0.1:8085 */ @FeignClient( name = "wms-server", url = "${platform.wms.host:http://127.0.0.1}:${platform.wms.port:8085}", path = "", fallback = WmsServerFeignClientFallback.class ) public interface WmsServerFeignClient { /** * 库存查询明细(调用server端的erpQueryInventoryDetails方法) * @param condition 查询条件实体类 * @return 库存明细列表 */ @PostMapping(WmsConstant.QUERY_INVENTORY_DETAILS) R queryInventoryDetails(@RequestBody InventoryQueryCondition condition); } rsf-open-api/src/main/java/com/vincent/rsf/openApi/feign/wms/fallback/WmsServerFeignClientFallback.java
New file @@ -0,0 +1,21 @@ package com.vincent.rsf.openApi.feign.wms.fallback; import com.vincent.rsf.framework.common.R; import com.vincent.rsf.openApi.entity.phyz.InventoryQueryCondition; import com.vincent.rsf.openApi.feign.wms.WmsServerFeignClient; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Component; /** * WMS Server Feign客户端降级处理 */ @Slf4j @Component public class WmsServerFeignClientFallback implements WmsServerFeignClient { @Override public R queryInventoryDetails(InventoryQueryCondition condition) { log.error("调用WMS Server库存查询明细接口失败,触发降级处理"); return R.error("服务调用失败,请稍后重试"); } } rsf-server/src/main/java/com/vincent/rsf/server/api/controller/erp/ErpQueryController.java
@@ -1,25 +1,24 @@ package com.vincent.rsf.server.api.controller.erp; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.vincent.rsf.server.api.service.ReceiveMsgService; import com.vincent.rsf.framework.common.R; import com.vincent.rsf.framework.exception.CoolException; import com.vincent.rsf.server.api.controller.erp.params.*; import com.vincent.rsf.server.api.controller.erp.params.InventoryQueryConditionParam; import com.vincent.rsf.server.api.controller.erp.params.QueryOrderParam; import com.vincent.rsf.server.api.service.ReceiveMsgService; import com.vincent.rsf.server.common.annotation.OperationLog; import com.vincent.rsf.server.common.domain.BaseParam; import com.vincent.rsf.server.common.domain.PageParam; import com.vincent.rsf.framework.common.R; import com.vincent.rsf.server.manager.entity.Loc; import com.vincent.rsf.server.manager.entity.Transfer; import com.vincent.rsf.server.manager.service.MatnrGroupService; import com.vincent.rsf.server.manager.service.*; import com.vincent.rsf.server.system.controller.BaseController; import io.swagger.annotations.Api; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import io.swagger.annotations.ApiOperation; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import java.util.Map; import java.util.Objects; @@ -104,4 +103,22 @@ return receiveMsgService.queryTransfer(queryParams); } /** * ERP库存查询明细(供open-api模块调用) * 对应open-api的 /inventory/details 接口 * @param condition 查询条件 * @return 库存明细列表 */ @PostMapping("/inventory/details") @ApiOperation(value = "ERP库存查询明细", hidden = true) @OperationLog("ERP库存查询明细") public R erpQueryInventoryDetails(@RequestBody InventoryQueryConditionParam condition) { // 参数验证 if (condition == null) { return R.error("查询条件不能为空"); } return receiveMsgService.erpQueryInventoryDetails(condition); } } rsf-server/src/main/java/com/vincent/rsf/server/api/controller/erp/params/InventoryQueryConditionParam.java
New file @@ -0,0 +1,129 @@ package com.vincent.rsf.server.api.controller.erp.params; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import lombok.experimental.Accessors; import java.util.Map; /** * 库存查询明细条件参数(供ERP调用) * 对应open-api的InventoryQueryCondition */ @Data @JsonIgnoreProperties(ignoreUnknown = true) @Accessors(chain = true) @ApiModel(value = "InventoryQueryConditionParam", description = "库存查询明细条件参数") public class InventoryQueryConditionParam { /** * 仓库编码 */ @ApiModelProperty(value = "仓库编码") private String wareHouseId; /** * 库位编码 */ @ApiModelProperty(value = "库位编码") private String locId; /** * 物料编码 */ @ApiModelProperty(value = "物料编码") private String matNr; /** * 订单号/工单号/MES工单号 */ @ApiModelProperty(value = "订单号/工单号/MES工单号") private String orderNo; /** * 计划跟踪号 */ @ApiModelProperty(value = "计划跟踪号") private String planNo; /** * 批次号 */ @ApiModelProperty(value = "批次号") private String batch; /** * 物料组 */ @ApiModelProperty(value = "物料组") private String matGroup; /** * 从Map构造InventoryQueryConditionParam对象 * 用于接收其他方法返回的Map参数并自动转换 * * @param map 查询条件Map * @return InventoryQueryConditionParam对象 */ public static InventoryQueryConditionParam fromMap(Map<String, Object> map) { if (map == null) { return null; } InventoryQueryConditionParam param = new InventoryQueryConditionParam(); if (map.containsKey("wareHouseId")) { param.setWareHouseId((String) map.get("wareHouseId")); } if (map.containsKey("locId")) { param.setLocId((String) map.get("locId")); } if (map.containsKey("matNr")) { param.setMatNr((String) map.get("matNr")); } if (map.containsKey("orderNo")) { param.setOrderNo((String) map.get("orderNo")); } if (map.containsKey("planNo")) { param.setPlanNo((String) map.get("planNo")); } if (map.containsKey("batch")) { param.setBatch((String) map.get("batch")); } if (map.containsKey("matGroup")) { param.setMatGroup((String) map.get("matGroup")); } return param; } /** * 转换为Map(用于兼容需要Map参数的方法) * * @return Map对象 */ public Map<String, Object> toMap() { Map<String, Object> map = new java.util.HashMap<>(); if (wareHouseId != null) { map.put("wareHouseId", wareHouseId); } if (locId != null) { map.put("locId", locId); } if (matNr != null) { map.put("matNr", matNr); } if (orderNo != null) { map.put("orderNo", orderNo); } if (planNo != null) { map.put("planNo", planNo); } if (batch != null) { map.put("batch", batch); } if (matGroup != null) { map.put("matGroup", matGroup); } return map; } } rsf-server/src/main/java/com/vincent/rsf/server/api/service/ReceiveMsgService.java
@@ -152,4 +152,11 @@ * @return */ R matUpdate(BaseMatParms baseMatParms); /** * 库存查询明细(供open-api调用) * @param condition 查询条件 * @return 库存明细列表 */ R erpQueryInventoryDetails(InventoryQueryConditionParam condition); } rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/ReceiveMsgServiceImpl.java
@@ -47,6 +47,8 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; import static com.vincent.rsf.server.manager.enums.OrderWorkType.*; /** * @author Ryan * @version 1.0 @@ -108,6 +110,8 @@ private WaitPakinService waitPakinService; @Autowired private WarehouseAreasItemServiceImpl warehouseAreasItemService; @Autowired private LocItemService locItemService; /** @@ -418,7 +422,7 @@ if (Objects.isNull(one)) { throw new CoolException("单据:" + syncOrder.getOrderNo() + ", 业务类型不存在!!"); } WkOrder order = asnOrderService.getOne(new LambdaQueryWrapper<WkOrder>() WkOrder order = asnOrderService.getOne(new LambdaQueryWrapper<WkOrder>() .eq(!Objects.isNull(syncOrder.getOrderId()), WkOrder::getPoId, syncOrder.getOrderId()) .eq(WkOrder::getPoCode, syncOrder.getOrderNo())); if (!Objects.isNull(order)) { @@ -439,7 +443,7 @@ //银座特供 String orderNs = null; if (rule.equals(SerialRuleCode.SYS_ASN_ORDER) || rule.equals(SerialRuleCode.SYS_OUT_STOCK_CODE) ){ if (rule.equals(SerialRuleCode.SYS_ASN_ORDER) || rule.equals(SerialRuleCode.SYS_OUT_STOCK_CODE)) { StringBuffer buffer = new StringBuffer(); Object poCode = syncOrder.getOrderNo(); orderNs = poCode == null ? "" : buffer.append(poCode).toString(); @@ -461,7 +465,7 @@ .setCreateBy(loginUserId) .setUpdateBy(loginUserId); if (syncOrder.getType().equals(OrderType.ORDER_OUT.type)){ if (syncOrder.getType().equals(OrderType.ORDER_OUT.type)) { wkOrder.setExceStatus(AsnExceStatus.OUT_STOCK_STATUS_TASK_INIT.val); } if (!asnOrderService.save(wkOrder)) { @@ -469,10 +473,10 @@ } AtomicReference<String> palletId = new AtomicReference<>(); syncOrder.getOrderItems().forEach(orderItem -> { if (Cools.isEmpty(palletId.get())){ if (Cools.isEmpty(palletId.get())) { palletId.set(orderItem.getPalletId()); } else { if (!palletId.get().equals(orderItem.getPalletId())){ if (!palletId.get().equals(orderItem.getPalletId())) { throw new CoolException("同一个单据明细中的托盘码必须一致!!!"); } } @@ -549,7 +553,7 @@ int i = 0; while (true) { i++; if (i>5) return; if (i > 5) return; Thread.sleep(3000); List<WarehouseAreasItem> list = warehouseAreasItemService.list(new LambdaQueryWrapper<WarehouseAreasItem>() .eq(WarehouseAreasItem::getAsnCode, orderNo)); @@ -575,6 +579,7 @@ log.error("订单 {} 自动组托失败: {}", orderNo, e.getMessage(), e); } } /** * @author Ryan * @date 2025/8/19 @@ -863,6 +868,7 @@ /** * 基础物料信息变更 * * @param baseMatParms * @return */ @@ -908,4 +914,270 @@ return R.ok(); } /** * 库存查询明细(供open-api调用) * * @param condition 查询条件实体类 * @return 库存明细列表 */ @Override public R erpQueryInventoryDetails(InventoryQueryConditionParam condition) { try { // 参数验证 if (condition == null) { return R.error("查询条件不能为空"); } // 将ERP参数映射为Java实体字段名(驼峰格式),PageParam会自动转换为数据库字段名(下划线格式) Map<String, Object> queryMap = new HashMap<>(); // 从实体类中提取查询条件,映射为数据库字段名 if (StringUtils.isNotBlank(condition.getLocId())) { queryMap.put("locCode", condition.getLocId()); } if (StringUtils.isNotBlank(condition.getMatNr())) { queryMap.put("matnrCode", condition.getMatNr()); } if (StringUtils.isNotBlank(condition.getPlanNo())) { queryMap.put("trackCode", condition.getPlanNo()); } if (StringUtils.isNotBlank(condition.getBatch())) { queryMap.put("batch", condition.getBatch()); } BaseParam baseParam = new BaseParam(); baseParam.syncMap(queryMap); PageParam<LocItem, BaseParam> pageParam = new PageParam<>(baseParam, LocItem.class); QueryWrapper<LocItem> wrapper = pageParam.buildWrapper(false); // 订单号/工单号/MES工单号 if (StringUtils.isNotBlank(condition.getOrderNo())) { String orderNo = condition.getOrderNo(); wrapper.and(w -> w.eq("plat_order_code", orderNo) .or().eq("plat_work_code", orderNo)); } // 物料组(需要通过物料表关联查询) if (StringUtils.isNotBlank(condition.getMatGroup())) { // 调用物料Service查询物料组对应的物料ID列表(复用已有方法) LambdaQueryWrapper<Matnr> matnrWrapper = new LambdaQueryWrapper<>(); matnrWrapper.eq(Matnr::getGroupId, condition.getMatGroup()); List<Matnr> matnrs = matnrService.list(matnrWrapper); if (!matnrs.isEmpty()) { List<Long> matnrIds = matnrs.stream().map(Matnr::getId).collect(Collectors.toList()); wrapper.in("matnr_id", matnrIds); } else { // 如果没有找到物料,返回空结果 return R.ok().add(new ArrayList<>()); } } // 只查询正常状态的库存(status=1表示正常) wrapper.eq("status", 1); pageParam.setCurrent(1); pageParam.setSize(Integer.MAX_VALUE); PageParam<LocItem, BaseParam> pageResult = locItemService.page(pageParam, wrapper); List<LocItem> locItems = pageResult.getRecords(); if (locItems.isEmpty()) { return R.ok().add(new ArrayList<>()); } // 获取所有需要关联的ID List<Long> locIds = locItems.stream() .map(LocItem::getLocId) .filter(Objects::nonNull) .distinct() .collect(Collectors.toList()); List<Long> warehouseIds = new ArrayList<>(); List<Long> orderIds = locItems.stream() .map(LocItem::getOrderId) .filter(Objects::nonNull) .distinct() .collect(Collectors.toList()); // 调用LocService查询库位信息(复用Service层方法) Map<Long, Loc> locMap = new HashMap<>(); if (!locIds.isEmpty()) { List<Loc> locs = locService.listByIds(locIds); locMap = locs.stream().collect(Collectors.toMap(Loc::getId, loc -> loc)); // 收集仓库ID warehouseIds = locs.stream() .map(Loc::getWarehouseId) .filter(Objects::nonNull) .distinct() .collect(Collectors.toList()); } // 仓库编码过滤 if (StringUtils.isNotBlank(condition.getWareHouseId())) { String wareHouseId = condition.getWareHouseId(); LambdaQueryWrapper<Warehouse> whWrapper = new LambdaQueryWrapper<>(); whWrapper.eq(Warehouse::getCode, wareHouseId); // 调用WarehouseService查询仓库信息(复用Service层方法) List<Warehouse> warehouses = warehouseService.list(whWrapper); if (!warehouses.isEmpty()) { Long targetWarehouseId = warehouses.get(0).getId(); // 过滤库位,只保留目标仓库的库位 locMap = locMap.entrySet().stream() .filter(entry -> Objects.equals(entry.getValue().getWarehouseId(), targetWarehouseId)) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); // 过滤locItems,只保留目标仓库的 Set<Long> validLocIds = locMap.keySet(); locItems = locItems.stream() .filter(item -> item.getLocId() != null && validLocIds.contains(item.getLocId())) .collect(Collectors.toList()); warehouseIds = Collections.singletonList(targetWarehouseId); } else { return R.ok().add(new ArrayList<>()); } } // 调用WarehouseService查询仓库信息(复用Service层方法) Map<Long, Warehouse> warehouseMap = new HashMap<>(); if (!warehouseIds.isEmpty()) { List<Warehouse> warehouses = warehouseService.listByIds(warehouseIds); warehouseMap = warehouses.stream().collect(Collectors.toMap(Warehouse::getId, wh -> wh)); } // 调用AsnOrderService查询订单信息(复用Service层方法) Map<Long, WkOrder> orderMap = new HashMap<>(); if (!orderIds.isEmpty()) { List<WkOrder> orders = asnOrderService.listByIds(orderIds); orderMap = orders.stream().collect(Collectors.toMap(WkOrder::getId, order -> order)); } // 转换结果 List<Map<String, Object>> result = new ArrayList<>(); for (LocItem locItem : locItems) { Map<String, Object> details = convertToInventoryDetails(locItem, locMap, warehouseMap, orderMap); if (details != null) { result.add(details); } } return R.ok().add(result); } catch (Exception e) { log.error("库存查询明细失败", e); return R.error("查询失败:" + e.getMessage()); } } /** * 转换为库存明细对象 */ private Map<String, Object> convertToInventoryDetails(LocItem locItem, Map<Long, Loc> locMap, Map<Long, Warehouse> warehouseMap, Map<Long, WkOrder> orderMap) { Map<String, Object> details = new HashMap<>(); // 库位编码 details.put("locId", locItem.getLocCode()); // 仓库信息 Loc loc = null; if (locItem.getLocId() != null) { loc = locMap.get(locItem.getLocId()); } if (loc != null) { // 托盘码(从库位的barcode获取) details.put("palletId", loc.getBarcode()); // 仓库信息 if (loc.getWarehouseId() != null && warehouseMap.containsKey(loc.getWarehouseId())) { Warehouse warehouse = warehouseMap.get(loc.getWarehouseId()); if (warehouse != null) { details.put("wareHouseId", warehouse.getCode()); details.put("wareHouseName", warehouse.getName()); } } } // 物料信息 details.put("matNr", locItem.getMatnrCode()); details.put("makTx", locItem.getMaktx()); details.put("spec", locItem.getSpec()); details.put("anfme", locItem.getAnfme()); details.put("unit", locItem.getUnit()); // 库存状态:1-正常(可用),0-冻结 if (locItem.getStatus() != null) { details.put("status", locItem.getStatus() == 1 ? "可用" : "冻结"); } // 批次号 details.put("batch", locItem.getBatch()); // 计划跟踪号 details.put("planNo", locItem.getTrackCode()); // 订单信息 if (locItem.getOrderId() != null && orderMap.containsKey(locItem.getOrderId())) { WkOrder order = orderMap.get(locItem.getOrderId()); if (order != null) { // 订单号 details.put("orderNo", order.getCode()); details.put("orderType", null); // 订单类型:1-出库单,2-入库单,3-调拔单 // 字符串类型映射:out->1(出库单), in->2(入库单), revise->(调拔单), check->(盘点单)) if (StringUtils.isNotBlank(order.getType())) { String orderTypeStr = order.getType().toLowerCase().trim(); switch (orderTypeStr) { case "out": details.put("orderType", 1); break; case "in": details.put("orderType", 2); break; case "revise": break; case "check": break; default: break; } //包含 备料单关键词就变成3 if (StringUtils.isNotBlank(order.getWkType())) { String workDesc = getWorkDesc(order.getWkType()); if (workDesc != null && workDesc.contains("备料单")) { details.put("orderType", 3); } } } // 备料类型:根据业务类型判断 // 正常领料(1),生产补料(2) details.put("prepareType", 1); if (StringUtils.isNotBlank(order.getWkType())) { String workDesc = getWorkDesc(order.getWkType()); if (workDesc != null && workDesc.contains("生产补料")) { details.put("prepareType", 2); } } } } // 如果订单号为空,尝试从platOrderCode或platWorkCode获取 if (!details.containsKey("orderNo") || details.get("orderNo") == null) { if (StringUtils.isNotBlank(locItem.getPlatOrderCode())) { details.put("orderNo", locItem.getPlatOrderCode()); } else if (StringUtils.isNotBlank(locItem.getPlatWorkCode())) { details.put("orderNo", locItem.getPlatWorkCode()); } } // 库存组织(从useOrgId获取) details.put("stockOrgId", locItem.getUseOrgId()); return details; } }