From 704265308b1227dbada5a36b2027b588c062ded2 Mon Sep 17 00:00:00 2001
From: 云 <2163098428@qq.com>
Date: 星期一, 12 十月 2026 09:14:37 +0800
Subject: [PATCH] feat(mes): 新增业务码支持并优化追溯查询功能
---
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/MesQcSeedQualityServiceImpl.java | 363 +++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 358 insertions(+), 5 deletions(-)
diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/MesQcSeedQualityServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/MesQcSeedQualityServiceImpl.java
index 531c3cf..ada99e6 100644
--- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/MesQcSeedQualityServiceImpl.java
+++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/seedquality/MesQcSeedQualityServiceImpl.java
@@ -1,30 +1,217 @@
package cn.iocoder.yudao.module.mes.service.qc.seedquality;
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
+import cn.iocoder.yudao.framework.common.pojo.PageResult;
+import cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo.MesQcSeedQualityPageReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo.MesQcSeedQualitySubmitReqVO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.pro.bagcode.MesProBagCodeDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.pro.batch.MesProBatchDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.qc.seedquality.*;
+import cn.iocoder.yudao.module.mes.dal.dataobject.wm.batch.MesWmBatchDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstock.MesWmMaterialStockDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseAreaDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseDO;
+import cn.iocoder.yudao.module.mes.dal.dataobject.wm.warehouse.MesWmWarehouseLocationDO;
+import cn.iocoder.yudao.module.mes.dal.mysql.pro.bagcode.MesProBagCodeMapper;
import cn.iocoder.yudao.module.mes.dal.mysql.qc.seedquality.*;
+import cn.iocoder.yudao.module.mes.dal.mysql.wm.batch.MesWmBatchMapper;
+import cn.iocoder.yudao.module.mes.dal.mysql.wm.materialstock.MesWmMaterialStockMapper;
+import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstockbag.MesWmMaterialStockBagDO;
+import cn.iocoder.yudao.module.mes.dal.mysql.wm.materialstockbag.MesWmMaterialStockBagMapper;
+import cn.iocoder.yudao.module.mes.enums.pro.MesProBagCodeQcStatusEnum;
+import cn.iocoder.yudao.module.mes.enums.wm.MesWmStockStateEnum;
+import cn.iocoder.yudao.module.mes.enums.wm.MesWmTransactionTypeEnum;
+import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants;
+import cn.iocoder.yudao.module.mes.enums.wm.MesWmWarehouseTypeEnum;
+import cn.iocoder.yudao.module.mes.service.pro.batch.MesProBatchService;
+import cn.iocoder.yudao.module.mes.service.wm.materialstockbag.MesWmMaterialStockBagService;
+import cn.iocoder.yudao.module.mes.service.wm.transaction.MesWmTransactionService;
+import cn.iocoder.yudao.module.mes.service.wm.transaction.dto.MesWmTransactionSaveReqDTO;
+import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseAreaService;
+import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseLocationService;
+import cn.iocoder.yudao.module.mes.service.wm.warehouse.MesWmWarehouseService;
import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.jdbc.BadSqlGrammarException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
+import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
-@Service @Validated
+import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_QUALIFIED_WAREHOUSE_NOT_CONFIGURED;
+import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_WAREHOUSE_NOT_EXISTS;
+import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.WM_WAREHOUSE_TYPE_NOT_QUALIFIED;
+
+@Service @Validated @Slf4j
public class MesQcSeedQualityServiceImpl implements MesQcSeedQualityService {
private static final Set<String> REQUIRED = Set.of("purity", "cleanliness", "germination_rate", "moisture");
@Resource private MesQcSeedQualityMapper qualityMapper;
@Resource private MesQcSeedQualityIndicatorMapper indicatorMapper;
+ @Resource private MesProBagCodeMapper bagCodeMapper;
+ @Resource private cn.iocoder.yudao.module.mes.dal.mysql.pro.pallet.MesProPalletMapper palletMapper;
+ @Resource private cn.iocoder.yudao.module.mes.dal.mysql.pro.batch.MesProBatchMapper batchMapper;
+ @Resource private MesProBatchService proBatchService;
+ @Resource private MesWmBatchMapper mesWmBatchMapper;
+ @Resource private MesWmMaterialStockMapper materialStockMapper;
+ @Resource private MesWmMaterialStockBagMapper materialStockBagMapper;
+ @Resource private MesWmMaterialStockBagService materialStockBagService;
+ @Resource private MesWmTransactionService wmTransactionService;
+ @Resource private MesWmWarehouseService warehouseService;
+ @Resource private MesWmWarehouseLocationService warehouseLocationService;
+ @Resource private MesWmWarehouseAreaService warehouseAreaService;
+
+ @Override
+ public PageResult<MesQcSeedQualityDO> getQualityPage(MesQcSeedQualityPageReqVO reqVO) {
+ if (StrUtil.isNotBlank(reqVO.getCode())) {
+ MesProBagCodeDO bag = bagCodeMapper.selectByScanCode(reqVO.getCode());
+ if (bag != null) reqVO.setCode(bag.getCode());
+ }
+ return qualityMapper.selectPage(reqVO);
+ }
+
+ @Override
+ public Map<String, Object> resolveScan(String code) {
+ MesProBagCodeDO bag = bagCodeMapper.selectByScanCode(code);
+ if (bag == null) throw new IllegalArgumentException("鏈В鏋愬埌鏈夋晥琚嬬爜锛岃鎵弿琚嬬爜");
+ Map<String, Object> result = new HashMap<>();
+ result.put("code", bag.getCode());
+ result.put("businessCode", bag.getBusinessCode());
+ result.put("batchCode", bag.getBatchCode());
+ result.put("inbound", bag.getInboundEventId() != null);
+ result.put("canceled", Integer.valueOf(30).equals(bag.getStatus()));
+ MesQcSeedQualityDO quality = qualityMapper.selectByCode(bag.getCode());
+ result.put("qualityId", quality == null ? null : quality.getId());
+ result.put("result", quality == null ? null : quality.getResult());
+ return result;
+ }
+
+ private record Scope(String code, String businessCode, String batchCode, boolean canceled, List<MesProBagCodeDO> bags) { }
+
+ private Scope scope(String code, String type, boolean lock) {
+ if ("BAG".equals(type)) {
+ MesProBagCodeDO bag = bagCodeMapper.selectByScanCode(code);
+ if (bag == null) throw new IllegalArgumentException("鏈壘鍒拌鐮侊紝璇锋牳瀵规壂鐮佺被鍨�");
+ return new Scope(bag.getCode(), bag.getBusinessCode(), bag.getBatchCode(), Integer.valueOf(30).equals(bag.getStatus()), List.of(bag));
+ }
+ if ("PALLET".equals(type)) {
+ var pallet = lock ? palletMapper.selectByScanCodeForUpdate(code) : palletMapper.selectByScanCode(code);
+ if (pallet == null) throw new IllegalArgumentException("鏈壘鍒版墭鐩樼爜锛岃鏍稿鎵爜绫诲瀷");
+ if (pallet.getBatchId() == null) throw new IllegalArgumentException("鎵樼洏灏氭湭缁戝畾鐢熶骇鎵规锛屾棤娉曡川妫�");
+ return new Scope(StrUtil.blankToDefault(pallet.getCode(), pallet.getTempCode()), pallet.getBusinessCode(), pallet.getBatchCode(),
+ Integer.valueOf(20).equals(pallet.getStatus()), lock ? bagCodeMapper.selectListByPalletIdForUpdate(pallet.getId()) : bagCodeMapper.selectListByPalletId(pallet.getId()));
+ }
+ if ("BATCH".equals(type)) {
+ var batch = lock ? batchMapper.selectByScanCodeForUpdate(code) : batchMapper.selectByScanCode(code);
+ if (batch == null) throw new IllegalArgumentException("鏈壘鍒扮敓浜ф壒娆$爜锛岃鏍稿鎵爜绫诲瀷");
+ return new Scope(StrUtil.blankToDefault(batch.getCode(), batch.getTempCode()), batch.getBusinessCode(), batch.getCode(),
+ Integer.valueOf(40).equals(batch.getStatus()), lock ? bagCodeMapper.selectListByBatchIdForUpdate(batch.getId()) : bagCodeMapper.selectListByBatchId(batch.getId()));
+ }
+ throw new IllegalArgumentException("涓嶆敮鎸佺殑璐ㄦ鎵爜绫诲瀷");
+ }
+
+ @Override
+ public Map<String, Object> resolveScan(String code, String scanType) {
+ Scope scope = scope(code, scanType, false);
+ List<MesProBagCodeDO> effective = scope.bags().stream().filter(b -> !Integer.valueOf(30).equals(b.getStatus())).toList();
+ Set<String> inspected = qualityMapper.selectListByCodes(effective.stream().map(MesProBagCodeDO::getCode).toList()).stream()
+ .map(MesQcSeedQualityDO::getCode).collect(java.util.stream.Collectors.toSet());
+ Map<String, Object> result = new HashMap<>();
+ result.put("scanType", scanType); result.put("code", scope.code()); result.put("businessCode", scope.businessCode());
+ result.put("batchCode", scope.batchCode()); result.put("canceled", scope.canceled());
+ result.put("totalCount", effective.size());
+ result.put("inbound", !effective.isEmpty() && effective.stream().allMatch(b -> b.getInboundEventId() != null));
+ result.put("pendingBagIds", effective.stream().filter(b -> b.getInboundEventId() != null && !inspected.contains(b.getCode())).map(MesProBagCodeDO::getId).sorted().toList());
+ result.put("completedBagIds", effective.stream().filter(b -> inspected.contains(b.getCode())).map(MesProBagCodeDO::getId).sorted().toList());
+ if ("BAG".equals(scanType)) {
+ MesQcSeedQualityDO quality = qualityMapper.selectByCode(scope.code());
+ result.put("qualityId", quality == null ? null : quality.getId()); result.put("result", quality == null ? null : quality.getResult());
+ }
+ return result;
+ }
+
+ @Override @Transactional(rollbackFor = Exception.class)
+ public Map<String, Object> submitGroup(cn.iocoder.yudao.module.mes.controller.admin.qc.seedquality.vo.MesQcSeedQualityGroupSubmitReqVO req) {
+ Scope scope = scope(req.getCode(), req.getScanType(), true);
+ if (scope.canceled()) throw new IllegalArgumentException("璐ㄦ瀵硅薄宸蹭綔搴�");
+ List<MesProBagCodeDO> effective = scope.bags().stream().filter(b -> !Integer.valueOf(30).equals(b.getStatus())).toList();
+ if (effective.isEmpty()) throw new IllegalArgumentException("娌℃湁鏈夋晥琚嬬爜");
+ List<MesProBagCodeDO> locked = bagCodeMapper.selectListByIdsForUpdate(effective.stream().map(MesProBagCodeDO::getId).toList());
+ if (locked.size() != effective.size() || locked.stream().anyMatch(b -> Integer.valueOf(30).equals(b.getStatus()) || b.getInboundEventId() == null))
+ throw new IllegalArgumentException("琚嬬爜宸插彉鍖栨垨灏氭湭鍏ㄩ儴鍏ュ簱锛岃閲嶆柊鎵弿鏍稿");
+ // 鍦ㄨ鐮侀攣涔嬪悗閲嶆柊鏍稿褰掑睘锛涘叾浠栫粦瀹氭搷浣滀笉寰楁敼鍙樺凡纭鐨勬楠岃寖鍥淬��
+ Scope current = scope(req.getCode(), req.getScanType(), false);
+ Set<Long> currentIds = current.bags().stream().filter(b -> !Integer.valueOf(30).equals(b.getStatus())).map(MesProBagCodeDO::getId).collect(java.util.stream.Collectors.toSet());
+ if (!currentIds.equals(new HashSet<>(locked.stream().map(MesProBagCodeDO::getId).toList())))
+ throw new IllegalArgumentException("琚嬬爜褰掑睘宸插彉鍖栵紝璇烽噸鏂版壂鎻忔牳瀵�");
+ Set<String> inspected = qualityMapper.selectListByCodesForUpdate(locked.stream().map(MesProBagCodeDO::getCode).toList()).stream()
+ .map(MesQcSeedQualityDO::getCode).collect(java.util.stream.Collectors.toSet());
+ List<MesProBagCodeDO> pending = locked.stream().filter(b -> !inspected.contains(b.getCode())).sorted(Comparator.comparing(MesProBagCodeDO::getId)).toList();
+ List<Long> confirmed = req.getBagIds().stream().sorted().toList();
+ if (pending.isEmpty() || !confirmed.equals(pending.stream().map(MesProBagCodeDO::getId).toList()))
+ throw new IllegalArgumentException("寰呰川妫�娓呭崟宸插彉鍖栨垨宸插叏閮ㄨ川妫�锛岃閲嶆柊鎵弿锛岀姝㈤噸澶嶅鐞�");
+ for (MesProBagCodeDO bag : pending) {
+ MesQcSeedQualitySubmitReqVO single = new MesQcSeedQualitySubmitReqVO();
+ single.setCode(bag.getCode());single.setIndicators(req.getIndicators());single.setReason(req.getReason());
+ single.setQualifiedWarehouseId(req.getQualifiedWarehouseId());
+ // 澶栧眰浜嬪姟瑕嗙洊鍏ㄩ儴琚嬬爜锛涗换浣曚竴琚嬪簱瀛樻祦杞け璐ラ兘浼氬洖婊氭暣娆℃搷浣溿��
+ submit(single);
+ }
+ return Map.of("processedCount", pending.size());
+ }
@Override @Transactional(rollbackFor = Exception.class)
public Long submit(MesQcSeedQualitySubmitReqVO reqVO) {
if (reqVO.getIndicators().size() != 4) throw new IllegalArgumentException("蹇呴』鎻愪氦鍥涢」鎸囨爣");
- if (qualityMapper.selectByCode(reqVO.getCode()) != null) throw new IllegalArgumentException("璇ヨ鐮佸凡璐ㄦ锛岀姝㈤噸澶嶆彁浜�");
+ // 绉嶅瓙璐ㄦ蹇呴』浠ヨ鐮侊紙鍗曡锛夋彁浜わ紝鐗╂枡淇℃伅鐢辫鐮佽嚜鍔ㄨВ鏋愶紝鍓嶇涓嶅啀鍗曠嫭閫夋嫨鐗╂枡
+ MesProBagCodeDO bag = bagCodeMapper.selectByScanCodeForUpdate(reqVO.getCode());
+ if (bag == null) {
+ throw new IllegalArgumentException("鏈В鏋愬埌鏈夋晥琚嬬爜锛岀瀛愯川妫�蹇呴』浠ヨ鐮佹彁浜�");
+ }
+ if (Integer.valueOf(30).equals(bag.getStatus()) || bag.getInboundEventId() == null)
+ throw new IllegalArgumentException("琚嬬爜宸蹭綔搴熸垨灏氭湭鍏ュ簱锛屾棤娉曡川妫�");
+ // 鍙岀爜閿佸畾鍚屼竴琚嬶紝骞朵互杩芥函鐮佽褰曠粨鏋滐紝闃叉鎹㈢爜鎴栧苟鍙戦噸澶嶆墸鍑忓簱瀛樸��
+ if (qualityMapper.selectByCodeForUpdate(bag.getCode()) != null) throw new IllegalArgumentException("璇ヨ鐮佸凡璐ㄦ锛岀姝㈤噸澶嶆彁浜�");
+ MesProBatchDO batch = bag.getBatchId() == null ? null : proBatchService.getBatch(bag.getBatchId());
+ if (batch == null || batch.getItemId() == null) {
+ throw new IllegalArgumentException("鏈牴鎹鐮佽В鏋愬埌鐗╂枡淇℃伅锛岃纭鎵爜鍐呭鎴栨壒娆″彿姝g‘");
+ }
+ if (Integer.valueOf(40).equals(batch.getStatus())) throw new IllegalArgumentException("鐢熶骇鎵规宸蹭綔搴燂紝鏃犳硶璐ㄦ");
+ // 琚嬬爜瀵瑰簲鎵规鐨勫簱瀛樺繀椤诲浜庢殏瀛樺簱锛堝緟璐ㄦ锛変腑锛屾墠鑳借繘琛岀瀛愯川妫�
+ MesWmBatchDO wmBatch = mesWmBatchMapper.selectByCode(batch.getCode());
+ if (wmBatch == null || materialStockMapper.selectTempStockCountByBatchId(wmBatch.getId()) == 0) {
+ throw new IllegalArgumentException("璇ヨ鐮�/鎵规瀵瑰簲鐨勫簱瀛樹笉鍦ㄦ殏瀛樺簱涓紝鏃犳硶杩涜璐ㄦ");
+ }
+ // 鏍¢獙鐩爣鍚堟牸搴擄細蹇呴』瀛樺湪涓斾粨搴撶被鍨嬩负鍚堟牸搴�(20)
+ if (warehouseService.getFirstQualifiedWarehouse() == null) {
+ throw exception(WM_QUALIFIED_WAREHOUSE_NOT_CONFIGURED);
+ }
+ MesWmWarehouseDO qualifiedWarehouse = warehouseService.getWarehouse(reqVO.getQualifiedWarehouseId());
+ if (qualifiedWarehouse == null) {
+ throw exception(WM_WAREHOUSE_NOT_EXISTS);
+ }
+ if (!MesWmWarehouseTypeEnum.QUALIFIED.getType().equals(qualifiedWarehouse.getType())) {
+ throw exception(WM_WAREHOUSE_TYPE_NOT_QUALIFIED);
+ }
+ // 瑙f瀽鍚堟牸搴撻粯璁ゅ簱鍖�/搴撲綅锛堝彇璇ヤ粨搴撲笅绗竴涓簱鍖恒�佸叾涓嬬涓�涓簱浣嶏紝鏈厤缃垯涓� null锛�
+ Long qualifiedLocationId = null;
+ Long qualifiedAreaId = null;
+ List<MesWmWarehouseLocationDO> locations = warehouseLocationService.getWarehouseLocationList(qualifiedWarehouse.getId());
+ if (CollUtil.isNotEmpty(locations)) {
+ qualifiedLocationId = locations.get(0).getId();
+ List<MesWmWarehouseAreaDO> areas = warehouseAreaService.getWarehouseAreaList(qualifiedLocationId);
+ if (CollUtil.isNotEmpty(areas)) {
+ qualifiedAreaId = areas.get(0).getId();
+ }
+ }
Set<String> codes = new HashSet<>();
boolean passed = true;
- MesQcSeedQualityDO quality = MesQcSeedQualityDO.builder().code(reqVO.getCode()).itemId(reqVO.getItemId())
- .batchCode(reqVO.getBatchCode()).reason(reqVO.getReason()).result(0)
+ MesQcSeedQualityDO quality = MesQcSeedQualityDO.builder().code(bag.getCode()).itemId(batch.getItemId())
+ .batchCode(batch.getCode()).reason(reqVO.getReason()).result(0)
.inspectedAt(LocalDateTime.now()).build();
qualityMapper.insert(quality);
for (MesQcSeedQualitySubmitReqVO.Indicator item : reqVO.getIndicators()) {
@@ -34,9 +221,175 @@
.value(item.getValue()).minValue(item.getMinValue()).maxValue(item.getMaxValue()).build());
}
if (!codes.equals(REQUIRED)) throw new IllegalArgumentException("鍥涢」鎸囨爣涓嶅畬鏁�");
+ if (!passed && StrUtil.isBlank(reqVO.getReason())) throw new IllegalArgumentException("璐ㄦ涓嶅悎鏍煎繀椤诲~鍐欏師鍥�");
quality.setResult(passed ? 1 : 2);
qualityMapper.updateById(quality);
- // 搴撲綅鐢卞悗鍙伴厤缃湇鍔℃帴绠★紝褰撳墠鐗堟湰淇濈暀瀹¤闂幆锛岀姝㈠墠绔紶鍏ュ簱浣嶃��
+ // 鎸夎鐮佺矑搴︽祦杞簱瀛橈細閿佸畾璇ヨ鍦ㄦ殏瀛樺簱涓殑娲诲姩鏄庣粏锛岀姝㈡寜鎵规浠绘剰鎵e噺
+ MesWmMaterialStockBagDO stockBag = materialStockBagMapper.selectActiveByBagCode(bag.getCode());
+ MesWmMaterialStockDO tempStock = resolveTempStock(bag, wmBatch, stockBag);
+ // A. 鏆傚瓨鍑哄簱锛�-1锛夛細璇ヨ绂诲紑鏆傚瓨搴擄紝鍐欏叆璐ㄦ鏆傚瓨鍑哄簱浜嬪姟锛堣烦杩囪鐮佽嚜鍔ㄧ淮鎶わ紝鐢辫川妫�缁熶竴鎺у埗琚嬬爜鏈�缁堣惤鐐癸級
+ MesWmTransactionSaveReqDTO tempOutReq = new MesWmTransactionSaveReqDTO()
+ .setType(MesWmTransactionTypeEnum.OUT.getType())
+ .setBizType(MesBizTypeConstants.QC_SEED_QUALITY)
+ .setBizId(quality.getId())
+ .setBizCode(reqVO.getCode())
+ .setBizLineId(quality.getId())
+ .setItemId(batch.getItemId())
+ .setQuantity(BigDecimal.ONE.negate())
+ .setBatchId(tempStock.getBatchId())
+ .setBatchCode(tempStock.getBatchCode())
+ .setBagCodeId(bag.getId())
+ .setBagCode(bag.getCode())
+ .setWarehouseId(tempStock.getWarehouseId())
+ .setLocationId(tempStock.getLocationId())
+ .setAreaId(tempStock.getAreaId())
+ .setVendorId(tempStock.getVendorId())
+ .setMaterialStockId(tempStock.getId())
+ .setCheckFlag(true)
+ .setSkipBagManage(true);
+ Long tempOutTxId = wmTransactionService.createTransaction(tempOutReq);
+ if (passed) {
+ // B1. 璐ㄦ鍚堟牸 鈫� 璇ヨ杞叆鎿嶄綔鍛橀�夋嫨鐨勫悎鏍煎簱锛屽啓鍏ュ悎鏍煎叆搴撲簨鍔★紙璺宠繃琚嬬爜鑷姩缁存姢锛�
+ MesWmMaterialStockDO qualifiedStock = getOrCreateQualifiedStock(tempStock, qualifiedWarehouse.getId(), qualifiedLocationId, qualifiedAreaId);
+ MesWmTransactionSaveReqDTO qualInReq = new MesWmTransactionSaveReqDTO()
+ .setType(MesWmTransactionTypeEnum.IN.getType())
+ .setBizType(MesBizTypeConstants.QC_SEED_QUALITY)
+ .setBizId(quality.getId())
+ .setBizCode(reqVO.getCode())
+ .setBizLineId(quality.getId())
+ .setItemId(batch.getItemId())
+ .setQuantity(BigDecimal.ONE)
+ .setBatchId(qualifiedStock.getBatchId())
+ .setBatchCode(qualifiedStock.getBatchCode())
+ .setBagCodeId(bag.getId())
+ .setBagCode(bag.getCode())
+ .setWarehouseId(qualifiedStock.getWarehouseId())
+ .setLocationId(qualifiedStock.getLocationId())
+ .setAreaId(qualifiedStock.getAreaId())
+ .setVendorId(qualifiedStock.getVendorId())
+ .setMaterialStockId(qualifiedStock.getId())
+ .setCheckFlag(false)
+ .setStockState(MesWmStockStateEnum.QUALIFIED.getState())
+ .setSkipBagManage(true);
+ Long qualInTxId = wmTransactionService.createTransaction(qualInReq);
+ // B2. 鍚屾杩佺Щ琚嬬爜鏄庣粏鍒板悎鏍煎簱瀛樿惤鐐�
+ materialStockBagService.moveIn(qualInReq, qualifiedStock, qualInTxId);
+ bagCodeMapper.updateQcStatus(bag.getId(), MesProBagCodeQcStatusEnum.QUALIFIED.getStatus());
+ log.info("[submit][璐ㄦ鍚堟牸锛岃鐮� {} 鐢辨殏瀛樺簱杞悎鏍煎簱 {}]", bag.getCode(), qualifiedWarehouse.getName());
+ } else {
+ // C. 璐ㄦ涓嶅悎鏍� 鈫� 璇ヨ鎶ュ簾锛涙殏瀛樺嚭搴撲簨鍔″凡鎵e噺鏆傚瓨搴撳瓨锛屾爣璁拌鐮佹姤搴�
+ materialStockBagService.scrap(tempOutReq, tempOutTxId);
+ bagCodeMapper.updateQcStatus(bag.getId(), MesProBagCodeQcStatusEnum.UNQUALIFIED.getStatus());
+ log.info("[submit][璐ㄦ涓嶅悎鏍硷紝琚嬬爜 {} 鎶ュ簾]", bag.getCode());
+ }
return quality.getId();
}
+
+ /**
+ * 瀹氫綅璇ヨ鐨勬殏瀛樺簱瀛樻眹鎬昏褰曪紙鍙畾浣嶏紝涓嶆墸鍑忥紱鎵e噺鐢辫川妫�鏆傚瓨鍑哄簱浜嬪姟瀹屾垚锛夈��
+ * <p>
+ * 浼樺厛涓ユ牸鎸夎鐮侀攣瀹氬叾娲诲姩鏄庣粏瀵瑰簲鐨勬殏瀛樿褰曪紱鍘嗗彶鏃犳槑缁嗘椂鍥為��鎸夋壒娆″畾浣嶅苟琛ュ缓鏄庣粏銆�
+ */
+ private MesWmMaterialStockDO resolveTempStock(MesProBagCodeDO bag, MesWmBatchDO wmBatch, MesWmMaterialStockBagDO stockBag) {
+ if (stockBag != null && stockBag.getMaterialStockId() != null) {
+ MesWmMaterialStockDO stock = materialStockMapper.selectById(stockBag.getMaterialStockId());
+ if (stock != null && MesWmStockStateEnum.TEMP.getState().equals(stock.getStockState())) {
+ return stock;
+ }
+ }
+ MesWmMaterialStockDO tempStock = materialStockMapper.selectStockListByBatchId(wmBatch.getId()).stream()
+ .filter(s -> MesWmStockStateEnum.TEMP.getState().equals(s.getStockState()))
+ .max(Comparator.comparing(MesWmMaterialStockDO::getQuantity))
+ .orElse(null);
+ if (tempStock == null) {
+ throw new IllegalArgumentException("璇ユ壒娆℃殏瀛樺簱瀛樹笉瓒筹紝鏃犳硶璐ㄦ");
+ }
+ getOrCreateStockBag(bag, tempStock);
+ return tempStock;
+ }
+
+ /**
+ * 璐ㄦ鍚堟牸锛氬皢璐ㄦ閫氳繃鐨勯偅琚嬭浆鍏ユ搷浣滃憳閫夋嫨鐨勫悎鏍煎簱锛堝悓缁勫悎閿悎鏍煎簱璁板綍 +1锛屼笉瀛樺湪鍒欐柊寤猴級銆�
+ *
+ * @param tempStock 浠庢殏瀛樺簱鎵e噺鍚庤繑鍥炵殑鏆傚瓨璁板綍锛堟惡甯� item/batch/vendor 缁村害锛�
+ * @param qualifiedWarehouseId 鐩爣鍚堟牸搴撲粨搴撶紪鍙�
+ * @param qualifiedLocationId 鐩爣鍚堟牸搴撳簱鍖虹紪鍙凤紙鏈厤缃垯涓� null锛�
+ * @param qualifiedAreaId 鐩爣鍚堟牸搴撳簱浣嶇紪鍙凤紙鏈厤缃垯涓� null锛�
+ */
+ private MesWmMaterialStockBagDO getOrCreateStockBag(MesProBagCodeDO bag, MesWmMaterialStockDO tempStock) {
+ MesWmMaterialStockBagDO stockBag = materialStockBagMapper.selectByBagCode(bag.getCode());
+ if (stockBag != null) {
+ return stockBag;
+ }
+ stockBag = MesWmMaterialStockBagDO.builder().materialStockId(tempStock.getId())
+ .bagCodeId(bag.getId()).bagCode(bag.getCode()).itemId(tempStock.getItemId())
+ .batchId(tempStock.getBatchId()).batchCode(tempStock.getBatchCode()).vendorId(tempStock.getVendorId())
+ .warehouseId(tempStock.getWarehouseId()).locationId(tempStock.getLocationId()).areaId(tempStock.getAreaId())
+ .stockState(MesWmStockStateEnum.TEMP.getState()).status(1).quantity(BigDecimal.ONE)
+ .frozen(false).inboundTime(tempStock.getReceiptTime()).build();
+ materialStockBagMapper.insert(stockBag);
+ return stockBag;
+ }
+
+ private MesWmMaterialStockDO getOrCreateQualifiedStock(MesWmMaterialStockDO tempStock, Long qualifiedWarehouseId,
+ Long qualifiedLocationId, Long qualifiedAreaId) {
+ MesWmMaterialStockDO qualified = materialStockMapper.selectQualifiedByCompositeKey(
+ tempStock.getItemId(), qualifiedWarehouseId, qualifiedLocationId,
+ qualifiedAreaId, tempStock.getBatchId(), tempStock.getVendorId());
+ if (qualified != null) {
+ return qualified;
+ }
+ // 涓嶅瓨鍦ㄥ垯鏂板缓鍚堟牸搴撹褰曪紙浠撳簱/搴撳尯/搴撲綅閲囩敤鎵�閫夊悎鏍煎簱鐨勭淮搴︼紝鏁伴噺鐢辫川妫�鍏ュ簱浜嬪姟 +1锛�
+ MesWmMaterialStockDO newStock = MesWmMaterialStockDO.builder()
+ .itemId(tempStock.getItemId()).itemTypeId(tempStock.getItemTypeId())
+ .warehouseId(qualifiedWarehouseId).locationId(qualifiedLocationId).areaId(qualifiedAreaId)
+ .batchId(tempStock.getBatchId()).batchCode(tempStock.getBatchCode()).vendorId(tempStock.getVendorId())
+ .quantity(BigDecimal.ZERO).receiptTime(LocalDateTime.now())
+ .stockState(MesWmStockStateEnum.QUALIFIED.getState())
+ .frozen(false)
+ .build();
+ materialStockMapper.insert(newStock);
+ return newStock;
+ }
+
+ /**
+ * 鐢辫鐮佹垨鐢熶骇鎵规瑙f瀽鎵�灞炵敓浜ф壒娆★紙琚嬬爜浼樺厛锛屾壒娆$爜鍏煎涓存椂鐮侊級
+ */
+ private MesProBatchDO resolveBatch(String code, String batchCode) {
+ if (StrUtil.isNotBlank(code)) {
+ MesProBagCodeDO bag = bagCodeMapper.selectByCode(code);
+ if (bag != null && bag.getBatchId() != null) {
+ MesProBatchDO batch = proBatchService.getBatch(bag.getBatchId());
+ if (batch != null) {
+ return batch;
+ }
+ }
+ }
+ if (StrUtil.isNotBlank(batchCode)) {
+ return proBatchService.getBatchByCode(batchCode);
+ }
+ return null;
+ }
+
+ @Override
+ public List<MesQcSeedQualityDO> getQualityByBatchCode(String batchCode) {
+ try {
+ return qualityMapper.selectListByBatchCode(batchCode);
+ } catch (BadSqlGrammarException ex) {
+ // 绉嶅瓙璐ㄦ琛ㄦ湭鍒濆鍖栨椂瀹归敊锛屼笉闃诲鍏紑婧簮
+ log.warn("[getQualityByBatchCode][绉嶅瓙璐ㄦ琛ㄦ湭鍒濆鍖栵紝鎵规 {} 鏌ヨ澶辫触: {}]", batchCode, ex.getMessage());
+ return List.of();
+ }
+ }
+
+ @Override
+ public List<MesQcSeedQualityIndicatorDO> getIndicatorsByQualityId(Long qualityId) {
+ try {
+ return indicatorMapper.selectListByQualityId(qualityId);
+ } catch (BadSqlGrammarException ex) {
+ // 绉嶅瓙璐ㄦ琛ㄦ湭鍒濆鍖栨椂瀹归敊
+ log.warn("[getIndicatorsByQualityId][绉嶅瓙璐ㄦ鎸囨爣琛ㄦ湭鍒濆鍖栵紝璐ㄦ {} 鏌ヨ澶辫触: {}]", qualityId, ex.getMessage());
+ return List.of();
+ }
+ }
}
--
Gitblit v1.9.3