chen.lin
11 小时以前 9bb62e919e8c85e7cfca55f0af90da5e48dcedeb
rsf-server/src/main/java/com/vincent/rsf/server/api/service/impl/ReceiveMsgServiceImpl.java
@@ -1,50 +1,53 @@
package com.vincent.rsf.server.api.service.impl;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.vincent.rsf.framework.common.Cools;
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.dto.CheckDiffDto;
import com.vincent.rsf.server.api.controller.erp.params.dto.TransferInfoDto;
import com.vincent.rsf.server.api.controller.erp.params.dto.WkOrderDto;
import com.vincent.rsf.server.api.utils.TimeConverterUtils;
import com.vincent.rsf.server.common.domain.BaseParam;
import com.vincent.rsf.server.common.domain.PageParam;
import com.vincent.rsf.server.common.utils.FieldsUtils;
import com.vincent.rsf.server.manager.controller.dto.LocStockDto;
import com.vincent.rsf.server.manager.controller.params.PakinItem;
import com.vincent.rsf.server.manager.controller.params.WaitPakinParam;
import com.vincent.rsf.server.manager.entity.*;
import com.vincent.rsf.server.manager.enums.*;
import com.vincent.rsf.server.manager.service.*;
import com.vincent.rsf.server.manager.service.impl.MatnrServiceImpl;
import com.vincent.rsf.server.manager.service.impl.WarehouseAreasItemServiceImpl;
import com.vincent.rsf.server.system.constant.DictTypeCode;
import com.vincent.rsf.server.system.constant.SerialRuleCode;
import com.vincent.rsf.server.system.entity.DictData;
import com.vincent.rsf.server.system.entity.DictType;
import com.vincent.rsf.server.system.entity.Fields;
import com.vincent.rsf.server.system.service.DictDataService;
import com.vincent.rsf.server.system.service.DictTypeService;
import com.vincent.rsf.server.system.service.FieldsService;
import com.vincent.rsf.server.system.service.impl.DictDataServiceImpl;
import com.vincent.rsf.server.system.utils.SerialRuleUtils;
import com.vincent.rsf.server.api.service.ReceiveMsgService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;
import static com.vincent.rsf.server.system.utils.SerialRuleUtils.objectToMap;
import static com.vincent.rsf.server.manager.enums.OrderWorkType.*;
/**
 * @author Ryan
@@ -103,6 +106,12 @@
    private DictDataService dictDataService;
    @Autowired
    private DictTypeService dictTypeService;
    @Autowired
    private WaitPakinService waitPakinService;
    @Autowired
    private WarehouseAreasItemServiceImpl warehouseAreasItemService;
    @Autowired
    private LocItemService locItemService;
    /**
@@ -413,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)) {
@@ -434,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();
@@ -444,32 +453,63 @@
                        .setWkType(one.getValue())
                        .setAnfme(syncOrder.getAnfme())
                        .setPoCode(syncOrder.getOrderNo())
                        .setWorkQty(0.0)
                        .setQty(0.0)
                        .setWorkQty(0.0)//执行数量
                        .setQty(0.0)//完成数量
                        .setPoId(syncOrder.getOrderInternalCode())
                        .setCode(ruleCode)
                        .setArrTime(syncOrder.getArrTime())
                        .setId(null)
                        .setCreateTime(new Date())
                        .setCreateTime(new TimeConverterUtils().timestampToDate(syncOrder.getCreateTime()))
                        .setBusinessTime(new TimeConverterUtils().timestampToDate(syncOrder.getBusinessTime()))
                        .setUpdateTime(new Date())
                        .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)) {
                    throw new CoolException("单据保存失败!!");
                }
                AtomicReference<String> palletId = new AtomicReference<>();
                syncOrder.getOrderItems().forEach(orderItem -> {
                    if (Cools.isEmpty(palletId.get())) {
                        palletId.set(orderItem.getPalletId());
                    } else {
                        if (!palletId.get().equals(orderItem.getPalletId())) {
                            throw new CoolException("同一个单据明细中的托盘码必须一致!!!");
                        }
                    }
                    Map<String, Object> map = new ObjectMapper().convertValue(orderItem, Map.class);
                    map.put("orderId", wkOrder.getId());
                    map.put("poId", wkOrder.getPoId());
                    map.put("poCode", wkOrder.getPoCode());
                    map.put("order_code", wkOrder.getCode());
                    map.put("matnrCode", orderItem.getMatnr());
                    map.put("platWorkCode", orderItem.getPlanNo());
                    map.put("platItemId", orderItem.getLineId());
                    map.put("splrBatch", orderItem.getBatch());
                    map.put("batch", orderItem.getBatch());
                    map.put("spec", orderItem.getSpecs());
                    map.put("model", orderItem.getModel());
                    map.put("stockUnit", orderItem.getUnit());
                    map.put("purUnit", orderItem.getUnit());
                    map.put("baseUnit", orderItem.getBaseUnitId());
                    map.put("useOrgId", orderItem.getUseOrgId());
                    map.put("useOrgName", orderItem.getUseOrgName());
                    map.put("erpClsId", orderItem.getErpClsId());
                    map.put("priceUnitId", orderItem.getPriceUnitId());
                    map.put("inStockType", orderItem.getInStockType());
                    map.put("ownerTypeId", orderItem.getOwnerTypeId());
                    map.put("ownerId", orderItem.getOwnerId());
                    map.put("ownerName", orderItem.getOwnerName());
                    map.put("keeperTypeId", orderItem.getKeeperTypeId());
                    map.put("keeperId", orderItem.getKeeperId());
                    map.put("keeperName", orderItem.getKeeperName());
                    map.put("targetWarehouseId", orderItem.getTargetWarehouseId());
                    map.put("sourceWarehouseId", orderItem.getSourceWarehouseId());
                    map.put("createBy", loginUserId);
                    map.put("updateBy", loginUserId);
                    if (!asnOrderItemService.fieldsSave(map, loginUserId)) {
                        throw new CoolException("明细保存失败!!");
@@ -482,9 +522,62 @@
                if (!asnOrderService.updateById(wkOrder)) {
                    throw new CoolException("计划收货数量修改失败!!");
                }
                // 立即触发异步任务,不等待结果
                if (!Cools.isEmpty(palletId.get()) && StringUtils.isNotBlank(syncOrder.getOrderNo()) && !Cools.isEmpty(syncOrder.getStationId())) {
                    //组托
                    WaitPakinParam pakinParam = new WaitPakinParam();
                    pakinParam.setBarcode(palletId.get());
                    pakinParam.setStaNo(syncOrder.getStationId());
                    boolean itemsCheck = waitPakinService.mergeItemsCheck(pakinParam, loginUserId);
                    if (itemsCheck) {
                        CompletableFuture.runAsync(() -> {
                            try {
                                asyncMergeItemsWcs(pakinParam, syncOrder.getOrderNo(), loginUserId);
                            } catch (Exception e) {
                                log.warn("订单 {} 开始自动组托", syncOrder.getOrderNo());
                            }
                        });
                    }
                }
            });
        }
        return R.ok();
    }
    @Async
    public void asyncMergeItemsWcs(WaitPakinParam param, String orderNo, Long loginUserId) {
        try {
            int i = 0;
            while (true) {
                i++;
                if (i > 5) return;
                Thread.sleep(3000);
                List<WarehouseAreasItem> list = warehouseAreasItemService.list(new LambdaQueryWrapper<WarehouseAreasItem>()
                        .eq(WarehouseAreasItem::getAsnCode, orderNo));
                if (list.isEmpty()) {
                    log.warn("订单 {} 没有找到库区项目,跳过组托", orderNo);
                    continue;
                }
                List<PakinItem> itemList = list.stream().map(item -> {
                    PakinItem pakinItem = new PakinItem();
                    pakinItem.setAsnCode(item.getAsnCode());
                    pakinItem.setId(item.getId());
                    pakinItem.setMatnrId(item.getMatnrId());
                    pakinItem.setReceiptQty(item.getAnfme());
                    return pakinItem;
                }).collect(Collectors.toList());
                param.setItems(itemList);
                break;
            }
            waitPakinService.mergeItemsWcs(param, loginUserId);
            log.info("订单 {} 自动组托完成,共处理 {} 个项目", orderNo, param.getItems().size());
        } catch (Exception e) {
            log.error("订单 {} 自动组托失败: {}", orderNo, e.getMessage(), e);
        }
    }
    /**
@@ -775,6 +868,7 @@
    /**
     * 基础物料信息变更
     *
     * @param baseMatParms
     * @return
     */
