Commit dfeb3c104d48d1b8844c9850bf55c924f51e37ef
1 parent
b31f78c8
✨ feat(mes): 更新销售出库单状态流转逻辑,添加 OQC 检验支持
优化销售出库单的状态流转逻辑,新增待检测状态以支持 OQC 检验。根据检验结果自动流转状态,提升出库流程的灵活性和准确性。
Showing
6 changed files
with
64 additions
and
11 deletions
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/ErrorCodeConstants.java
| @@ -533,7 +533,8 @@ public interface ErrorCodeConstants { | @@ -533,7 +533,8 @@ public interface ErrorCodeConstants { | ||
| 533 | ErrorCode WM_PRODUCT_SALES_CANNOT_SHIPPING = new ErrorCode(1_040_714_006, "当前状态不允许填写运单"); | 533 | ErrorCode WM_PRODUCT_SALES_CANNOT_SHIPPING = new ErrorCode(1_040_714_006, "当前状态不允许填写运单"); |
| 534 | ErrorCode WM_PRODUCT_SALES_CANNOT_FINISH = new ErrorCode(1_040_714_007, "当前状态不允许执行出库"); | 534 | ErrorCode WM_PRODUCT_SALES_CANNOT_FINISH = new ErrorCode(1_040_714_007, "当前状态不允许执行出库"); |
| 535 | ErrorCode WM_PRODUCT_SALES_CANNOT_CANCEL = new ErrorCode(1_040_714_008, "当前状态不允许取消"); | 535 | ErrorCode WM_PRODUCT_SALES_CANNOT_CANCEL = new ErrorCode(1_040_714_008, "当前状态不允许取消"); |
| 536 | - ErrorCode WM_PRODUCT_SALES_DETAILS_EMPTY = new ErrorCode(1_040_714_009, "拣货明细不能为空"); | 536 | + ErrorCode WM_PRODUCT_SALES_CANNOT_CONFIRM = new ErrorCode(1_040_714_009, "当前状态不允许确认检验通过"); |
| 537 | + ErrorCode WM_PRODUCT_SALES_DETAILS_EMPTY = new ErrorCode(1_040_714_020, "拣货明细不能为空"); | ||
| 537 | ErrorCode WM_PRODUCT_SALES_DETAIL_QUANTITY_MISMATCH = new ErrorCode(1_040_714_010, "拣货数量与出库数量不匹配"); | 538 | ErrorCode WM_PRODUCT_SALES_DETAIL_QUANTITY_MISMATCH = new ErrorCode(1_040_714_010, "拣货数量与出库数量不匹配"); |
| 538 | ErrorCode WM_PRODUCT_SALES_LINE_NOT_EXISTS = new ErrorCode(1_040_714_011, "销售出库单行不存在"); | 539 | ErrorCode WM_PRODUCT_SALES_LINE_NOT_EXISTS = new ErrorCode(1_040_714_011, "销售出库单行不存在"); |
| 539 | ErrorCode WM_PRODUCT_SALES_DETAIL_NOT_EXISTS = new ErrorCode(1_040_714_012, "销售出库明细不存在"); | 540 | ErrorCode WM_PRODUCT_SALES_DETAIL_NOT_EXISTS = new ErrorCode(1_040_714_012, "销售出库明细不存在"); |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/enums/wm/MesWmProductSalesStatusEnum.java
| @@ -28,10 +28,18 @@ public enum MesWmProductSalesStatusEnum implements ArrayValuable<Integer> { | @@ -28,10 +28,18 @@ public enum MesWmProductSalesStatusEnum implements ArrayValuable<Integer> { | ||
| 28 | */ | 28 | */ |
| 29 | PREPARE(MesOrderStatusConstants.PREPARE, "草稿"), | 29 | PREPARE(MesOrderStatusConstants.PREPARE, "草稿"), |
| 30 | /** | 30 | /** |
| 31 | - * 待拣货 | 31 | + * 待检测(需要 OQC 检验时),对接 qc 模块的 MesQcOqcDO 后续流程 |
| 32 | * | 32 | * |
| 33 | * 对应方法:{@link MesWmProductSalesService#submitProductSales(Long)} | 33 | * 对应方法:{@link MesWmProductSalesService#submitProductSales(Long)} |
| 34 | */ | 34 | */ |
| 35 | + CONFIRMED(MesOrderStatusConstants.CONFIRMED, "待检测"), | ||
| 36 | + /** | ||
| 37 | + * 待拣货 | ||
| 38 | + * | ||
| 39 | + * 对应方法: | ||
| 40 | + * 1. 不需要 OQC 检验时:{@link MesWmProductSalesService#submitProductSales(Long)} | ||
| 41 | + * 2. 或 OQC 检验完成时:{@link MesWmProductSalesService#confirmProductSales(Long)} | ||
| 42 | + */ | ||
| 35 | APPROVING(MesOrderStatusConstants.APPROVING, "待拣货"), | 43 | APPROVING(MesOrderStatusConstants.APPROVING, "待拣货"), |
| 36 | /** | 44 | /** |
| 37 | * 待填写运单 | 45 | * 待填写运单 |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesLineServiceImpl.java
| @@ -115,19 +115,30 @@ public class MesWmProductSalesLineServiceImpl implements MesWmProductSalesLineSe | @@ -115,19 +115,30 @@ public class MesWmProductSalesLineServiceImpl implements MesWmProductSalesLineSe | ||
| 115 | productSalesLineMapper.updateById(new MesWmProductSalesLineDO() | 115 | productSalesLineMapper.updateById(new MesWmProductSalesLineDO() |
| 116 | .setId(id).setOqcId(oqcId).setQualityStatus(qualityStatus)); | 116 | .setId(id).setOqcId(oqcId).setQualityStatus(qualityStatus)); |
| 117 | 117 | ||
| 118 | - // 2. 检查同一出库单下所有需要 OQC 检验的行的质检状态,联动更新出库单整体状态 | 118 | + // 2. 检查同一出库单下所有需要 OQC 检验的行 |
| 119 | MesWmProductSalesLineDO currentLine = productSalesLineMapper.selectById(id); | 119 | MesWmProductSalesLineDO currentLine = productSalesLineMapper.selectById(id); |
| 120 | if (currentLine == null || currentLine.getSalesId() == null) { | 120 | if (currentLine == null || currentLine.getSalesId() == null) { |
| 121 | return; | 121 | return; |
| 122 | } | 122 | } |
| 123 | Long salesId = currentLine.getSalesId(); | 123 | Long salesId = currentLine.getSalesId(); |
| 124 | List<MesWmProductSalesLineDO> allLines = productSalesLineMapper.selectListBySalesId(salesId); | 124 | List<MesWmProductSalesLineDO> allLines = productSalesLineMapper.selectListBySalesId(salesId); |
| 125 | + | ||
| 126 | + // 2.1 检查是否有不合格行 → 取消出库单 | ||
| 125 | boolean hasNg = CollectionUtils.anyMatch(allLines, | 127 | boolean hasNg = CollectionUtils.anyMatch(allLines, |
| 126 | line -> Boolean.TRUE.equals(line.getOqcCheckFlag()) | 128 | line -> Boolean.TRUE.equals(line.getOqcCheckFlag()) |
| 127 | && Objects.equals(line.getQualityStatus(), MesWmQualityStatusEnum.FAIL.getStatus())); | 129 | && Objects.equals(line.getQualityStatus(), MesWmQualityStatusEnum.FAIL.getStatus())); |
| 128 | if (hasNg) { | 130 | if (hasNg) { |
| 129 | log.info("[updateProductSalesLineWhenOqcFinish][销售出库单({}) 存在质检不合格行,取消出库单]", salesId); | 131 | log.info("[updateProductSalesLineWhenOqcFinish][销售出库单({}) 存在质检不合格行,取消出库单]", salesId); |
| 130 | productSalesService.cancelProductSales(salesId); | 132 | productSalesService.cancelProductSales(salesId); |
| 133 | + return; | ||
| 134 | + } | ||
| 135 | + | ||
| 136 | + // 2.2 检查是否所有 OQC 行都已完成,自动流转 CONFIRMED → APPROVING | ||
| 137 | + boolean hasUnchecked = CollectionUtils.anyMatch(allLines, | ||
| 138 | + line -> Boolean.TRUE.equals(line.getOqcCheckFlag()) && line.getOqcId() == null); | ||
| 139 | + if (!hasUnchecked) { | ||
| 140 | + log.info("[updateProductSalesLineWhenOqcFinish][销售出库单({}) 所有 OQC 行检验完成,流转到待拣货]", salesId); | ||
| 141 | + productSalesService.confirmProductSales(salesId); | ||
| 131 | } | 142 | } |
| 132 | } | 143 | } |
| 133 | 144 |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesService.java
| @@ -53,7 +53,11 @@ public interface MesWmProductSalesService { | @@ -53,7 +53,11 @@ public interface MesWmProductSalesService { | ||
| 53 | PageResult<MesWmProductSalesDO> getProductSalesPage(MesWmProductSalesPageReqVO pageReqVO); | 53 | PageResult<MesWmProductSalesDO> getProductSalesPage(MesWmProductSalesPageReqVO pageReqVO); |
| 54 | 54 | ||
| 55 | /** | 55 | /** |
| 56 | - * 提交销售出库单(草稿 → 待拣货) | 56 | + * 提交销售出库单 |
| 57 | + * <ul> | ||
| 58 | + * <li>有 OQC 检验行:草稿 → 待检测</li> | ||
| 59 | + * <li>无 OQC 检验行:草稿 → 待拣货</li> | ||
| 60 | + * </ul> | ||
| 57 | * | 61 | * |
| 58 | * @param id 编号 | 62 | * @param id 编号 |
| 59 | */ | 63 | */ |
| @@ -95,4 +99,11 @@ public interface MesWmProductSalesService { | @@ -95,4 +99,11 @@ public interface MesWmProductSalesService { | ||
| 95 | */ | 99 | */ |
| 96 | void cancelProductSales(Long id); | 100 | void cancelProductSales(Long id); |
| 97 | 101 | ||
| 102 | + /** | ||
| 103 | + * OQC 检验完成后,自动流转(待检测 → 待拣货) | ||
| 104 | + * | ||
| 105 | + * @param id 编号 | ||
| 106 | + */ | ||
| 107 | + void confirmProductSales(Long id); | ||
| 108 | + | ||
| 98 | } | 109 | } |
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/wm/productsales/MesWmProductSalesServiceImpl.java
| @@ -117,7 +117,16 @@ public class MesWmProductSalesServiceImpl implements MesWmProductSalesService { | @@ -117,7 +117,16 @@ public class MesWmProductSalesServiceImpl implements MesWmProductSalesService { | ||
| 117 | throw exception(WM_PRODUCT_SALES_LINES_EMPTY); | 117 | throw exception(WM_PRODUCT_SALES_LINES_EMPTY); |
| 118 | } | 118 | } |
| 119 | 119 | ||
| 120 | - // 提交(草稿 → 待拣货) | 120 | + // 检查所有行的 oqcCheckFlag:如果有需要 OQC 检验的行,进入待检测状态 |
| 121 | + boolean needOqc = CollectionUtils.anyMatch(lines, | ||
| 122 | + line -> Boolean.TRUE.equals(line.getOqcCheckFlag())); | ||
| 123 | + if (needOqc) { | ||
| 124 | + // 需要检验,进入待检测 | ||
| 125 | + productSalesMapper.updateById(new MesWmProductSalesDO() | ||
| 126 | + .setId(id).setStatus(MesWmProductSalesStatusEnum.CONFIRMED.getStatus())); | ||
| 127 | + return; | ||
| 128 | + } | ||
| 129 | + // 不需要检验,直接进入待拣货 | ||
| 121 | productSalesMapper.updateById(new MesWmProductSalesDO() | 130 | productSalesMapper.updateById(new MesWmProductSalesDO() |
| 122 | .setId(id).setStatus(MesWmProductSalesStatusEnum.APPROVING.getStatus())); | 131 | .setId(id).setStatus(MesWmProductSalesStatusEnum.APPROVING.getStatus())); |
| 123 | } | 132 | } |
| @@ -215,6 +224,18 @@ public class MesWmProductSalesServiceImpl implements MesWmProductSalesService { | @@ -215,6 +224,18 @@ public class MesWmProductSalesServiceImpl implements MesWmProductSalesService { | ||
| 215 | .setId(id).setStatus(MesWmProductSalesStatusEnum.CANCELED.getStatus())); | 224 | .setId(id).setStatus(MesWmProductSalesStatusEnum.CANCELED.getStatus())); |
| 216 | } | 225 | } |
| 217 | 226 | ||
| 227 | + @Override | ||
| 228 | + public void confirmProductSales(Long id) { | ||
| 229 | + // 校验存在 + 待检测状态 | ||
| 230 | + MesWmProductSalesDO sales = validateProductSalesExists(id); | ||
| 231 | + if (ObjUtil.notEqual(MesWmProductSalesStatusEnum.CONFIRMED.getStatus(), sales.getStatus())) { | ||
| 232 | + throw exception(WM_PRODUCT_SALES_CANNOT_CONFIRM); | ||
| 233 | + } | ||
| 234 | + // OQC 检验完成,流转到待拣货 | ||
| 235 | + productSalesMapper.updateById(new MesWmProductSalesDO() | ||
| 236 | + .setId(id).setStatus(MesWmProductSalesStatusEnum.APPROVING.getStatus())); | ||
| 237 | + } | ||
| 238 | + | ||
| 218 | private MesWmProductSalesDO validateProductSalesExists(Long id) { | 239 | private MesWmProductSalesDO validateProductSalesExists(Long id) { |
| 219 | MesWmProductSalesDO sales = productSalesMapper.selectById(id); | 240 | MesWmProductSalesDO sales = productSalesMapper.selectById(id); |
| 220 | if (sales == null) { | 241 | if (sales == null) { |
yudao-module-mes/src/main/resources/mapper/qc/pendinginspect/MesQcPendingInspectMapper.xml
| @@ -4,12 +4,12 @@ | @@ -4,12 +4,12 @@ | ||
| 4 | 4 | ||
| 5 | <!-- | 5 | <!-- |
| 6 | 待检任务查询(UNION ALL 多来源),已实现的来源: | 6 | 待检任务查询(UNION ALL 多来源),已实现的来源: |
| 7 | - 1. 到货通知单(IQC):单据状态=待质检(2),行的 iqc_check_flag=1 且 iqc_id 为空 | ||
| 8 | - 2. 外协入库单(IQC):单据状态=待检验(1),行的 iqc_check_flag=1 且 iqc_id 为空 | ||
| 9 | - 3. 生产报工(IPQC):单据状态=待检验(3) | ||
| 10 | - 4. 销售出库单(OQC):无单据状态要求,行的 oqc_check_flag=1 且 oqc_id 为空 | ||
| 11 | - 5. 生产退料单(RQC):单据状态=待检验(1),行的 rqc_check_flag=1 且 rqc_id 为空 且 quality_status=0(待检) | ||
| 12 | - 6. 销售退货单(RQC):单据状态=待检验(1),行的 rqc_check_flag=1 且 rqc_id 为空 且 quality_status=0(待检) | 7 | + 1. 到货通知单(IQC):单据状态=PENDING_QC(2),行的 iqc_check_flag=1 且 iqc_id 为空 |
| 8 | + 2. 外协入库单(IQC):单据状态=CONFIRMED(1),行的 iqc_check_flag=1 且 iqc_id 为空 | ||
| 9 | + 3. 生产报工(IPQC):单据状态=UNCHECK(3) | ||
| 10 | + 4. 销售出库单(OQC):单据状态=CONFIRMED(1),行的 oqc_check_flag=1 且 oqc_id 为空 | ||
| 11 | + 5. 生产退料单(RQC):单据状态=CONFIRMED(1),行的 rqc_check_flag=1 且 rqc_id 为空 且 quality_status=0(待检) | ||
| 12 | + 6. 销售退货单(RQC):单据状态=CONFIRMED(1),行的 rqc_check_flag=1 且 rqc_id 为空 且 quality_status=0(待检) | ||
| 13 | --> | 13 | --> |
| 14 | <select id="selectQcPendingPage" resultType="cn.iocoder.yudao.module.mes.controller.admin.qc.pendinginspect.vo.MesQcPendingInspectRespVO"> | 14 | <select id="selectQcPendingPage" resultType="cn.iocoder.yudao.module.mes.controller.admin.qc.pendinginspect.vo.MesQcPendingInspectRespVO"> |
| 15 | SELECT * FROM ( | 15 | SELECT * FROM ( |
| @@ -103,6 +103,7 @@ | @@ -103,6 +103,7 @@ | ||
| 103 | JOIN mes_wm_product_sales_line sl ON s.id = sl.sales_id | 103 | JOIN mes_wm_product_sales_line sl ON s.id = sl.sales_id |
| 104 | WHERE sl.oqc_check_flag = 1 | 104 | WHERE sl.oqc_check_flag = 1 |
| 105 | AND sl.oqc_id IS NULL | 105 | AND sl.oqc_id IS NULL |
| 106 | + AND s.status = ${@cn.iocoder.yudao.module.mes.enums.wm.MesWmProductSalesStatusEnum@CONFIRMED.status} | ||
| 106 | AND s.deleted = 0 | 107 | AND s.deleted = 0 |
| 107 | AND sl.deleted = 0 | 108 | AND sl.deleted = 0 |
| 108 | 109 |