| | |
| | | // 1. 校验关联数据(产线、生产人员) |
| | | MesProLineDO line = lineService.validateLineExistsAndEnable(createReqVO.getLineId()); |
| | | validateRelations(createReqVO); |
| | | createReqVO.setItemId(resolveBindingItem(null, createReqVO)); |
| | | |
| | | // 2. 生成批次号(编码规则:前缀 + 日期 + 产线编码 + 流水号) |
| | | String code = generateBatchCode(line.getCode()); |
| | |
| | | boolean bindPallets = CollUtil.isNotEmpty(createReqVO.getPalletIds()); |
| | | MesProBatchDO batch = BeanUtils.toBean(createReqVO, MesProBatchDO.class) |
| | | .setCode(code) |
| | | .setBusinessCode(codeRedisDao.generate()) |
| | | .setLineCode(line.getCode()) |
| | | .setLineName(line.getName()) |
| | | .setBagQuantity(0) |
| | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public List<MesProBatchDO> preGenerateBatch(MesProBatchPreGenerateReqVO reqVO) { |
| | | // 1. 生成临时批次码(全局 8 位序号,格式 PB-00000001) |
| | | int startSeq = batchMapper.selectMaxTempCodeSeq() + 1; |
| | | // 1. 通过统一编码生成器分配临时码及业务码,不再解析历史临时码序号。 |
| | | List<MesProBatchDO> list = new ArrayList<>(reqVO.getCount()); |
| | | for (int i = 0; i < reqVO.getCount(); i++) { |
| | | list.add(new MesProBatchDO() |
| | | .setTempCode(codeRedisDao.generate()) |
| | | .setBusinessCode(codeRedisDao.generate()) |
| | | .setBagQuantity(0) |
| | | .setPalletQuantity(0) |
| | | .setStatus(MesProBatchStatusEnum.DRAFT.getStatus()) |
| | |
| | | // 2. 校验关联数据并生成正式批次号 |
| | | MesProLineDO line = lineService.validateLineExistsAndEnable(fillReqVO.getLineId()); |
| | | validateRelations(fillReqVO); |
| | | fillReqVO.setItemId(resolveBindingItem(batch, fillReqVO)); |
| | | String code = generateBatchCode(line.getCode()); |
| | | // 3. 落库业务信息(保留临时批次码用于历史扫码追溯;产线编码/名称冗余回填;勾选绑定托盘时批次直接进入生产中) |
| | | boolean bindPallets = CollUtil.isNotEmpty(fillReqVO.getPalletIds()); |
| | |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void updateBatch(MesProBatchSaveReqVO updateReqVO) { |
| | | // 1. 校验存在 + 状态(草稿/生产中才允许修改) |
| | | MesProBatchDO oldBatch = validateBatchExists(updateReqVO.getId()); |
| | | MesProBatchDO oldBatch = batchMapper.selectByIdForUpdate(updateReqVO.getId()); |
| | | if (oldBatch == null) throw exception(PRO_BATCH_NOT_EXISTS); |
| | | validateBatchEditable(oldBatch); |
| | | // 2. 校验关联数据(生产人员) |
| | | validateRelations(updateReqVO); |
| | | updateReqVO.setItemId(resolveBindingItem(oldBatch, updateReqVO)); |
| | | |
| | | // 3. 未生成正式批次号或产线变化时重新生成批次号(批次号包含产线编码要素) |
| | | boolean codeEmpty = StrUtil.isEmpty(oldBatch.getCode()); |
| | |
| | | } |
| | | |
| | | @Override |
| | | public MesProBatchDO getBatchByScanCode(String code) { |
| | | return batchMapper.selectByScanCode(code); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public int generateBusinessCodes(java.util.List<Long> ids) { |
| | | if (ids == null || ids.isEmpty() || ids.size() > 200 || ids.stream().anyMatch(java.util.Objects::isNull)) |
| | | throw new cn.iocoder.yudao.framework.common.exception.ServiceException(400, "请选择 1 至 200 条记录"); |
| | | java.util.List<MesProBatchDO> records = new java.util.ArrayList<>(); |
| | | for (Long id : ids.stream().distinct().sorted().toList()) { |
| | | MesProBatchDO record = batchMapper.selectByIdForUpdate(id); |
| | | if (record == null) throw exception(PRO_BATCH_NOT_EXISTS); |
| | | if (MesProBatchStatusEnum.CANCELED.getStatus().equals(record.getStatus())) |
| | | throw new cn.iocoder.yudao.framework.common.exception.ServiceException(400, "已作废记录不可补生成业务码"); |
| | | records.add(record); |
| | | } |
| | | int count = 0; |
| | | for (MesProBatchDO record : records) { |
| | | if (StrUtil.isNotBlank(record.getBusinessCode())) continue; |
| | | batchMapper.updateById(new MesProBatchDO().setId(record.getId()).setBusinessCode(codeRedisDao.generate())); |
| | | count++; |
| | | } |
| | | return count; |
| | | } |
| | | |
| | | @Override |
| | | public MesProBatchDO getBatchByCode(String code) { |
| | | MesProBatchDO batch = batchMapper.selectByCode(code); |
| | | if (batch == null) { |
| | |
| | | * 批次绑定托盘(可选):同事务内复用托盘绑定批次逻辑, |
| | | * 生成正式托盘码并级联录入托盘下未绑批次的袋码,失败整体回滚 |
| | | */ |
| | | private Long resolveBindingItem(MesProBatchDO batch, MesProBatchSaveReqVO req) { |
| | | Long itemId = batch == null ? null : batch.getItemId(); |
| | | if (batch != null) { |
| | | for (Long existing : bagCodeMapper.selectDistinctItemIdsByBatchId(batch.getId())) |
| | | itemId = cn.iocoder.yudao.module.mes.service.pro.pallet.MesProPalletItemResolver.merge(itemId, existing); |
| | | for (var pallet : palletMapper.selectListByBatchId(batch.getId())) |
| | | itemId = cn.iocoder.yudao.module.mes.service.pro.pallet.MesProPalletItemResolver.merge(itemId, |
| | | cn.iocoder.yudao.module.mes.service.pro.pallet.MesProPalletItemResolver.resolve(pallet, bagCodeMapper.selectListByPalletId(pallet.getId()))); |
| | | } |
| | | if (CollUtil.isNotEmpty(req.getPalletIds())) for (Long id : req.getPalletIds().stream().distinct().sorted().toList()) { |
| | | var pallet = palletMapper.selectByIdForUpdate(id); |
| | | if (pallet == null) throw exception(PRO_PALLET_NOT_EXISTS); |
| | | Long candidate = cn.iocoder.yudao.module.mes.service.pro.pallet.MesProPalletItemResolver.resolve(pallet, bagCodeMapper.selectListByPalletId(id)); |
| | | if (candidate == null) throw new cn.iocoder.yudao.framework.common.exception.ServiceException(400, "托盘缺少品种,请先绑定同品种袋码"); |
| | | itemId = cn.iocoder.yudao.module.mes.service.pro.pallet.MesProPalletItemResolver.merge(itemId, candidate); |
| | | } |
| | | // 请求里的品种只能与已绑定/待绑定托盘一致,不能通过编辑改变批次品种。 |
| | | if (req.getItemId() != null && !Objects.equals(req.getItemId(), itemId)) |
| | | throw new cn.iocoder.yudao.framework.common.exception.ServiceException(400, "品种由绑定托盘带入,不可修改为其他品种"); |
| | | return itemId; |
| | | } |
| | | |
| | | private void bindPalletsToBatch(Long batchId, List<Long> palletIds) { |
| | | if (CollUtil.isEmpty(palletIds)) { |
| | | return; |