feat(mes): 新增包装袋型管理和托盘自动生成功能
- 在 DictTypeConstants 中添加包装袋型字典常量
- 在 ErrorCodeConstants 中添加袋型相关错误码定义
- 修改 MesProBagCodeController 的 generateBagCodes 接口返回托盘标签数据
- 在 MesProBagCodeMapper 中添加查询未绑定有效袋码的方法
- 更新 MesProBagCodeService 接口返回托盘生成结果
- 在 MesProBatchDO 中添加 bagType 字段存储包装袋型
- 在 MesProBatchRespVO 和 SaveReqVO 中添加包装袋型字段
- 实现批次袋型校验和修改限制逻辑
- 在 MesProPalletDO 中添加 autoGenerated 自动生成标识字段
- 在 MesProPalletRespVO 中添加自动生成标识字段
- 实现 MesProPalletService 的 autoCreatePallets 自动托盘生成功能
- 添加 MesProBagCodeGenerateRespVO 和 MesProPalletAutoPrintRespVO 数据传输对象
- 定义 MesProBagTypeEnum 枚举包含小袋大袋类型和阈值
- 提供前端联调文档和数据库迁移脚本
| | |
| | | |
| | | import java.time.LocalDateTime; |
| | | |
| | | import cn.iocoder.yudao.module.mes.enums.DictTypeConstants; |
| | | |
| | | /** |
| | | * MES 袋码赋码(一袋一码)DO |
| | | * <p> |
| | | * 根据批次信息自动生成唯一二维码数据包:码值 = 批次号 + - + 袋序号,全局唯一,满足唯一性、可识别性、可追溯性要求。 |
| | | * 支持批量导出交付印刷,并与托盘码关联。 |
| | | * |
| | | * @author 超级管理员 |
| | | */ |
| | | @TableName("mes_pro_bag_code") |
| | | @KeySequence("mes_pro_bag_code_seq") |
| | | @Data |
| | |
| | | @NoArgsConstructor |
| | | @AllArgsConstructor |
| | | public class MesProBagCodeDO extends BaseDO { |
| | | |
| | | /** |
| | | * 编号 |
| | | */ |
| | | @TableId |
| | | private Long id; |
| | | /** |
| | | * 生成组 UUID(标记同一次生成的数据包) |
| | | */ |
| | | private String uuid; |
| | | /** |
| | | * 袋码(二维码内容:批次号-袋序号,全局唯一) |
| | | */ |
| | | private String code; |
| | | /** |
| | | * 批次内袋序号 |
| | | */ |
| | | private Integer bagNo; |
| | | /** |
| | | * 生产批次编号 |
| | | * <p> |
| | | * 关联 {@link MesProBatchDO#getId()} |
| | | */ |
| | | private Long batchId; |
| | | /** |
| | | * 批次号(冗余,便于展示) |
| | | */ |
| | | private String batchCode; |
| | | /** |
| | | * 绑定托盘编号 |
| | | * <p> |
| | | * 关联 {@link MesProPalletDO#getId()} |
| | | */ |
| | | private Long palletId; |
| | | /** |
| | | * 托盘码(冗余,便于展示) |
| | | */ |
| | | private String palletCode; |
| | | /** |
| | | * 状态 |
| | | * <p> |
| | | * 字典 {@link DictTypeConstants#MES_PRO_BAG_CODE_STATUS} |
| | | * 枚举 {@link cn.iocoder.yudao.module.mes.enums.pro.MesProBagCodeStatusEnum} |
| | | */ |
| | | private Integer status; |
| | | /** |
| | | * 导出(交付印刷)时间 |
| | | */ |
| | | private LocalDateTime printTime; |
| | | /** |
| | | * 作废时间 |
| | | */ |
| | | private LocalDateTime cancelTime; |
| | | /** |
| | | * 作废原因 |
| | | */ |
| | | private String cancelReason; |
| | | /** |
| | | * 备注 |
| | | */ |
| | | private LocalDateTime inboundTime; |
| | | private Long inboundEventId; |
| | | private String inboundDeviceCode; |
| | | private String inboundLineCode; |
| | | private String remark; |
| | | |
| | | } |
| | |
| | | * 已生成托盘码数量 |
| | | */ |
| | | private Integer palletQuantity; |
| | | /** 入库时间 */ |
| | | private LocalDateTime inboundTime; |
| | | /** 累计入库袋数 */ |
| | | private Integer inboundBagQuantity; |
| | | /** 最近入库事件编号 */ |
| | | private Long inboundEventId; |
| | | /** 入库设备编码 */ |
| | | private String inboundDeviceCode; |
| | | /** 入库产线编码 */ |
| | | private String inboundLineCode; |
| | | /** |
| | | * 批次状态 |
| | | * <p> |
| | |
| | | return selectOne(MesProBagCodeDO::getCode, code); |
| | | } |
| | | |
| | | default MesProBagCodeDO selectByCodeForUpdate(String code) { |
| | | return selectOne(new LambdaQueryWrapperX<MesProBagCodeDO>() |
| | | .eq(MesProBagCodeDO::getCode, code).last("FOR UPDATE")); |
| | | } |
| | | |
| | | @org.apache.ibatis.annotations.Update("UPDATE mes_pro_bag_code SET inbound_time = NOW(), inbound_event_id = #{eventId}, inbound_device_code = #{deviceCode}, inbound_line_code = #{lineCode}, update_time = NOW() WHERE id = #{id} AND deleted = 0 AND inbound_event_id IS NULL") |
| | | int markInbound(@org.apache.ibatis.annotations.Param("id") Long id, @org.apache.ibatis.annotations.Param("eventId") Long eventId, |
| | | @org.apache.ibatis.annotations.Param("deviceCode") String deviceCode, @org.apache.ibatis.annotations.Param("lineCode") String lineCode); |
| | | |
| | | default List<MesProBagCodeDO> selectListByUuid(String uuid) { |
| | | return selectList(MesProBagCodeDO::getUuid, uuid); |
| | | } |
| | |
| | | @Select("SELECT * FROM mes_pro_batch WHERE id = #{id} AND deleted = 0 FOR UPDATE") |
| | | MesProBatchDO selectByIdForUpdate(@org.apache.ibatis.annotations.Param("id") Long id); |
| | | |
| | | @org.apache.ibatis.annotations.Update("UPDATE mes_pro_batch SET inbound_time = NOW(), inbound_event_id = #{eventId}, inbound_device_code = #{deviceCode}, inbound_line_code = #{lineCode}, inbound_bag_quantity = COALESCE(inbound_bag_quantity, 0) + 1, update_time = NOW() WHERE id = #{id} AND deleted = 0") |
| | | int markInbound(@org.apache.ibatis.annotations.Param("id") Long id, @org.apache.ibatis.annotations.Param("eventId") Long eventId, |
| | | @org.apache.ibatis.annotations.Param("deviceCode") String deviceCode, @org.apache.ibatis.annotations.Param("lineCode") String lineCode); |
| | | |
| | | default PageResult<MesProBatchDO> selectPage(MesProBatchPageReqVO reqVO) { |
| | | return selectPage(reqVO, new LambdaQueryWrapperX<MesProBatchDO>() |
| | | .likeIfPresent(MesProBatchDO::getCode, reqVO.getCode()) |
| | |
| | | */ |
| | | public interface ErrorCodeConstants { |
| | | |
| | | // ========== MES 生产管理-扫码入库(1-040-755-000) ========== |
| | | ErrorCode PRO_SCAN_EVENT_BAG_NOT_EXISTS = new ErrorCode(1_040_755_000, "袋码不存在"); |
| | | ErrorCode PRO_SCAN_EVENT_ALREADY_INBOUND = new ErrorCode(1_040_755_001, "袋码已入库"); |
| | | ErrorCode PRO_SCAN_EVENT_BATCH_NOT_EXISTS = new ErrorCode(1_040_755_002, "生产批次不存在"); |
| | | ErrorCode PRO_SCAN_EVENT_WIP_WAREHOUSE_NOT_EXISTS = new ErrorCode(1_040_755_003, "WIP虚拟仓不存在"); |
| | | ErrorCode PRO_SCAN_EVENT_LOCATION_INVALID = new ErrorCode(1_040_755_004, "扫码入库库位无效"); |
| | | ErrorCode PRO_SCAN_EVENT_TRANSACTION_FAILED = new ErrorCode(1_040_755_005, "库存事务处理失败"); |
| | | ErrorCode PRO_SCAN_EVENT_ID_CONFLICT = new ErrorCode(1_040_755_006, "事件号已存在但内容不一致"); |
| | | ErrorCode PRO_SCAN_EVENT_FAILED = new ErrorCode(1_040_755_007, "扫码入库失败"); |
| | | |
| | | // ========== MES 基础数据-物料分类(1-040-100-000) ========== |
| | | ErrorCode MD_ITEM_TYPE_NOT_EXISTS = new ErrorCode(1_040_100_000, "物料分类不存在"); |
| | | ErrorCode MD_ITEM_TYPE_EXITS_CHILDREN = new ErrorCode(1_040_100_001, "存在子分类,无法删除"); |