src/main/java/com/ruoyi/procurementrecord/utils/StockUtils.java
@@ -44,7 +44,7 @@ stockUninventoryDto.setRecordType(String.valueOf(recordType)); stockUninventoryDto.setQualitity(quantity); stockUninventoryDto.setProductModelId(productModelId); stockUninventoryService.addStockUninventory(stockUninventoryDto); stockUninventoryService.addStockInRecordOnly(stockUninventoryDto); } /** @@ -77,7 +77,7 @@ stockInventoryDto.setRecordType(String.valueOf(recordType)); stockInventoryDto.setQualitity(quantity); stockInventoryDto.setProductModelId(productModelId); stockInventoryService.addstockInventory(stockInventoryDto); stockInventoryService.addStockInRecordOnly(stockInventoryDto); } /** src/main/java/com/ruoyi/production/bean/dto/ProductionOperationTaskDto.java
@@ -4,8 +4,10 @@ import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; import org.springframework.format.annotation.DateTimeFormat; import java.math.BigDecimal; import java.time.LocalDate; @EqualsAndHashCode(callSuper = true) @Data @@ -31,4 +33,15 @@ @Schema(description = "完成进度") private BigDecimal completionStatus; @Schema(description = "订单号") private String npsNo; @Schema(description = "开始日期") @DateTimeFormat(pattern = "yyyy-MM-dd") private LocalDate startDate; @Schema(description = "结束日期") @DateTimeFormat(pattern = "yyyy-MM-dd") private LocalDate endDate; } src/main/java/com/ruoyi/production/bean/vo/ProductionOperationTaskVo.java
@@ -29,6 +29,15 @@ @Schema(description = "工单类型 正常/返工返修") private String workOrderType; @Schema(description = "生产任务数") private Long productionTaskCount; @Schema(description = "良品数") private BigDecimal goodQuantity; @Schema(description = "报废数量") private BigDecimal scrapQty; @Schema(description = "完成进度") private BigDecimal completionStatus; src/main/java/com/ruoyi/production/bean/vo/ProductionOrderVo.java
@@ -36,4 +36,7 @@ @Schema(description = "完成进度") private BigDecimal completionStatus; @Schema(description = "是否已退料") private Boolean returned; } src/main/java/com/ruoyi/production/bean/vo/ProductionOrderWorkOrderDetailVo.java
@@ -1,6 +1,5 @@ package com.ruoyi.production.bean.vo; import com.ruoyi.production.pojo.ProductionOperationTask; import com.ruoyi.production.pojo.ProductionOrderRoutingOperationParam; import com.ruoyi.production.pojo.ProductionProductMain; import com.ruoyi.production.pojo.ProductionProductOutput; @@ -13,54 +12,63 @@ import java.util.List; @Data @Schema(name = "ProductionOrderWorkOrderDetailVo", description = "Production order work order/report/inspect detail") @Schema(name = "ProductionOrderWorkOrderDetailVo", description = "生产追溯返回对象") public class ProductionOrderWorkOrderDetailVo { @Schema(description = "Production order info") @Schema(description = "订单") private ProductionOrderVo productionOrder; @Schema(description = "Work order list") @Schema(description = "工单明细列表") private List<WorkOrderDetail> workOrderList; @Data @Schema(name = "WorkOrderDetail", description = "Work order detail") @Schema(name = "WorkOrderDetail", description = "工单明细") public static class WorkOrderDetail { @Schema(description = "Work order info") private ProductionOperationTask workOrder; @Schema(description = "工单信息") private ProductionOperationTaskVo workOrder; @Schema(description = "Report list under current work order") @Schema(description = "报工详情列表") private List<ReportDetail> reportList; } @Data @Schema(name = "ReportDetail", description = "Production report detail") public static class ReportDetail { @Schema(description = "Report main info") private ProductionProductMain reportMain; @Schema(description = "Report output list") private List<ProductionProductOutput> reportOutputList; @Schema(description = "Report process param list") private List<ProductionOrderRoutingOperationParam> reportParamList; @Schema(description = "Inspect list under current report") @Schema(description = "质检详情列表") private List<InspectDetail> inspectList; } @Data @Schema(name = "InspectDetail", description = "Quality inspect detail") @Schema(name = "ReportDetail", description = "报工详情") public static class ReportDetail { @Schema(description = "报工主信息") private ProductionProductMain reportMain; @Schema(description = "报工产出明细") private List<ProductionProductOutput> reportOutputList; @Schema(description = "报工工序参数") private List<ProductionOrderRoutingOperationParam> reportParamList; } @Data @Schema(name = "InspectDetail", description = "质检详情") public static class InspectDetail { @Schema(description = "Inspect main info") @Schema(description = "报工ID") private Long reportId; @Schema(description = "报工单号") private String reportNo; @Schema(description = "报工主信息") private ProductionProductMain reportMain; @Schema(description = "质检主信息") private QualityInspect inspect; @Schema(description = "Inspect param list") @Schema(description = "质检指标明细") private List<QualityInspectParam> inspectParamList; @Schema(description = "Inspect attachment list") @Schema(description = "质检附件列表") private List<QualityInspectFile> inspectFileList; } } src/main/java/com/ruoyi/production/controller/ProductionOperationTaskController.java
@@ -70,14 +70,16 @@ return R.ok(productionOperationTaskService.assign(dto)); } /** * 工单流转卡下载 * @param response * @param dto */ @PostMapping("/down") @Operation(summary = "工单流转卡下载") public void down(HttpServletResponse response, @RequestBody ProductionOperationTaskDto dto) { productionOperationTaskService.down(response, dto); } @GetMapping("/getOperation") @Operation(summary = "工序详情查询") public R<List<ProductionOperationTaskVo>> getOperation(ProductionOperationTaskDto dto) { return R.ok(productionOperationTaskService.getOperation(dto)); } } src/main/java/com/ruoyi/production/controller/ProductionOrderController.java
@@ -84,10 +84,10 @@ return R.ok(productionOrderService.pick(productionOrderId)); } @GetMapping("/workOrder/detail/{productionOrderId}") @Operation(summary = "Query work orders/reports/inspects by production order id") public R<ProductionOrderWorkOrderDetailVo> getWorkOrderReportInspectDetail(@PathVariable Long productionOrderId) { return R.ok(productionOrderService.getWorkOrderReportInspectDetail(productionOrderId)); @GetMapping("/ordeDetail") @Operation(summary = "生产追溯") public R<ProductionOrderWorkOrderDetailVo> getWorkOrderReportInspectDetail(ProductionOrderDto productionOrderDto) { return R.ok(productionOrderService.getWorkOrderReportInspectDetail(productionOrderDto)); } @Operation(summary = "更新订单状态") src/main/java/com/ruoyi/production/mapper/ProductionOperationTaskMapper.java
@@ -41,4 +41,6 @@ @Param("processIds") List<Long> processIds); ProductionOperationTaskDto getProductWorkOrderFlowCard(@Param("id") Long id); List<ProductionOperationTaskVo> getOperation(@Param("c") ProductionOperationTaskDto dto); } src/main/java/com/ruoyi/production/service/ProductionOperationTaskService.java
@@ -28,4 +28,6 @@ boolean assign(ProductionOperationTaskDto dto); void down(HttpServletResponse response, ProductionOperationTaskDto dto); List<ProductionOperationTaskVo> getOperation(ProductionOperationTaskDto dto); } src/main/java/com/ruoyi/production/service/ProductionOrderService.java
@@ -32,7 +32,7 @@ List<ProductionOrderPickVo> pick(Long productionOrderId); ProductionOrderWorkOrderDetailVo getWorkOrderReportInspectDetail(Long productionOrderId); ProductionOrderWorkOrderDetailVo getWorkOrderReportInspectDetail(ProductionOrderDto productionOrderDto); int updateOrder(ProductionOrderDto productionOrderDto); } src/main/java/com/ruoyi/production/service/impl/ProductionOperationTaskServiceImpl.java
@@ -347,4 +347,9 @@ return null; } } @Override public List<ProductionOperationTaskVo> getOperation(ProductionOperationTaskDto dto) { return baseMapper.getOperation(dto); } } src/main/java/com/ruoyi/production/service/impl/ProductionOrderPickServiceImpl.java
@@ -673,8 +673,8 @@ if (dto.getProductModelId() == null) { throw new ServiceException("第" + rowNo + "条产品规格ID不能为空"); } if (dto.getPickQuantity() == null || dto.getPickQuantity().compareTo(BigDecimal.ZERO) <= 0) { throw new ServiceException("第" + rowNo + "条领料数量必须大于0"); if (dto.getPickQuantity() == null || dto.getPickQuantity().compareTo(BigDecimal.ZERO) < 0) { throw new ServiceException("第" + rowNo + "条领料数量不能小于0"); } if (dto.getPickType() != null && dto.getPickType() != PICK_TYPE_NORMAL && dto.getPickType() != PICK_TYPE_FEEDING) { throw new ServiceException("第" + rowNo + "条领料类型只能是1或2"); @@ -688,8 +688,8 @@ if (dto.getId() == null) { throw new ServiceException("第" + rowNo + "条领料ID不能为空"); } if (dto.getFeedingQuantity() == null || dto.getFeedingQuantity().compareTo(BigDecimal.ZERO) <= 0) { throw new ServiceException("第" + rowNo + "条本次补料数量必须大于0"); if (dto.getFeedingQuantity() == null || dto.getFeedingQuantity().compareTo(BigDecimal.ZERO) < 0) { throw new ServiceException("第" + rowNo + "条本次补料数量不能小于0"); } if (!isFeedingPick(dto)) { throw new ServiceException("第" + rowNo + "条补料类型必须为2"); src/main/java/com/ruoyi/production/service/impl/ProductionOrderServiceImpl.java
@@ -14,8 +14,10 @@ import com.ruoyi.basic.utils.FileUtil; import com.ruoyi.common.constant.StorageAttachmentConstants; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.production.bean.dto.ProductionOperationTaskDto; import com.ruoyi.production.bean.dto.ProductionOrderDto; import com.ruoyi.production.bean.vo.ProductionBomStructureVo; import com.ruoyi.production.bean.vo.ProductionOperationTaskVo; import com.ruoyi.production.bean.vo.ProductionOrderPickVo; import com.ruoyi.production.bean.vo.ProductionOrderVo; import com.ruoyi.production.bean.vo.ProductionPlanVo; @@ -681,29 +683,33 @@ } @Override public ProductionOrderWorkOrderDetailVo getWorkOrderReportInspectDetail(Long productionOrderId) { if (productionOrderId == null) { throw new ServiceException("productionOrderId can not be null"); } public ProductionOrderWorkOrderDetailVo getWorkOrderReportInspectDetail(ProductionOrderDto dto) { Long productionOrderId = resolveProductionOrderId(dto); ProductionOrderVo orderInfo = getProductionOrderInfo(productionOrderId); if (orderInfo == null) { throw new ServiceException("production order not found"); throw new ServiceException("生产订单不存在"); } ProductionOrderWorkOrderDetailVo detailVo = new ProductionOrderWorkOrderDetailVo(); detailVo.setProductionOrder(orderInfo); List<ProductionOperationTask> workOrderList = productionOperationTaskMapper.selectList( Wrappers.<ProductionOperationTask>lambdaQuery() .eq(ProductionOperationTask::getProductionOrderId, productionOrderId) .orderByAsc(ProductionOperationTask::getId)); ProductionOperationTaskDto taskQuery = new ProductionOperationTaskDto(); taskQuery.setProductionOrderId(productionOrderId); IPage<ProductionOperationTaskVo> workOrderPage = productionOperationTaskMapper.pageProductionOperationTask( new Page<ProductionOperationTaskVo>(1, -1), taskQuery); List<ProductionOperationTaskVo> workOrderList = workOrderPage == null || workOrderPage.getRecords() == null ? Collections.emptyList() : workOrderPage.getRecords().stream() .filter(Objects::nonNull) .sorted(Comparator.comparing(ProductionOperationTaskVo::getId, Comparator.nullsLast(Comparator.naturalOrder()))) .collect(Collectors.toList()); if (workOrderList == null || workOrderList.isEmpty()) { detailVo.setWorkOrderList(Collections.emptyList()); return detailVo; } List<Long> workOrderIdList = workOrderList.stream() .map(ProductionOperationTask::getId) .map(ProductionOperationTaskVo::getId) .filter(Objects::nonNull) .collect(Collectors.toList()); List<ProductionProductMain> reportMainList = workOrderIdList.isEmpty() @@ -712,12 +718,12 @@ Wrappers.<ProductionProductMain>lambdaQuery() .in(ProductionProductMain::getProductionOperationTaskId, workOrderIdList) .orderByAsc(ProductionProductMain::getId)); Map<Long, List<ProductionProductMain>> reportMainMap = new LinkedHashMap<>(); Map<Long, List<ProductionProductMain>> reportMainByWorkOrderMap = new LinkedHashMap<>(); for (ProductionProductMain reportMain : reportMainList) { if (reportMain == null || reportMain.getProductionOperationTaskId() == null) { continue; } reportMainMap.computeIfAbsent(reportMain.getProductionOperationTaskId(), k -> new ArrayList<>()).add(reportMain); reportMainByWorkOrderMap.computeIfAbsent(reportMain.getProductionOperationTaskId(), key -> new ArrayList<>()).add(reportMain); } List<Long> reportMainIdList = reportMainList.stream() @@ -766,7 +772,7 @@ if (inspect == null || inspect.getProductMainId() == null) { continue; } inspectMap.computeIfAbsent(inspect.getProductMainId(), k -> new ArrayList<>()).add(inspect); inspectMap.computeIfAbsent(inspect.getProductMainId(), key -> new ArrayList<>()).add(inspect); } List<Long> inspectIdList = inspectList.stream() @@ -799,42 +805,44 @@ } List<ProductionOrderWorkOrderDetailVo.WorkOrderDetail> workOrderDetailList = new ArrayList<>(); for (ProductionOperationTask workOrder : workOrderList) { for (ProductionOperationTaskVo workOrder : workOrderList) { ProductionOrderWorkOrderDetailVo.WorkOrderDetail workOrderDetail = new ProductionOrderWorkOrderDetailVo.WorkOrderDetail(); workOrderDetail.setWorkOrder(workOrder); List<ProductionProductMain> workOrderReportMainList = reportMainMap.get(workOrder.getId()); if (workOrderReportMainList == null || workOrderReportMainList.isEmpty()) { List<ProductionProductMain> workOrderReportMainList = reportMainByWorkOrderMap.getOrDefault(workOrder.getId(), Collections.emptyList()); if (workOrderReportMainList.isEmpty()) { workOrderDetail.setReportList(Collections.emptyList()); workOrderDetail.setInspectList(Collections.emptyList()); workOrderDetailList.add(workOrderDetail); continue; } List<ProductionOrderWorkOrderDetailVo.ReportDetail> reportDetailList = new ArrayList<>(); List<ProductionOrderWorkOrderDetailVo.InspectDetail> inspectDetailList = new ArrayList<>(); for (ProductionProductMain reportMain : workOrderReportMainList) { Long reportMainId = reportMain.getId(); ProductionOrderWorkOrderDetailVo.ReportDetail reportDetail = new ProductionOrderWorkOrderDetailVo.ReportDetail(); reportDetail.setReportMain(reportMain); reportDetail.setReportOutputList(reportOutputMap.getOrDefault(reportMainId, Collections.emptyList())); reportDetail.setReportParamList(reportParamMap.getOrDefault(reportMainId, Collections.emptyList())); reportDetailList.add(reportDetail); List<QualityInspect> reportInspectList = inspectMap.get(reportMainId); if (reportInspectList == null || reportInspectList.isEmpty()) { reportDetail.setInspectList(Collections.emptyList()); } else { List<ProductionOrderWorkOrderDetailVo.InspectDetail> inspectDetailList = new ArrayList<>(); List<QualityInspect> reportInspectList = inspectMap.getOrDefault(reportMainId, Collections.emptyList()); for (QualityInspect inspect : reportInspectList) { ProductionOrderWorkOrderDetailVo.InspectDetail inspectDetail = new ProductionOrderWorkOrderDetailVo.InspectDetail(); inspectDetail.setReportId(reportMainId); inspectDetail.setReportNo(reportMain.getProductNo()); inspectDetail.setReportMain(reportMain); inspectDetail.setInspect(inspect); inspectDetail.setInspectParamList(inspectParamMap.getOrDefault(inspect.getId(), Collections.emptyList())); inspectDetail.setInspectFileList(inspectFileMap.getOrDefault(inspect.getId(), Collections.emptyList())); inspectDetailList.add(inspectDetail); } reportDetail.setInspectList(inspectDetailList); } reportDetailList.add(reportDetail); } workOrderDetail.setReportList(reportDetailList); workOrderDetail.setInspectList(inspectDetailList); workOrderDetailList.add(workOrderDetail); } @@ -842,6 +850,26 @@ return detailVo; } private Long resolveProductionOrderId(ProductionOrderDto dto) { if (dto == null) { throw new ServiceException("请传入生产订单ID或生产订单号"); } if (dto.getId() != null) { return dto.getId(); } if (dto.getNpsNo() == null || dto.getNpsNo().trim().isEmpty()) { throw new ServiceException("请传入生产订单ID或生产订单号"); } ProductionOrder productionOrder = baseMapper.selectOne( Wrappers.<ProductionOrder>lambdaQuery() .eq(ProductionOrder::getNpsNo, dto.getNpsNo().trim()) .last("limit 1")); if (productionOrder == null || productionOrder.getId() == null) { throw new ServiceException("生产订单不存在"); } return productionOrder.getId(); } @Override public List<ProductionOrderPickVo> pick(Long productionOrderId) { if (productionOrderId == null) { src/main/resources/mapper/production/ProductionOperationTaskMapper.xml
@@ -29,7 +29,8 @@ pm.model as model, pm.unit as unit, poro.operation_name as operationName, ROUND(pot.complete_quantity / pot.plan_quantity * 100, 2) AS completionStatus, IFNULL(scrapStat.scrapQty, 0) AS scrapQty, ROUND(IFNULL(pot.complete_quantity, 0) / NULLIF(pot.plan_quantity, 0) * 100, 2) AS completionStatus, CASE WHEN pot.work_order_no LIKE 'FG%' THEN '返工返修' ELSE '正常' @@ -39,9 +40,19 @@ left join production_order_routing_operation poro on pot.production_order_routing_operation_id = poro.id left join product_model pm on pm.id = ifnull(poro.product_model_id, po.product_model_id) left join product p on pm.product_id = p.id left join ( select ppm.production_operation_task_id as taskId, sum(ifnull(ppo.scrap_qty, 0)) as scrapQty from production_product_main ppm left join production_product_output ppo on ppo.production_product_main_id = ppm.id group by ppm.production_operation_task_id ) scrapStat on scrapStat.taskId = pot.id <where> <if test="c != null and c.id != null"> and pot.id = #{c.id} </if> <if test="c != null and c.npsNo != null"> and po.nps_no like concat('%', #{c.npsNo}, '%') </if> <if test="c != null and c.productionOrderId != null"> and pot.production_order_id = #{c.productionOrderId} @@ -145,4 +156,58 @@ WHERE pot.id = #{id} </select> <select id="getOperation" resultType="com.ruoyi.production.bean.vo.ProductionOperationTaskVo"> select poro.operation_name as operationName, count(pot.id) as productionTaskCount, sum(ifnull(pot.plan_quantity, 0)) as planQuantity, sum(ifnull(pot.complete_quantity, 0)) as completeQuantity, sum(ifnull(pot.complete_quantity, 0)) as goodQuantity, sum(ifnull(outputStat.scrapQty, 0)) as scrapQty, round( case when sum(ifnull(pot.plan_quantity, 0)) = 0 then 0 else (sum(ifnull(pot.complete_quantity, 0)) + sum(ifnull(outputStat.scrapQty, 0))) / sum(ifnull(pot.plan_quantity, 0)) * 100 end, 2 ) as completionStatus from production_operation_task pot left join production_order_routing_operation poro on pot.production_order_routing_operation_id = poro.id left join ( select ppm.production_operation_task_id as taskId, sum(ifnull(ppo.scrap_qty, 0)) as scrapQty from production_product_main ppm left join production_product_output ppo on ppo.production_product_main_id = ppm.id group by ppm.production_operation_task_id ) outputStat on outputStat.taskId = pot.id <where> <if test="c != null and c.startDate != null"> and date(pot.create_time) >= #{c.startDate} </if> <if test="c != null and c.endDate != null"> and date(pot.create_time) <= #{c.endDate} </if> <if test="c != null and c.planStartTime != null"> and pot.plan_start_time >= #{c.planStartTime} </if> <if test="c != null and c.planEndTime != null"> and pot.plan_end_time <= #{c.planEndTime} </if> <if test="c != null and c.productionOrderId != null"> and pot.production_order_id = #{c.productionOrderId} </if> <if test="c != null and c.productionOrderRoutingOperationId != null"> and pot.production_order_routing_operation_id = #{c.productionOrderRoutingOperationId} </if> <if test="c != null and c.status != null"> and pot.status = #{c.status} </if> <if test="c != null and c.processName != null and c.processName != ''"> and poro.operation_name like concat('%', #{c.processName}, '%') </if> </where> group by poro.operation_name order by min(poro.drag_sort), poro.operation_name </select> </mapper> src/main/resources/mapper/production/ProductionOrderMapper.xml
@@ -27,6 +27,7 @@ <result column="productName" property="productName" /> <result column="model" property="model" /> <result column="processRouteCode" property="processRouteCode" /> <result column="returned" property="returned" /> </resultMap> <sql id="ProductionOrderVoColumns"> @@ -52,7 +53,8 @@ po.is_end_order as endOrder, tr.process_route_code as processRouteCode, ROUND(po.complete_quantity / po.quantity * 100, 2) AS completionStatus, tb.bom_no as bomNo tb.bom_no as bomNo, pop_return.returned as returned </sql> <sql id="ProductionOrderVoFrom"> @@ -73,6 +75,12 @@ left join product p on pm.product_id = p.id left join technology_routing tr on po.technology_routing_id = tr.id left join technology_bom tb on tb.id = tr.bom_id left join ( select production_order_id as productionOrderId, if(max(case when ifnull(is_returned, 0) = 1 then 1 else 0 end) = 1, true, false) as returned from production_order_pick group by production_order_id ) pop_return on pop_return.productionOrderId = po.id </sql> <sql id="ProductionOrderWhere">