diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/pendinginspect/MesQcPendingInspectController.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/pendinginspect/MesQcPendingInspectController.java new file mode 100644 index 0000000..0b64e0d --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/pendinginspect/MesQcPendingInspectController.java @@ -0,0 +1,37 @@ +package cn.iocoder.yudao.module.mes.controller.admin.qc.pendinginspect; + +import cn.iocoder.yudao.framework.common.pojo.CommonResult; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.mes.controller.admin.qc.pendinginspect.vo.MesQcPendingInspectPageReqVO; +import cn.iocoder.yudao.module.mes.controller.admin.qc.pendinginspect.vo.MesQcPendingInspectRespVO; +import cn.iocoder.yudao.module.mes.service.qc.pendinginspect.MesQcPendingInspectService; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.annotation.Resource; +import jakarta.validation.Valid; +import org.springframework.security.access.prepost.PreAuthorize; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; + +@Tag(name = "管理后台 - MES 待检任务") +@RestController +@RequestMapping("/mes/qc/pending-inspect") +@Validated +public class MesQcPendingInspectController { + + @Resource + private MesQcPendingInspectService pendingInspectService; + + @GetMapping("/page") + @Operation(summary = "获得待检任务分页") + @PreAuthorize("@ss.hasPermission('mes:qc-pending-inspect:query')") + public CommonResult> getPendingInspectPage( + @Valid MesQcPendingInspectPageReqVO pageReqVO) { + return success(pendingInspectService.getPendingInspectPage(pageReqVO)); + } + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/pendinginspect/vo/MesQcPendingInspectPageReqVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/pendinginspect/vo/MesQcPendingInspectPageReqVO.java new file mode 100644 index 0000000..7cfc634 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/pendinginspect/vo/MesQcPendingInspectPageReqVO.java @@ -0,0 +1,24 @@ +package cn.iocoder.yudao.module.mes.controller.admin.qc.pendinginspect.vo; + +import cn.iocoder.yudao.framework.common.pojo.PageParam; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; + +@Schema(description = "管理后台 - MES 待检任务分页 Request VO") +@Data +@EqualsAndHashCode(callSuper = true) +@ToString(callSuper = true) +public class MesQcPendingInspectPageReqVO extends PageParam { + + @Schema(description = "来源单据编号", example = "AN2025001") + private String sourceDocCode; + + @Schema(description = "检验类型", example = "1") + private Integer qcType; + + @Schema(description = "物料编号", example = "1024") + private Long itemId; + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/pendinginspect/vo/MesQcPendingInspectRespVO.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/pendinginspect/vo/MesQcPendingInspectRespVO.java new file mode 100644 index 0000000..bfb4403 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/qc/pendinginspect/vo/MesQcPendingInspectRespVO.java @@ -0,0 +1,66 @@ +package cn.iocoder.yudao.module.mes.controller.admin.qc.pendinginspect.vo; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +import java.math.BigDecimal; +import java.time.LocalDateTime; + +@Schema(description = "管理后台 - MES 待检任务 Response VO") +@Data +public class MesQcPendingInspectRespVO { + + @Schema(description = "来源单据 ID", example = "100") + private Long sourceDocId; + + @Schema(description = "来源单据类型(MesBizTypeConstants)", example = "100") + private Integer sourceDocType; + + @Schema(description = "来源单据编号", example = "AN2025001") + private String sourceDocCode; + + @Schema(description = "来源单据行 ID", example = "200") + private Long sourceLineId; + + @Schema(description = "检验类型(MesQcTypeEnum)", example = "1") + private Integer qcType; + + @Schema(description = "检验类型名称", example = "来料检验") + private String qcTypeName; + + // ========== 物料 ========== + + @Schema(description = "物料 ID", example = "10") + private Long itemId; + + @Schema(description = "物料编码", example = "ITEM001") + private String itemCode; + + @Schema(description = "物料名称", example = "物料A") + private String itemName; + + @Schema(description = "规格型号", example = "100mm*50mm") + private String specification; + + @Schema(description = "单位名称", example = "个") + private String unitName; + + // ========== 数量 ========== + + @Schema(description = "待检数量", example = "100.00") + private BigDecimal quantityToCheck; + + // ========== 供应商(IQC 场景) ========== + + @Schema(description = "供应商 ID", example = "5") + private Long vendorId; + + @Schema(description = "供应商名称", example = "供应商A") + private String vendorName; + + // ========== 时间 ========== + + @Schema(description = "记录时间") + private LocalDateTime recordTime; + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/arrivalnotice/MesWmArrivalNoticeLineMapper.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/arrivalnotice/MesWmArrivalNoticeLineMapper.java index d2dff2a..5ac266f 100644 --- a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/arrivalnotice/MesWmArrivalNoticeLineMapper.java +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/wm/arrivalnotice/MesWmArrivalNoticeLineMapper.java @@ -29,4 +29,11 @@ public interface MesWmArrivalNoticeLineMapper extends BaseMapperX selectListByIqcPending(List noticeIds) { + return selectList(new LambdaQueryWrapperX() + .in(MesWmArrivalNoticeLineDO::getNoticeId, noticeIds) + .eq(MesWmArrivalNoticeLineDO::getIqcCheckFlag, true) + .isNull(MesWmArrivalNoticeLineDO::getIqcId)); + } + } diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/pendinginspect/MesQcPendingInspectService.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/pendinginspect/MesQcPendingInspectService.java new file mode 100644 index 0000000..dda2586 --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/pendinginspect/MesQcPendingInspectService.java @@ -0,0 +1,20 @@ +package cn.iocoder.yudao.module.mes.service.qc.pendinginspect; + +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.mes.controller.admin.qc.pendinginspect.vo.MesQcPendingInspectPageReqVO; +import cn.iocoder.yudao.module.mes.controller.admin.qc.pendinginspect.vo.MesQcPendingInspectRespVO; + +/** + * MES 待检任务 Service 接口 + */ +public interface MesQcPendingInspectService { + + /** + * 获得待检任务分页 + * + * @param pageReqVO 分页查询 + * @return 待检任务分页 + */ + PageResult getPendingInspectPage(MesQcPendingInspectPageReqVO pageReqVO); + +} diff --git a/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/pendinginspect/MesQcPendingInspectServiceImpl.java b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/pendinginspect/MesQcPendingInspectServiceImpl.java new file mode 100644 index 0000000..7100c3f --- /dev/null +++ b/yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/service/qc/pendinginspect/MesQcPendingInspectServiceImpl.java @@ -0,0 +1,162 @@ +package cn.iocoder.yudao.module.mes.service.qc.pendinginspect; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.StrUtil; +import cn.iocoder.yudao.framework.common.pojo.PageResult; +import cn.iocoder.yudao.module.mes.controller.admin.qc.pendinginspect.vo.MesQcPendingInspectPageReqVO; +import cn.iocoder.yudao.module.mes.controller.admin.qc.pendinginspect.vo.MesQcPendingInspectRespVO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.unitmeasure.MesMdUnitMeasureDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.md.vendor.MesMdVendorDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.arrivalnotice.MesWmArrivalNoticeDO; +import cn.iocoder.yudao.module.mes.dal.dataobject.wm.arrivalnotice.MesWmArrivalNoticeLineDO; +import cn.iocoder.yudao.module.mes.dal.mysql.wm.arrivalnotice.MesWmArrivalNoticeLineMapper; +import cn.iocoder.yudao.module.mes.dal.mysql.wm.arrivalnotice.MesWmArrivalNoticeMapper; +import cn.iocoder.yudao.module.mes.enums.MesBizTypeConstants; +import cn.iocoder.yudao.module.mes.enums.qc.MesQcTypeEnum; +import cn.iocoder.yudao.module.mes.enums.wm.MesWmArrivalNoticeStatusEnum; +import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService; +import cn.iocoder.yudao.module.mes.service.md.unitmeasure.MesMdUnitMeasureService; +import cn.iocoder.yudao.module.mes.service.md.vendor.MesMdVendorService; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Service; +import org.springframework.validation.annotation.Validated; + +import java.util.*; +import java.util.stream.Collectors; + +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap; +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; + +/** + * MES 待检任务 Service 实现类 + */ +@Service +@Validated +public class MesQcPendingInspectServiceImpl implements MesQcPendingInspectService { + + @Resource + private MesWmArrivalNoticeMapper arrivalNoticeMapper; + @Resource + private MesWmArrivalNoticeLineMapper arrivalNoticeLineMapper; + @Resource + private MesMdItemService itemService; + @Resource + private MesMdVendorService vendorService; + @Resource + private MesMdUnitMeasureService unitMeasureService; + + // 【下面的 todo 先晚点改】 + // TODO @AI:是否可以在 mapper 里查询(union 汇总)然后关联数据的读取,尽量放在 controller; + // TODO @AI:另外,如果使用 mapper 操作,尽量使用 mybatis plus 或者 mybatis plus join,减少 mapper xml; + @Override + public PageResult getPendingInspectPage(MesQcPendingInspectPageReqVO pageReqVO) { + List allItems = new ArrayList<>(); + + // 1. IQC 来源:到货通知单 + if (pageReqVO.getQcType() == null || Objects.equals(pageReqVO.getQcType(), MesQcTypeEnum.IQC.getType())) { + allItems.addAll(queryIqcPendingFromArrivalNotice(pageReqVO)); + } + // TODO 2. IPQC 来源(生产工单,WM 模块未实现) + // TODO 3. OQC 来源(销售出库单,WM 模块未实现) + // TODO 4. RQC 来源(退货单,WM 模块未实现) + + // 5. 按 recordTime 降序排序 + allItems.sort(Comparator.comparing(MesQcPendingInspectRespVO::getRecordTime, + Comparator.nullsLast(Comparator.reverseOrder()))); + + // 6. 内存分页 + int total = allItems.size(); + int fromIndex = (pageReqVO.getPageNo() - 1) * pageReqVO.getPageSize(); + if (fromIndex >= total) { + return new PageResult<>(Collections.emptyList(), (long) total); + } + int toIndex = Math.min(fromIndex + pageReqVO.getPageSize(), total); + return new PageResult<>(allItems.subList(fromIndex, toIndex), (long) total); + } + + // ==================== IQC 来源:到货通知单 ==================== + + private List queryIqcPendingFromArrivalNotice(MesQcPendingInspectPageReqVO pageReqVO) { + // 1. 查询状态为"待质检"的到货通知单 + List notices = arrivalNoticeMapper.selectListByStatus( + MesWmArrivalNoticeStatusEnum.PENDING_QC.getStatus()); + if (CollUtil.isEmpty(notices)) { + return Collections.emptyList(); + } + // 1.1 按 sourceDocCode 模糊过滤 + if (StrUtil.isNotBlank(pageReqVO.getSourceDocCode())) { + notices = notices.stream() + .filter(n -> n.getCode().contains(pageReqVO.getSourceDocCode())) + .collect(Collectors.toList()); + } + if (CollUtil.isEmpty(notices)) { + return Collections.emptyList(); + } + Map noticeMap = convertMap(notices, MesWmArrivalNoticeDO::getId); + + // 2. 查询需要 IQC 但尚未创建检验单的行 + List lines = arrivalNoticeLineMapper.selectListByIqcPending( + new ArrayList<>(noticeMap.keySet())); + if (CollUtil.isEmpty(lines)) { + return Collections.emptyList(); + } + + // 3. 批量查询物料 + Map itemMap = itemService.getItemMap(convertSet(lines, MesWmArrivalNoticeLineDO::getItemId)); + // 3.1 按 itemId 精确过滤 + if (pageReqVO.getItemId() != null) { + lines = lines.stream() + .filter(line -> pageReqVO.getItemId().equals(line.getItemId())) + .collect(Collectors.toList()); + } + if (CollUtil.isEmpty(lines)) { + return Collections.emptyList(); + } + + // 4. 批量查询供应商 + Map vendorMap = vendorService.getVendorMap( + convertSet(notices, MesWmArrivalNoticeDO::getVendorId)); + // 5. 批量查询计量单位 + Map unitMeasureMap = unitMeasureService.getUnitMeasureMap( + convertSet(itemMap.values(), MesMdItemDO::getUnitMeasureId)); + + // 6. 组装 VO + List result = new ArrayList<>(lines.size()); + for (MesWmArrivalNoticeLineDO line : lines) { + MesWmArrivalNoticeDO notice = noticeMap.get(line.getNoticeId()); + if (notice == null) { + continue; + } + MesQcPendingInspectRespVO vo = new MesQcPendingInspectRespVO(); + vo.setSourceDocId(notice.getId()); + vo.setSourceDocType(MesBizTypeConstants.WM_ARRIVAL_NOTICE); + vo.setSourceDocCode(notice.getCode()); + vo.setSourceLineId(line.getId()); + vo.setQcType(MesQcTypeEnum.IQC.getType()); + vo.setQcTypeName(MesQcTypeEnum.IQC.getName()); + vo.setItemId(line.getItemId()); + vo.setQuantityToCheck(line.getArrivalQuantity()); + vo.setVendorId(notice.getVendorId()); + vo.setRecordTime(notice.getArrivalDate()); + // 物料信息 + MesMdItemDO item = itemMap.get(line.getItemId()); + if (item != null) { + vo.setItemCode(item.getCode()); + vo.setItemName(item.getName()); + vo.setSpecification(item.getSpecification()); + MesMdUnitMeasureDO unit = unitMeasureMap.get(item.getUnitMeasureId()); + if (unit != null) { + vo.setUnitName(unit.getName()); + } + } + // 供应商信息 + MesMdVendorDO vendor = vendorMap.get(notice.getVendorId()); + if (vendor != null) { + vo.setVendorName(vendor.getName()); + } + result.add(vo); + } + return result; + } +}