package cn.iocoder.yudao.module.mes.service.pro.bagcode; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.StrUtil; import cn.iocoder.yudao.framework.common.pojo.CommonResult; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.module.mdm.api.unit.MdmUnitMeasureApi; import cn.iocoder.yudao.module.mdm.api.unit.dto.MdmUnitMeasureRespDTO; import cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo.MesProBagCodeBindBatchReqVO; import cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo.MesProBagCodeBindReqVO; import cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo.MesProBagCodeGenerateReqVO; import cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo.MesProBagCodeGenerateRespVO; import cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo.MesProBagCodePageReqVO; import cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo.MesProBagCodeRawGenerateReqVO; import cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo.MesProBagCodeReplaceItemRespVO; import cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo.MesProBagCodeReplaceReqVO; import cn.iocoder.yudao.module.mes.controller.admin.pro.bagcode.vo.MesProBagCodeReplaceRespVO; import cn.iocoder.yudao.module.mes.dal.dataobject.mdm.MesMdmItemDO; import cn.iocoder.yudao.module.mes.dal.dataobject.pro.bagcode.MesProBagCodeDO; import cn.iocoder.yudao.module.mes.dal.dataobject.pro.bagcode.MesProBagCodeReplaceDO; import cn.iocoder.yudao.module.mes.dal.dataobject.pro.batch.MesProBatchDO; import cn.iocoder.yudao.module.mes.dal.dataobject.pro.pallet.MesProPalletDO; import cn.iocoder.yudao.module.mes.dal.mysql.pro.bagcode.MesProBagCodeMapper; import cn.iocoder.yudao.module.mes.dal.mysql.pro.bagcode.MesProBagCodeReplaceMapper; import cn.iocoder.yudao.module.mes.dal.mysql.pro.batch.MesProBatchMapper; import cn.iocoder.yudao.module.mes.dal.mysql.pro.pallet.MesProPalletMapper; import cn.iocoder.yudao.module.mes.enums.pro.MesProBagCodeStatusEnum; import cn.iocoder.yudao.module.mes.enums.pro.MesProBatchStatusEnum; import cn.iocoder.yudao.module.mes.enums.pro.MesProPalletStatusEnum; import cn.iocoder.yudao.module.mes.service.mdm.MesMdmItemService; import cn.iocoder.yudao.module.mes.service.pro.pallet.MesProPalletService; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.validation.annotation.Validated; import java.time.LocalDateTime; import java.util.ArrayList; import java.util.Collection; import java.util.LinkedHashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.regex.Matcher; import java.util.regex.Pattern; import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; import static cn.iocoder.yudao.module.mes.enums.ErrorCodeConstants.*; /** * MES 袋码赋码(一袋一码)Service 实现类 * * @author 超级管理员 */ @Service @Validated @Slf4j public class MesProBagCodeServiceImpl implements MesProBagCodeService { @Resource private MesProBagCodeMapper bagCodeMapper; @Resource private MesProBatchMapper batchMapper; @Resource private MesProBagCodeReplaceMapper replaceMapper; @Resource private MesProPalletMapper palletMapper; @Resource private MesProPalletService palletService; @Resource private MesMdmItemService mdmItemService; @Resource private MdmUnitMeasureApi unitMeasureApi; /** * 计量单位类型「吨」(无托盘模式) */ private static final String UNIT_TYPE_TON = "吨"; /** * 计量单位类型「N千克」:每托盘装 N 个袋码 */ private static final Pattern KG_TYPE_PATTERN = Pattern.compile("^(\\d{1,5})千克$"); @Override @Transactional(rollbackFor = Exception.class) public MesProBagCodeGenerateRespVO generateBagCodes(MesProBagCodeGenerateReqVO generateReqVO) { // 1. 校验品种并读取主计量单位类型 MesMdmItemDO item = mdmItemService.validateItemExists(generateReqVO.getItemId()); String type = getUnitType(item); // 2. 按类型换算袋码数量:N千克 = 每托 N 袋 × 托盘数;吨 = 直接输入袋码数(无托盘) boolean ton = UNIT_TYPE_TON.equals(type); int perPallet = ton ? 0 : parseKgPerPallet(type); int totalCount; int palletCount = 0; if (ton) { if (generateReqVO.getBagCount() == null || generateReqVO.getBagCount() <= 0) { throw exception(PRO_BAG_CODE_GENERATE_COUNT_INVALID); } totalCount = generateReqVO.getBagCount(); } else { if (generateReqVO.getPalletCount() == null || generateReqVO.getPalletCount() <= 0) { throw exception(PRO_BAG_CODE_PALLET_COUNT_REQUIRED); } palletCount = generateReqVO.getPalletCount(); totalCount = perPallet * palletCount; } // 3. 生成阶段:袋码直接绑定品种;生产批次在后续录入 String uuid = IdUtil.fastSimpleUUID(); List pallets = new ArrayList<>(palletCount); if (!ton) { int startSeq = palletMapper.selectMaxTempCodeSeq() + 1; for (int i = 0; i < palletCount; i++) { pallets.add(new MesProPalletDO() .setTempCode("PL-" + StrUtil.padPre(String.valueOf(startSeq + i), 8, '0')) .setBagCount(perPallet) .setAutoGenerated(true) .setStatus(MesProPalletStatusEnum.IN_USE.getStatus())); } palletMapper.insertBatch(pallets); } int startNo = bagCodeMapper.selectMaxBagNo() + 1; List bagCodes = new ArrayList<>(totalCount); for (int i = 0; i < totalCount; i++) { int bagNo = startNo + i; MesProPalletDO pallet = ton ? null : pallets.get(i / perPallet); bagCodes.add(new MesProBagCodeDO() .setUuid(uuid) .setCode("BAG-" + StrUtil.padPre(String.valueOf(bagNo), 8, '0')) .setBagNo(bagNo) .setItemId(item.getId()) .setItemCode(item.getCode()) .setItemName(item.getName()) .setPalletId(pallet == null ? null : pallet.getId()) .setPalletCode(pallet == null ? null : pallet.getTempCode()) .setStatus(MesProBagCodeStatusEnum.GENERATED.getStatus()) .setRemark(generateReqVO.getRemark())); } bagCodeMapper.insertBatch(bagCodes); return new MesProBagCodeGenerateRespVO() .setUuid(uuid) .setType(type) .setPerPallet(perPallet) .setTotalCount(totalCount) .setPalletIds(pallets.stream().map(MesProPalletDO::getId).toList()); } @Override @Transactional(rollbackFor = Exception.class) public MesProBagCodeGenerateRespVO generateRawBagCodes(MesProBagCodeRawGenerateReqVO generateReqVO) { // 原始袋码不依赖计量单位类型与托盘:仅按数量生成,袋码带品种冗余,后续可正常录入批次/绑定托盘 MesMdmItemDO item = mdmItemService.validateItemExists(generateReqVO.getItemId()); String uuid = IdUtil.fastSimpleUUID(); int startNo = bagCodeMapper.selectMaxBagNo() + 1; List bagCodes = new ArrayList<>(generateReqVO.getCount()); for (int i = 0; i < generateReqVO.getCount(); i++) { int bagNo = startNo + i; bagCodes.add(new MesProBagCodeDO() .setUuid(uuid) .setCode("BAG-" + StrUtil.padPre(String.valueOf(bagNo), 8, '0')) .setBagNo(bagNo) .setItemId(item.getId()) .setItemCode(item.getCode()) .setItemName(item.getName()) .setStatus(MesProBagCodeStatusEnum.GENERATED.getStatus()) .setRemark(generateReqVO.getRemark())); } bagCodeMapper.insertBatch(bagCodes); return new MesProBagCodeGenerateRespVO() .setUuid(uuid) .setTotalCount(bagCodes.size()) .setPalletIds(List.of()); } /** * 读取品种主计量单位的类型(48千克/100千克/吨),未配置或无法识别时报错 */ private String getUnitType(MesMdmItemDO item) { String type = null; if (item.getUnitMeasureId() != null) { CommonResult result = unitMeasureApi.getUnitMeasure(item.getUnitMeasureId()); if (result != null && result.isSuccess() && result.getData() != null) { type = StrUtil.trimToNull(result.getData().getType()); } } if (type == null) { throw exception(PRO_BAG_CODE_ITEM_TYPE_NOT_CONFIGURED); } if (!UNIT_TYPE_TON.equals(type) && !KG_TYPE_PATTERN.matcher(type).matches()) { throw exception(PRO_BAG_CODE_ITEM_TYPE_NOT_CONFIGURED); } return type; } /** * 解析「N千克」类型得出每托盘袋数 */ private int parseKgPerPallet(String type) { Matcher matcher = KG_TYPE_PATTERN.matcher(type); if (!matcher.matches()) { throw exception(PRO_BAG_CODE_ITEM_TYPE_NOT_CONFIGURED); } return Integer.parseInt(matcher.group(1)); } @Override @Transactional(rollbackFor = Exception.class) public void bindBatch(MesProBagCodeBindBatchReqVO bindReqVO) { MesProBatchDO batch = batchMapper.selectByIdForUpdate(bindReqVO.getBatchId()); if (batch == null) { throw exception(PRO_BATCH_NOT_EXISTS); } if (!MesProBatchStatusEnum.PRODUCING.getStatus().equals(batch.getStatus())) { throw exception(PRO_BATCH_STATUS_NOT_GENERATE_CODE); } // 临时批次(未补录正式批次号)不允许袋码录入 if (StrUtil.isEmpty(batch.getCode())) { throw exception(PRO_BATCH_NOT_FILLED); } List ids = bindReqVO.getIds().stream().distinct().toList(); List bagCodes = bagCodeMapper.selectListByIdsForUpdate(ids); if (bagCodes.size() != ids.size() || bagCodes.stream().anyMatch(code -> code.getBatchId() != null || (!MesProBagCodeStatusEnum.GENERATED.getStatus().equals(code.getStatus()) && !MesProBagCodeStatusEnum.PRINTED.getStatus().equals(code.getStatus())))) { throw exception(PRO_BAG_CODE_STATUS_NOT_GENERATED); } // 录入的袋码必须属于同一品种,且与批次已有袋码品种一致(历史空白袋码 item 为空不参与校验) Set itemIds = new LinkedHashSet<>(); bagCodes.stream().map(MesProBagCodeDO::getItemId).filter(Objects::nonNull).forEach(itemIds::add); itemIds.addAll(bagCodeMapper.selectDistinctItemIdsByBatchId(batch.getId())); if (itemIds.size() > 1) { throw exception(PRO_BAG_CODE_BIND_BATCH_ITEM_MISMATCH); } if (bagCodeMapper.bindBatchByIds(ids, batch.getId(), batch.getCode(), List.of(MesProBagCodeStatusEnum.GENERATED.getStatus(), MesProBagCodeStatusEnum.PRINTED.getStatus())) != ids.size()) { throw exception(PRO_BAG_CODE_STATUS_NOT_GENERATED); } batchMapper.updateById(new MesProBatchDO().setId(batch.getId()) .setBagQuantity(bagCodeMapper.selectEffectiveCountByBatchId(batch.getId()))); // 级联:本组袋码绑定的未入批次托盘,分配正式托盘码并绑定批次 bindPalletsToBatch(bagCodes, batch); } /** * 袋码录入批次时,将其绑定的临时托盘(未绑定批次)级联绑定到同一批次: * 分配正式托盘码(批次号-P序号)、回写袋码上的冗余托盘码、累计批次托盘数 */ private void bindPalletsToBatch(List bagCodes, MesProBatchDO batch) { List palletIds = bagCodes.stream().map(MesProBagCodeDO::getPalletId) .filter(Objects::nonNull).distinct().sorted().toList(); if (palletIds.isEmpty()) { return; } int nextPalletNo = palletMapper.selectMaxPalletNo(batch.getId()) + 1; int boundCount = 0; for (Long palletId : palletIds) { MesProPalletDO pallet = palletMapper.selectByIdForUpdate(palletId); if (pallet == null || pallet.getBatchId() != null || StrUtil.isNotEmpty(pallet.getCode())) { continue; } String palletCode = batch.getCode() + "-P" + StrUtil.padPre(String.valueOf(nextPalletNo++), 2, '0'); palletMapper.updateById(new MesProPalletDO().setId(palletId) .setCode(palletCode) .setBatchId(batch.getId()) .setBatchCode(batch.getCode()) .setPalletNo(nextPalletNo - 1)); // 袋码上的冗余托盘码由临时码更新为正式码 bagCodeMapper.updatePalletCodeByPalletId(palletId, palletCode); boundCount++; } if (boundCount > 0) { batchMapper.updateById(new MesProBatchDO().setId(batch.getId()) .setPalletQuantity((batch.getPalletQuantity() == null ? 0 : batch.getPalletQuantity()) + boundCount)); } } @Override @Transactional(rollbackFor = Exception.class) public MesProBagCodeReplaceRespVO replaceBagCodes(MesProBagCodeReplaceReqVO replaceReqVO) { MesProBatchDO batch = batchMapper.selectByIdForUpdate(replaceReqVO.getBatchId()); if (batch == null) { throw exception(PRO_BATCH_NOT_EXISTS); } if (!MesProBatchStatusEnum.PRODUCING.getStatus().equals(batch.getStatus()) && !MesProBatchStatusEnum.FINISHED.getStatus().equals(batch.getStatus())) { throw exception(PRO_BAG_CODE_REPLACE_BATCH_STATUS_INVALID); } List oldIds = replaceReqVO.getOldIds().stream() .distinct().sorted().toList(); List oldBagCodes = bagCodeMapper.selectListByIdsForUpdate(oldIds); if (oldBagCodes.size() != oldIds.size()) { throw exception(PRO_BAG_CODE_NOT_EXISTS); } for (MesProBagCodeDO oldBagCode : oldBagCodes) { if (!batch.getId().equals(oldBagCode.getBatchId())) { throw exception(PRO_BAG_CODE_REPLACE_BATCH_MISMATCH); } if (!MesProBagCodeStatusEnum.GENERATED.getStatus().equals(oldBagCode.getStatus()) && !MesProBagCodeStatusEnum.PRINTED.getStatus().equals(oldBagCode.getStatus())) { throw exception(PRO_BAG_CODE_REPLACE_STATUS_INVALID); } if (replaceMapper.selectByOldBagCodeId(oldBagCode.getId()) != null) { throw exception(PRO_BAG_CODE_REPLACE_ALREADY_REPLACED); } } Map palletMap = new LinkedHashMap<>(); oldBagCodes.stream().map(MesProBagCodeDO::getPalletId).filter(id -> id != null) .distinct().sorted().forEach(palletId -> { MesProPalletDO pallet = palletMapper.selectByIdForUpdate(palletId); if (pallet == null || !MesProPalletStatusEnum.IN_USE.getStatus().equals(pallet.getStatus())) { throw exception(PRO_BAG_CODE_REPLACE_PALLET_INVALID); } palletMap.put(palletId, pallet); }); String replaceUuid = IdUtil.fastSimpleUUID(); LocalDateTime replaceTime = LocalDateTime.now(); int startNo = bagCodeMapper.selectMaxBagNo() + 1; List newBagCodes = new ArrayList<>(oldBagCodes.size()); List replacements = new ArrayList<>(oldBagCodes.size()); List items = new ArrayList<>(oldBagCodes.size()); for (int i = 0; i < oldBagCodes.size(); i++) { MesProBagCodeDO oldBagCode = oldBagCodes.get(i); if (bagCodeMapper.cancelById(oldBagCode.getId(), oldBagCode.getStatus(), MesProBagCodeStatusEnum.CANCELED.getStatus(), replaceTime, replaceReqVO.getReason()) != 1) { throw exception(PRO_BAG_CODE_REPLACE_STATUS_INVALID); } int newBagNo = startNo + i; MesProPalletDO pallet = oldBagCode.getPalletId() == null ? null : palletMap.get(oldBagCode.getPalletId()); MesProBagCodeDO newBagCode = new MesProBagCodeDO() .setUuid(replaceUuid) .setCode(batch.getCode() + "-" + StrUtil.padPre(String.valueOf(newBagNo), 4, '0')) .setBagNo(newBagNo) .setBatchId(batch.getId()) .setBatchCode(batch.getCode()) .setItemId(oldBagCode.getItemId()) .setItemCode(oldBagCode.getItemCode()) .setItemName(oldBagCode.getItemName()) .setPalletId(pallet == null ? null : pallet.getId()) .setPalletCode(pallet == null ? null : pallet.getCode()) .setStatus(MesProBagCodeStatusEnum.GENERATED.getStatus()) .setRemark(replaceReqVO.getReason()); newBagCodes.add(newBagCode); replacements.add(new MesProBagCodeReplaceDO() .setReplaceUuid(replaceUuid) .setBatchId(batch.getId()) .setBatchCode(batch.getCode()) .setOldBagCodeId(oldBagCode.getId()) .setOldCode(oldBagCode.getCode()) .setOldBagNo(oldBagCode.getBagNo()) .setOldStatus(oldBagCode.getStatus()) .setOldPalletId(oldBagCode.getPalletId()) .setOldPalletCode(oldBagCode.getPalletCode()) .setNewCode(newBagCode.getCode()) .setNewBagNo(newBagNo) .setReason(replaceReqVO.getReason()) .setReplaceTime(replaceTime)); items.add(new MesProBagCodeReplaceItemRespVO() .setOldBagCodeId(oldBagCode.getId()) .setOldCode(oldBagCode.getCode()) .setOldBagNo(oldBagCode.getBagNo()) .setOldStatus(oldBagCode.getStatus()) .setOldPalletId(oldBagCode.getPalletId()) .setOldPalletCode(oldBagCode.getPalletCode()) .setNewCode(newBagCode.getCode()) .setNewBagNo(newBagNo) .setNewPalletId(newBagCode.getPalletId()) .setNewPalletCode(newBagCode.getPalletCode()) .setReason(replaceReqVO.getReason()) .setReplaceTime(replaceTime)); } bagCodeMapper.insertBatch(newBagCodes); for (int i = 0; i < replacements.size(); i++) { replacements.get(i).setNewBagCodeId(newBagCodes.get(i).getId()); items.get(i).setNewBagCodeId(newBagCodes.get(i).getId()); } replaceMapper.insertBatch(replacements); batchMapper.updateById(new MesProBatchDO().setId(batch.getId()) .setBagQuantity(bagCodeMapper.selectEffectiveCountByBatchId(batch.getId()))); return new MesProBagCodeReplaceRespVO() .setReplaceUuid(replaceUuid) .setBatchId(batch.getId()) .setBatchCode(batch.getCode()) .setCount(newBagCodes.size()) .setItems(items); } @Override @Transactional(rollbackFor = Exception.class) public void deleteBagCodesByUuid(String uuid) { // 1. 校验生成组存在 List bagCodes = bagCodeMapper.selectListByUuid(uuid); if (CollUtil.isEmpty(bagCodes)) { throw exception(PRO_BAG_CODE_UUID_NOT_EXISTS); } // 2. 校验均为已生成状态 if (bagCodes.stream().anyMatch(bagCode -> !MesProBagCodeStatusEnum.GENERATED.getStatus().equals(bagCode.getStatus()))) { throw exception(PRO_BAG_CODE_STATUS_NOT_GENERATED); } // 3. 绑定的托盘仅限"自动生成且未绑定批次"(生成数据包时自动绑定),级联删除;已入批次的托盘不允许随包删除 Set palletIds = new LinkedHashSet<>(); bagCodes.stream().map(MesProBagCodeDO::getPalletId).filter(Objects::nonNull).forEach(palletIds::add); for (Long palletId : palletIds) { MesProPalletDO pallet = palletMapper.selectById(palletId); if (pallet != null && (pallet.getBatchId() != null || StrUtil.isNotEmpty(pallet.getCode()))) { throw exception(PRO_BAG_CODE_BIND_PALLET_BOUND); } } // 4. 删除生成组与其自动生成的临时托盘 bagCodeMapper.deleteByIds(bagCodes.stream().map(MesProBagCodeDO::getId).toList()); if (!palletIds.isEmpty()) { palletMapper.deleteByIds(palletIds); } // 5. 回减批次袋码数量 MesProBatchDO batch = batchMapper.selectById(bagCodes.get(0).getBatchId()); if (batch != null && batch.getBagQuantity() != null) { batchMapper.updateById(new MesProBatchDO().setId(batch.getId()) .setBagQuantity(Math.max(0, batch.getBagQuantity() - bagCodes.size()))); } } @Override @Transactional(rollbackFor = Exception.class) public void bindPallet(MesProBagCodeBindReqVO bindReqVO) { // 1. 锁定托盘,避免与自动归集并发修改袋数 MesProPalletDO pallet = palletMapper.selectByIdForUpdate(bindReqVO.getPalletId()); if (pallet == null) { throw exception(PRO_PALLET_NOT_EXISTS); } // 2. 锁定并校验袋码 List bagCodes = validateBagCodesForBind(bindReqVO.getIds(), pallet, true); // 3. 绑定袋码并累加托盘已装袋数(托盘无容量上限) int currentCount = pallet.getBagCount() == null ? 0 : pallet.getBagCount(); bagCodeMapper.bindPalletByIds(bindReqVO.getIds(), pallet.getId(), pallet.getCode()); palletService.updatePalletBagCount(pallet.getId(), currentCount + bagCodes.size()); } @Override @Transactional(rollbackFor = Exception.class) public void unbindPallet(MesProBagCodeBindReqVO bindReqVO) { // 1. 锁定托盘,避免与自动归集并发修改袋数 MesProPalletDO pallet = palletMapper.selectByIdForUpdate(bindReqVO.getPalletId()); if (pallet == null) { throw exception(PRO_PALLET_NOT_EXISTS); } // 2. 锁定并校验袋码均绑定在当前托盘上 List bagCodes = bagCodeMapper.selectListByIdsForUpdate(bindReqVO.getIds()); if (bagCodes.size() != bindReqVO.getIds().size()) { throw exception(PRO_BAG_CODE_NOT_EXISTS); } if (bagCodes.stream().anyMatch(bagCode -> !pallet.getId().equals(bagCode.getPalletId()))) { throw exception(PRO_BAG_CODE_BIND_PALLET_MISMATCH); } // 3. 解绑袋码并回减托盘已装袋数 bagCodeMapper.unbindPalletByIds(bindReqVO.getIds()); int currentCount = pallet.getBagCount() == null ? 0 : pallet.getBagCount(); palletService.updatePalletBagCount(pallet.getId(), Math.max(0, currentCount - bagCodes.size())); } @Override public void markBagCodesPrinted(Collection ids) { if (CollUtil.isEmpty(ids)) { return; } bagCodeMapper.updateStatusByIds(ids, MesProBagCodeStatusEnum.GENERATED.getStatus(), MesProBagCodeStatusEnum.PRINTED.getStatus(), LocalDateTime.now()); } @Override public MesProBagCodeDO getBagCode(Long id) { return bagCodeMapper.selectById(id); } @Override public MesProBagCodeDO validateBagCodeExists(Long id) { MesProBagCodeDO bagCode = bagCodeMapper.selectById(id); if (bagCode == null) { throw exception(PRO_BAG_CODE_NOT_EXISTS); } return bagCode; } @Override public MesProBagCodeDO getBagCodeByCode(String code) { return bagCodeMapper.selectByCode(code); } @Override public MesProBagCodeReplaceDO getReplacementByOldBagCodeId(Long oldBagCodeId) { return replaceMapper.selectByOldBagCodeId(oldBagCodeId); } @Override public MesProBagCodeReplaceDO getReplacementByNewBagCodeId(Long newBagCodeId) { return replaceMapper.selectByNewBagCodeId(newBagCodeId); } @Override public PageResult getBagCodePage(MesProBagCodePageReqVO pageReqVO) { return bagCodeMapper.selectPage(pageReqVO); } @Override public List getBagCodeListByUuid(String uuid) { return bagCodeMapper.selectListByUuid(uuid); } @Override public List getBagCodeListByPalletId(Long palletId) { return bagCodeMapper.selectListByPalletId(palletId); } @Override public List getBagCodeListByBatchId(Long batchId) { return bagCodeMapper.selectListByBatchId(batchId); } @Override public void markOutbound(Long id, Long salesId) { bagCodeMapper.markOutbound(id, salesId, LocalDateTime.now()); } @Override public void clearOutbound(Long id) { bagCodeMapper.clearOutbound(id); } // ==================== 私有方法 ==================== /** * 校验待绑定的袋码:存在、与托盘同批次、未绑定过托盘、状态有效(已生成/已导出印刷) */ private List validateBagCodesForBind(List ids, MesProPalletDO pallet, boolean lock) { List bagCodes = lock ? bagCodeMapper.selectListByIdsForUpdate(ids) : bagCodeMapper.selectListByIds(ids); if (bagCodes.size() != ids.size()) { throw exception(PRO_BAG_CODE_NOT_EXISTS); } for (MesProBagCodeDO bagCode : bagCodes) { if (!pallet.getBatchId().equals(bagCode.getBatchId())) { throw exception(PRO_BAG_CODE_BIND_PALLET_MISMATCH); } if (bagCode.getPalletId() != null) { throw exception(PRO_BAG_CODE_BIND_PALLET_BOUND); } if (MesProBagCodeStatusEnum.CANCELED.getStatus().equals(bagCode.getStatus())) { throw exception(PRO_BAG_CODE_STATUS_NOT_GENERATED); } } return bagCodes; } }