| | |
| | | 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.params.*; |
| | | import com.vincent.rsf.server.api.controller.erp.params.*; |
| | | import com.vincent.rsf.server.api.entity.dto.*; |
| | | import com.vincent.rsf.server.manager.enums.*; |
| | | import com.vincent.rsf.server.api.service.MobileService; |
| | |
| | | import com.vincent.rsf.server.manager.entity.*; |
| | | import com.vincent.rsf.server.manager.mapper.*; |
| | | import com.vincent.rsf.server.manager.service.*; |
| | | import com.vincent.rsf.server.manager.service.impl.BasContainerServiceImpl; |
| | | import com.vincent.rsf.server.system.constant.CodeRes; |
| | | import com.vincent.rsf.server.system.constant.GlobalConfigCode; |
| | | import com.vincent.rsf.server.system.constant.SerialRuleCode; |
| | |
| | | import com.vincent.rsf.server.system.service.UserService; |
| | | import com.vincent.rsf.server.system.utils.SerialRuleUtils; |
| | | import org.apache.commons.lang3.StringUtils; |
| | | import org.slf4j.Logger; |
| | | import org.slf4j.LoggerFactory; |
| | | import org.springframework.beans.BeanUtils; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.beans.factory.annotation.Value; |
| | |
| | | */ |
| | | @Service |
| | | public class MobileServiceImpl implements MobileService { |
| | | |
| | | private static final Logger logger = LoggerFactory.getLogger(MobileServiceImpl.class); |
| | | |
| | | @Value("${super.pwd}") |
| | | private String superPwd; |
| | |
| | | private CompanysService companysService; |
| | | @Autowired |
| | | private OutStockService outStockService; |
| | | @Autowired |
| | | private BasContainerService basContainerService; |
| | | |
| | | /** |
| | | * @return |
| | |
| | | throw new CoolException("数据错误!!"); |
| | | } |
| | | if (!one.getExceStatus().equals(AsnExceStatus.OUT_STOCK_STATUS_TASK_DONE.val)) { |
| | | throw new CoolException("出库单未完成,无法完成收货!!"); |
| | | throw new CoolException("调拔出库单未完成,不可执行收货操作!!"); |
| | | } |
| | | } |
| | | |
| | |
| | | throw new CoolException("数据错误:主单不存在!!"); |
| | | } |
| | | //TODO /**收货数量累加,1. 会出超收情况 2. 会有收货不足情况*/ |
| | | Double rcptedQty = Math.round((wkOrder.getQty() + receiptQty) * 10000) / 10000.0; |
| | | Double rcptedQty = Math.round((wkOrder.getQty() + receiptQty) * 1000000) / 1000000.0; |
| | | wkOrder.setQty(rcptedQty).setExceStatus(AsnExceStatus.ASN_EXCE_STATUS_EXCE_ING.val); |
| | | if (!asnOrderMapper.updateById(wkOrder)) { |
| | | throw new CoolException("已收货数量修改失败!!"); |
| | |
| | | throw new CoolException("请输入正确的时间格式!!"); |
| | | } |
| | | |
| | | Double itemRcptQty = Math.round((dto.getReceiptQty() + orderItem.getQty()) * 10000) / 10000.0; |
| | | Double itemRcptQty = Math.round((dto.getReceiptQty() + orderItem.getQty()) * 1000000) / 1000000.0; |
| | | Boolean allowOver = false; |
| | | if (!Objects.isNull(config)) { |
| | | if (Boolean.parseBoolean(config.getVal())) { |
| | |
| | | |
| | | if (!Objects.isNull(serviceOne)) { |
| | | item.setId(serviceOne.getId()); |
| | | Double anfme = Math.round((item.getAnfme() + serviceOne.getAnfme()) * 10000) / 10000.0; |
| | | Double anfme = Math.round((item.getAnfme() + serviceOne.getAnfme()) * 1000000) / 1000000.0; |
| | | item.setAnfme(anfme); |
| | | } |
| | | |
| | |
| | | * @time 2025/4/7 16:58 |
| | | */ |
| | | @Override |
| | | public R getDeltByCode(Map<String, Object> params) { |
| | | Object code = params.get("code"); |
| | | Object matnrCode = params.get("matnrCode"); |
| | | Object asnCode = params.get("asnCode"); |
| | | Object batch = params.get("batch"); |
| | | public R getDeltByCode(Map<String, String> params) { |
| | | String code = params.get("code"); |
| | | String matnrCode = params.get("matnrCode"); |
| | | String asnCode = params.get("asnCode"); |
| | | String crushNo = params.get("fieldsIndex"); |
| | | String batch = params.get("batch"); |
| | | // String barcode = params.get("barcode"); |
| | | |
| | | // if (Objects.isNull(crushNo)) { |
| | | // throw new CoolException("票号不能为空!!"); |
| | | // } |
| | | // if (Objects.isNull(code)) { |
| | | // throw new CoolException("容器号不能为空!!"); |
| | | // } |
| | | // BasContainer container = basContainerService.getOne(new LambdaQueryWrapper<BasContainer>().eq(BasContainer::getCode, barcode)); |
| | | // if (Objects.isNull(container)) { |
| | | // throw new CoolException("容器不存在!!"); |
| | | // } |
| | | // if (!Objects.isNull(params.get("isHalf")) && !params.get("isHalf").equals("0")) { |
| | | // container.setIsHalf(1); |
| | | // if (!basContainerService.updateById(container)) { |
| | | // throw new CoolException("容器状态修改失败!!"); |
| | | // } |
| | | // } |
| | | |
| | | String fieldIndexTemp = null; |
| | | if (!Objects.isNull(crushNo)) { |
| | | FieldsItem fieldsItem = fieldsItemService.getOne(new LambdaQueryWrapper<FieldsItem>().eq(FieldsItem::getValue, crushNo).last("Limit 1")); |
| | | if (!Objects.isNull(fieldsItem)) { |
| | | fieldIndexTemp = fieldsItem.getUuid(); |
| | | } |
| | | } |
| | | final String fieldIndex = fieldIndexTemp; |
| | | |
| | | // 检查是否有至少一个有效查询条件 |
| | | boolean hasValidCondition = !Cools.isEmpty(code) || !Cools.isEmpty(batch) |
| | | || !Objects.isNull(fieldIndex) || !Cools.isEmpty(matnrCode) || !Cools.isEmpty(asnCode); |
| | | |
| | | if (!hasValidCondition) { |
| | | throw new CoolException("请至少输入一个查询条件:物料编码、ASN单号、跟踪码、批次或票号"); |
| | | } |
| | | |
| | | // 如果扫描物料编码且ASN单号为空,直接从物料信息表获取,不查询收货区 |
| | | if (!Cools.isEmpty(matnrCode) && Cools.isEmpty(asnCode) && Cools.isEmpty(code) |
| | | && Cools.isEmpty(batch) && Objects.isNull(fieldIndex)) { |
| | | logger.info("=== 从物料信息表查询物料信息(不查询收货区) ==="); |
| | | logger.info("查询参数 - matnrCode: {}", matnrCode); |
| | | |
| | | Matnr matnr = matnrMapper.selectOne(new LambdaQueryWrapper<Matnr>() |
| | | .eq(Matnr::getCode, matnrCode) |
| | | .eq(Matnr::getDeleted, 0) |
| | | .last("LIMIT 1")); |
| | | |
| | | if (matnr == null) { |
| | | logger.warn("物料信息表中未找到物料编码: {}", matnrCode); |
| | | return R.ok(new ArrayList<>()); |
| | | } |
| | | |
| | | // 构造一个虚拟的 WarehouseAreasItem 对象返回物料信息 |
| | | WarehouseAreasItem item = new WarehouseAreasItem(); |
| | | item.setMatnrId(matnr.getId()); |
| | | item.setMatnrCode(matnr.getCode()); |
| | | item.setMaktx(matnr.getName()); |
| | | item.setStockUnit(matnr.getStockUnit()); |
| | | item.setUnit(matnr.getUnit()); |
| | | item.setAnfme(0.0); // 数量设为0,因为不是从收货区查询的 |
| | | item.setWorkQty(0.0); |
| | | item.setQty(0.0); |
| | | |
| | | // 设置扩展字段 |
| | | Map<String, String> fields = FieldsUtils.getFields(matnr.getFieldsIndex()); |
| | | item.setExtendFields(fields); |
| | | |
| | | List<WarehouseAreasItem> resultList = new ArrayList<>(); |
| | | resultList.add(item); |
| | | |
| | | logger.info("从物料信息表返回 1 条物料数据"); |
| | | return R.ok(resultList); |
| | | } |
| | | |
| | | //TODO 后续需根据策略配置,获取组拖数据。如:混装,按批次混装等 |
| | | LambdaQueryWrapper<WarehouseAreasItem> queryWrapper = new LambdaQueryWrapper<WarehouseAreasItem>() |
| | | .or().eq(!Cools.isEmpty(code), WarehouseAreasItem::getTrackCode, code) |
| | | .or().eq(!Cools.isEmpty(batch), WarehouseAreasItem::getSplrBatch, batch) |
| | | .or().eq(!Cools.isEmpty(matnrCode), WarehouseAreasItem::getMatnrCode, matnrCode) |
| | | .or().eq(!Cools.isEmpty(asnCode), WarehouseAreasItem::getAsnCode, asnCode); |
| | | LambdaQueryWrapper<WarehouseAreasItem> queryWrapper = new LambdaQueryWrapper<>(); |
| | | |
| | | // 构建OR查询条件组 |
| | | // 统计有效条件数量 |
| | | int conditionCount = 0; |
| | | if (!Cools.isEmpty(code)) conditionCount++; |
| | | if (!Cools.isEmpty(batch)) conditionCount++; |
| | | if (!Objects.isNull(fieldIndex)) conditionCount++; |
| | | if (!Cools.isEmpty(matnrCode)) conditionCount++; |
| | | if (!Cools.isEmpty(asnCode)) conditionCount++; |
| | | |
| | | // 如果只有一个条件,直接使用eq;如果有多个条件,使用and包裹or条件组 |
| | | if (conditionCount == 1) { |
| | | // 单个条件,直接查询 |
| | | if (!Cools.isEmpty(code)) { |
| | | queryWrapper.eq(WarehouseAreasItem::getTrackCode, code); |
| | | } else if (!Cools.isEmpty(batch)) { |
| | | queryWrapper.eq(WarehouseAreasItem::getSplrBatch, batch); |
| | | } else if (!Objects.isNull(fieldIndex)) { |
| | | queryWrapper.eq(WarehouseAreasItem::getFieldsIndex, fieldIndex); |
| | | } else if (!Cools.isEmpty(matnrCode)) { |
| | | queryWrapper.eq(WarehouseAreasItem::getMatnrCode, matnrCode); |
| | | } else if (!Cools.isEmpty(asnCode)) { |
| | | queryWrapper.eq(WarehouseAreasItem::getAsnCode, asnCode); |
| | | } |
| | | } else { |
| | | // 多个条件,使用OR连接 |
| | | queryWrapper.and(wrapper -> { |
| | | boolean first = true; |
| | | if (!Cools.isEmpty(code)) { |
| | | wrapper.eq(WarehouseAreasItem::getTrackCode, code); |
| | | first = false; |
| | | } |
| | | if (!Cools.isEmpty(batch)) { |
| | | if (!first) wrapper.or(); |
| | | wrapper.eq(WarehouseAreasItem::getSplrBatch, batch); |
| | | first = false; |
| | | } |
| | | if (!Objects.isNull(fieldIndex)) { |
| | | if (!first) wrapper.or(); |
| | | wrapper.eq(WarehouseAreasItem::getFieldsIndex, fieldIndex); |
| | | first = false; |
| | | } |
| | | if (!Cools.isEmpty(matnrCode)) { |
| | | if (!first) wrapper.or(); |
| | | wrapper.eq(WarehouseAreasItem::getMatnrCode, matnrCode); |
| | | first = false; |
| | | } |
| | | if (!Cools.isEmpty(asnCode)) { |
| | | if (!first) wrapper.or(); |
| | | wrapper.eq(WarehouseAreasItem::getAsnCode, asnCode); |
| | | } |
| | | }); |
| | | } |
| | | |
| | | // 打印查询参数到控制台 |
| | | logger.info("=== 查询可组托物料 ==="); |
| | | logger.info("查询参数 - code: {}, matnrCode: {}, asnCode: {}, batch: {}, fieldIndex: {}", |
| | | code, matnrCode, asnCode, batch, fieldIndex); |
| | | |
| | | List<WarehouseAreasItem> list = warehouseAreasItemService.list(queryWrapper); |
| | | list.removeIf(e -> e.getAnfme() <= e.getWorkQty()); |
| | | logger.info("查询到 {} 条收货区库存数据", list.size()); |
| | | |
| | | // 过滤条件:只返回可组托数量 > 0 的数据 |
| | | // 可组托数量 = anfme - workQty - qty |
| | | if (!list.isEmpty()) { |
| | | int beforeFilterSize = list.size(); |
| | | list.removeIf(e -> { |
| | | // 如果anfme为null,移除该数据 |
| | | Double anfme = e.getAnfme(); |
| | | if (Objects.isNull(anfme) || anfme <= 0) { |
| | | logger.debug("过滤数据 - ID: {}, matnrCode: {}, anfme为null或<=0: {}", |
| | | e.getId(), e.getMatnrCode(), anfme); |
| | | return true; // 移除数量为null或<=0的数据 |
| | | } |
| | | |
| | | Double workQty = Objects.isNull(e.getWorkQty()) ? 0.0 : e.getWorkQty(); |
| | | Double qty = Objects.isNull(e.getQty()) ? 0.0 : e.getQty(); |
| | | |
| | | // 可组托数量 = 总数量 - 已执行数量 - 已收货数量 |
| | | Double availableQty = anfme - workQty - qty; |
| | | if (availableQty <= 0) { |
| | | logger.debug("过滤数据 - ID: {}, matnrCode: {}, anfme: {}, workQty: {}, qty: {}, 可组托数量: {} <= 0", |
| | | e.getId(), e.getMatnrCode(), anfme, workQty, qty, availableQty); |
| | | } |
| | | return availableQty <= 0; // 移除可组托数量 <= 0 的数据 |
| | | }); |
| | | |
| | | // 如果过滤后数据为空,说明所有数据都被过滤掉了 |
| | | if (list.isEmpty() && beforeFilterSize > 0) { |
| | | logger.warn("未找到可组托的物料,请检查:1.物料编码是否正确 2.物料是否已收货至收货区 3.是否还有可组托数量"); |
| | | logger.warn("查询条件 - code: {}, matnrCode: {}, asnCode: {}, batch: {}, fieldIndex: {}", |
| | | code, matnrCode, asnCode, batch, fieldIndex); |
| | | logger.warn("查询到 {} 条数据,但全部被过滤(可组托数量 <= 0)", beforeFilterSize); |
| | | } |
| | | } else { |
| | | logger.warn("未找到可组托的物料,请检查:1.物料编码是否正确 2.物料是否已收货至收货区 3.是否还有可组托数量"); |
| | | logger.warn("查询条件 - code: {}, matnrCode: {}, asnCode: {}, batch: {}, fieldIndex: {}", |
| | | code, matnrCode, asnCode, batch, fieldIndex); |
| | | logger.warn("数据库查询结果为空,可能原因:1.物料编码不匹配 2.物料未收货至收货区 3.数据已被删除"); |
| | | } |
| | | |
| | | // 如果扫描物料编码加载物料并且ASN单号为空时,从物料信息表获取物料信息并更新 |
| | | if (!Cools.isEmpty(matnrCode) && Cools.isEmpty(asnCode) && !list.isEmpty()) { |
| | | // 收集所有唯一的物料编码 |
| | | Set<String> matnrCodes = list.stream() |
| | | .map(WarehouseAreasItem::getMatnrCode) |
| | | .filter(matCode -> !Cools.isEmpty(matCode)) |
| | | .collect(Collectors.toSet()); |
| | | |
| | | // 批量查询物料信息 |
| | | if (!matnrCodes.isEmpty()) { |
| | | Map<String, Matnr> matnrMap = new HashMap<>(); |
| | | for (String matCode : matnrCodes) { |
| | | Matnr matnr = matnrMapper.selectOne(new LambdaQueryWrapper<Matnr>() |
| | | .eq(Matnr::getCode, matCode) |
| | | .eq(Matnr::getDeleted, 0) |
| | | .last("LIMIT 1")); |
| | | if (matnr != null) { |
| | | matnrMap.put(matCode, matnr); |
| | | } |
| | | } |
| | | |
| | | // 更新列表中的物料信息 |
| | | list.forEach(item -> { |
| | | String itemMatnrCode = item.getMatnrCode(); |
| | | if (!Cools.isEmpty(itemMatnrCode) && matnrMap.containsKey(itemMatnrCode)) { |
| | | Matnr matnr = matnrMap.get(itemMatnrCode); |
| | | // 从物料信息表更新物料名称 |
| | | if (!Cools.isEmpty(matnr.getName())) { |
| | | item.setMaktx(matnr.getName()); |
| | | } |
| | | // 从物料信息表更新库存单位 |
| | | if (!Cools.isEmpty(matnr.getStockUnit())) { |
| | | item.setStockUnit(matnr.getStockUnit()); |
| | | } |
| | | // 从物料信息表更新单位 |
| | | if (!Cools.isEmpty(matnr.getUnit())) { |
| | | item.setUnit(matnr.getUnit()); |
| | | } |
| | | logger.debug("已从物料信息表更新物料信息 - matnrCode: {}, name: {}, stockUnit: {}", |
| | | itemMatnrCode, matnr.getName(), matnr.getStockUnit()); |
| | | } |
| | | }); |
| | | } |
| | | } |
| | | |
| | | list.forEach(item -> { |
| | | Map<String, String> fields = FieldsUtils.getFields(item.getFieldsIndex()); |
| | | item.setExtendFields(fields); |
| | | }); |
| | | |
| | | logger.info("返回 {} 条可组托物料数据", list.size()); |
| | | return R.ok(list); |
| | | } |
| | | |
| | |
| | | */ |
| | | @Override |
| | | public R getItemByContainer(Map<String, Object> params) { |
| | | // if (Objects.isNull(params.get("code"))) { |
| | | // throw new CoolException("参数不能为空!!"); |
| | | // } |
| | | //获取组拖未生成任务的组拖档 |
| | | List<Short> asList = Arrays.asList(Short.valueOf(PakinIOStatus.PAKIN_IO_STATUS_DONE.val)); |
| | | Short flagDefect = 0; |
| | | if (!Objects.isNull(params.get("type")) && params.get("type").equals("defective")) { |
| | | flagDefect = 1; |
| | | } |
| | | List<WaitPakin> waitPakin = waitPakinService.list(new LambdaQueryWrapper<WaitPakin>() |
| | | WaitPakin waitPakin = waitPakinService.getOne(new LambdaQueryWrapper<WaitPakin>() |
| | | .eq(WaitPakin::getBarcode, params.get("barcode").toString()) |
| | | // .eq(WaitPakin::getFlagDefect, flagDefect) |
| | | .eq(WaitPakin::getFlagDefect, flagDefect) |
| | | .in(WaitPakin::getIoStatus, asList)); |
| | | if (!Cools.isEmpty(waitPakin)) { |
| | | throw new CoolException("托盘不可用,在组托中已存在"); |
| | | // if (!Cools.isEmpty(waitPakin)) { |
| | | // throw new CoolException("托盘不可用,在组托中已存在"); |
| | | // } |
| | | List<Task> tasks = taskService.list(new LambdaQueryWrapper<Task>().eq(Task::getBarcode, params.get("barcode").toString())); |
| | | if (!tasks.isEmpty()) { |
| | | throw new CoolException("托盘码已在任务档执行!!"); |
| | | } |
| | | List<Loc> locs = locService.list(new LambdaQueryWrapper<Loc>().eq(Loc::getBarcode, params.get("barcode").toString())); |
| | | if (!Cools.isEmpty(locs)) { |
| | | throw new CoolException("托盘不可用,在库位中已存在"); |
| | | } |
| | | return R.ok("托盘可用"); |
| | | // List<WaitPakinItem> items = waitPakinItemService.list(new LambdaQueryWrapper<WaitPakinItem>().eq(WaitPakinItem::getPakinId, waitPakin.getId())); |
| | | // items.forEach(item -> { |
| | | // FieldsItem fieldsItem = fieldsItemService.getOne(new LambdaQueryWrapper<FieldsItem>().eq(FieldsItem::getUuid, item.getFieldsIndex()).last("limit 1")); |
| | | // if (!Objects.isNull(fieldsItem) && !Objects.isNull(item.getFieldsIndex())) { |
| | | // Map<String, String> fields = FieldsUtils.getFields(item.getFieldsIndex()); |
| | | // item.setExtendFields(fields); |
| | | // } |
| | | // }); |
| | | return R.ok(); |
| | | } |
| | | |
| | | /** |
| | |
| | | if (Cools.isEmpty(params.get("barcode")) && Cools.isEmpty(params.get("code"))) { |
| | | throw new CoolException("容器号与组托档编码不能全为空"); |
| | | } |
| | | //获取组拖未生成任务的组拖档 |
| | | // List<Short> asList = Arrays.asList(Short.valueOf(PakinIOStatus.PAKIN_IO_STATUS_DONE.val), Short.valueOf(PakinIOStatus.PAKIN_IO_STATUS_DONE.val)); |
| | | |
| | | WaitPakin waitPakin = waitPakinService.getOne(new LambdaQueryWrapper<WaitPakin>() |
| | | .eq(!Cools.isEmpty(params.get("barcode")), WaitPakin::getBarcode, params.get("barcode")) |
| | | .eq(!Cools.isEmpty(params.get("code")), WaitPakin::getCode, params.get("code")) |
| | |
| | | if (Objects.isNull(stockItem)) { |
| | | detlsDto.setStockQty(0.0); |
| | | } else { |
| | | Double anfme = Math.round((stockItem.getAnfme() + stockItem.getWorkQty()) * 10000) / 10000.0; |
| | | Double anfme = Math.round((stockItem.getAnfme() + stockItem.getWorkQty()) * 1000000) / 1000000.0; |
| | | detlsDto.setStockQty(anfme); |
| | | } |
| | | |