@@ -820,4 +914,290 @@
        return R.ok();
    }
    /**
     * 库存查询明细(供open-api调用)
     *
     * @param condition 查询条件实体类
     * @return 库存明细列表
     */
    @Override
    public R erpQueryInventoryDetails(InventoryQueryConditionParam condition) {
        try {
            // 参数验证
            if (condition == null) {
                return R.error("查询条件不能为空");
            }
            // 将ERP参数映射为数据库字段名(下划线格式)
            Map<String, Object> queryMap = new HashMap<>();
            // 从实体类中提取查询条件,映射为真实的数据库字段名
            if (StringUtils.isNotBlank(condition.getLocId())) {
                queryMap.put("loc_code", condition.getLocId());
            }
            if (StringUtils.isNotBlank(condition.getMatNr())) {
                queryMap.put("matnr_code", condition.getMatNr());
            }
            if (StringUtils.isNotBlank(condition.getPlanNo())) {
                queryMap.put("track_code", condition.getPlanNo());
            }
            if (StringUtils.isNotBlank(condition.getBatch())) {
                queryMap.put("batch", condition.getBatch());
            }
            // 注意:orderNo 和 wareHouseId 不在 LocItem 表中,需要通过其他方式查询
            // orderNo 已在后面单独处理(plat_order_code 和 plat_work_code)
            // wareHouseId 需要通过 Loc 表关联查询,已在后面单独处理
            BaseParam baseParam = new BaseParam();
            baseParam.syncMap(queryMap);
            PageParam<LocItem, BaseParam> pageParam = new PageParam<>(baseParam, LocItem.class);
            QueryWrapper<LocItem> wrapper = pageParam.buildWrapper(false);
            // 订单号/工单号/MES工单号
            // 订单号可能存储在:1) LocItem.plat_order_code 2) LocItem.plat_work_code 3) WkOrder.code (通过orderId关联)
            if (StringUtils.isNotBlank(condition.getOrderNo())) {
                String orderNo = condition.getOrderNo();
                // 先查询WkOrder表,获取匹配的订单ID列表
                LambdaQueryWrapper<WkOrder> orderWrapper = new LambdaQueryWrapper<>();
                orderWrapper.eq(WkOrder::getCode, orderNo);
                List<WkOrder> matchingOrders = asnOrderService.list(orderWrapper);
                List<Long> matchingOrderIds = matchingOrders.stream()
                        .map(WkOrder::getId)
                        .collect(Collectors.toList());
                // 构建订单号查询条件:LocItem表的plat_order_code、plat_work_code,或通过orderId关联WkOrder.code
                wrapper.and(w -> {
                    w.eq("plat_order_code", orderNo)
                     .or().eq("plat_work_code", orderNo);
                    // 如果找到了匹配的订单,也查询orderId
                    if (!matchingOrderIds.isEmpty()) {
                        w.or().in("order_id", matchingOrderIds);
                    }
                });
            }
            // 物料组(需要通过物料表关联查询)
            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;
    }
}