src/main/java/com/ruoyi/basic/pojo/ProductModel.java
@@ -2,11 +2,13 @@ import com.baomidou.mybatisplus.annotation.*; import com.ruoyi.framework.aspectj.lang.annotation.Excel; import com.ruoyi.sales.pojo.CommonFile; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.math.BigDecimal; import java.time.LocalDateTime; import java.util.List; @Data @TableName("product_model") @@ -14,6 +16,9 @@ private static final long serialVersionUID = 1L; @TableField(exist = false) private List<CommonFile> SalesLedgerFiles; /** * 序号 */ src/main/java/com/ruoyi/basic/service/IProductService.java
@@ -23,4 +23,5 @@ IPage<ProductModel> listPageProductModel(Page<ProductModel> page, ProductModel productModel); AjaxResult listPage(Page page, ProductAndModelDto productDto); } src/main/java/com/ruoyi/basic/service/impl/ProductModelServiceImpl.java
@@ -12,6 +12,7 @@ import com.ruoyi.basic.pojo.ProductModel; import com.ruoyi.basic.service.IProductModelService; import com.ruoyi.common.enums.FileNameType; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.utils.OrderUtils; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.bean.BeanUtils; @@ -199,7 +200,7 @@ // 查询所有工艺路线 List<ProductProcess> productRoutes = productProcessMapper.selectList(new QueryWrapper<ProductProcess>()); if(CollectionUtils.isEmpty(productRoutes)){ throw new RuntimeException("请先创建产品工艺路线"); throw new ServiceException("请先创建产品工艺路线"); } for (ProductModelExcelCopyDto dto : dtoList) { // 查询条件:型号+图纸编号(更精准,符合分组逻辑) src/main/java/com/ruoyi/basic/service/impl/ProductServiceImpl.java
@@ -64,7 +64,11 @@ @Override public IPage<ProductModel> listPageProductModel(Page<ProductModel> page, ProductModel productModel) { return productModelMapper.listPageProductModel(page, productModel); IPage<ProductModel> productModelIPage = productModelMapper.listPageProductModel(page, productModel); productModelIPage.getRecords().forEach(item -> { item.setSalesLedgerFiles(commonFileService.getFileListByBusinessId(item.getId(), FileNameType.PRODUCT_MODEL.getValue())); }); return productModelIPage; } @Override src/main/java/com/ruoyi/common/enums/StockInQualifiedRecordTypeEnum.java
@@ -12,7 +12,8 @@ PURCHASE_STOCK_IN("7", "采购-入库"), QUALITYINSPECT_STOCK_IN("6", "质检-合格入库"), DEFECTIVE_PASS("11", "不合格-让步放行"), RETURN_HE_IN("14", "销售退货-合格入库"); RETURN_HE_IN("14", "销售退货-合格入库"), RETURN_MATERIAL_IN("15", "退料-入库"); private final String code; src/main/java/com/ruoyi/production/controller/ProductionProductInputController.java
@@ -3,14 +3,17 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ruoyi.framework.web.domain.R; import com.ruoyi.production.dto.ProductionProductInputDto; import com.ruoyi.production.pojo.ProductionProductInput; import com.ruoyi.production.service.ProductionProductInputService; import io.swagger.annotations.Api; import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.*; @RequestMapping("productionProductInput") import java.util.List; @RequestMapping("/productionProductInput") @RestController @Api(value = "生产投入") public class ProductionProductInputController { @@ -18,8 +21,16 @@ @Autowired private ProductionProductInputService productionProductInputService; @GetMapping("listPage") @GetMapping("/listPage") public R page(Page<ProductionProductInputDto> page, ProductionProductInputDto productionProductInputDto) { return R.ok(productionProductInputService.listPageProductionProductInputDto(page, productionProductInputDto)); } @ApiOperation(value = "退料") @PostMapping("/returnMaterial") @Transactional(rollbackFor = Exception.class) public R returnMaterial(@RequestBody List<ProductionProductInput> productionProductInput) { return R.ok(productionProductInputService.returnMaterial(productionProductInput)); } } src/main/java/com/ruoyi/production/dto/ProductOrderDto.java
@@ -5,12 +5,14 @@ import com.fasterxml.jackson.annotation.JsonFormat; import com.ruoyi.framework.aspectj.lang.annotation.Excel; import com.ruoyi.production.pojo.ProductOrder; import com.ruoyi.production.pojo.ProductWorkOrder; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import org.springframework.format.annotation.DateTimeFormat; import java.math.BigDecimal; import java.time.LocalDate; import java.util.List; @Data @ExcelIgnoreUnannotated @@ -68,4 +70,7 @@ @ApiModelProperty(value = "操作 1-开始 2-暂停") private Integer operation; @ApiModelProperty(value = "生产任务") private List<ProductWorkOrderDto> productWorkOrders; } src/main/java/com/ruoyi/production/mapper/ProductWorkOrderMapper.java
@@ -17,6 +17,8 @@ IPage<ProductWorkOrderDto> pageProductWorkOrder(Page<ProductWorkOrderDto> page, @Param("c") ProductWorkOrderDto productWorkOrder); List<ProductWorkOrderDto> getProductWorkOrderList(@Param("c") ProductWorkOrderDto productWorkOrder); ProductWorkOrderDto getProductWorkOrderFlowCard(@Param("id") Long id); List<ProductWorkOrderDto> selectWorkOrderStartStats(@Param("startDate") String startDate, @Param("endDate") String endDate); src/main/java/com/ruoyi/production/pojo/ProductWorkOrder.java
@@ -11,6 +11,7 @@ import java.math.BigDecimal; import java.time.LocalDate; import java.time.LocalDateTime; import java.util.List; /** * 产品工单实体类 @@ -20,8 +21,16 @@ @TableName("product_work_order") public class ProductWorkOrder implements Serializable { private static final long serialVersionUID = 1L; @TableField(exist = false) @ApiModelProperty(value = "颜色 1-灰色 2-黄色 3-绿色 4-红色") private Integer color; /** * 主键id */ src/main/java/com/ruoyi/production/pojo/ProductionProductInput.java
@@ -26,6 +26,9 @@ @ApiModelProperty(value = "数量") private BigDecimal quantity; @ApiModelProperty(value = "退料数量") private BigDecimal returnQuantity; @ApiModelProperty(value = "创建时间") @TableField(fill = FieldFill.INSERT) private LocalDateTime createTime; src/main/java/com/ruoyi/production/service/ProductionProductInputService.java
@@ -6,6 +6,10 @@ import com.ruoyi.production.dto.ProductionProductInputDto; import com.ruoyi.production.pojo.ProductionProductInput; import java.util.List; public interface ProductionProductInputService extends IService<ProductionProductInput> { IPage<ProductionProductInputDto> listPageProductionProductInputDto(Page page, ProductionProductInputDto productionProductInputDto); Object returnMaterial(List<ProductionProductInput> productionProductInput); } src/main/java/com/ruoyi/production/service/impl/ProductBomServiceImpl.java
@@ -269,14 +269,14 @@ } private ProductModel findModel(String name, String spec) { Product product = productService.getOne(new LambdaQueryWrapper<Product>() .eq(Product::getProductName, name).last("limit 1")); if (product == null) throw new ServiceException("产品未维护:" + name); // Product product = productService.getOne(new LambdaQueryWrapper<Product>() // .eq(Product::getProductName, name).last("limit 1")); // if (product == null) throw new ServiceException("产品未维护:" + name); ProductModel model = productModelService.getOne(new LambdaQueryWrapper<ProductModel>() .eq(ProductModel::getProductId, product.getId()) // .eq(ProductModel::getProductId, product.getId()) .eq(ProductModel::getModel, spec).last("limit 1")); if (model == null) throw new ServiceException("规格未维护:" + name + "[" + spec + "]"); if (model == null) throw new ServiceException("图纸编号未维护:" + name + "[" + spec + "]"); return model; } src/main/java/com/ruoyi/production/service/impl/ProductOrderServiceImpl.java
@@ -15,6 +15,7 @@ import com.ruoyi.procurementrecord.utils.StockUtils; import com.ruoyi.production.dto.ProductOrderDto; import com.ruoyi.production.dto.ProductStructureDto; import com.ruoyi.production.dto.ProductWorkOrderDto; import com.ruoyi.production.mapper.*; import com.ruoyi.production.pojo.*; import com.ruoyi.production.service.ProductOrderService; @@ -102,10 +103,73 @@ // 附件 productOrderDto.setSalesLedgerFiles(commonFileService.getFileListByBusinessId(productOrderDto.getId() , FileNameType.PRODUCT_ORDER.getValue())); // 获取对应工单记录 ProductWorkOrderDto productWorkOrder = new ProductWorkOrderDto(); productWorkOrder.setProductOrderId(productOrderDto.getId()); List<ProductWorkOrderDto> productWorkOrders = productWorkOrderMapper.getProductWorkOrderList(productWorkOrder); if(CollectionUtils.isNotEmpty(productWorkOrders)){ productOrderDto.setProductWorkOrders(calculateColor(productWorkOrders)); } }); return productOrderDtoIPage; } /** * 自动计算颜色(核心方法) * @param productWorkOrders */ public List<ProductWorkOrderDto> calculateColor(List<ProductWorkOrderDto> productWorkOrders) { List<ProductWorkOrderDto> result = new java.util.ArrayList<>(); for (int i = 0; i < productWorkOrders.size(); i++) { ProductWorkOrderDto current = productWorkOrders.get(i); // 判断是否存在下一道工单 + 下一道工单是否有完成数量 boolean nextOrderHasComplete = false; // 黄色 boolean nextOrderHasScrap = false; // 红色 // 如果不是最后一条,就取下一条判断 for (int j = i + 1; j < productWorkOrders.size(); j++) { if (i < productWorkOrders.size() - 1) { ProductWorkOrderDto next = productWorkOrders.get(j); BigDecimal nextComplete = next.getCompleteQuantity() == null ? BigDecimal.ZERO : next.getCompleteQuantity(); BigDecimal nextScrap = next.getPlanQuantity() == null ? BigDecimal.ZERO : next.getPlanQuantity(); // 下一道工单完成数量 > 0 nextOrderHasComplete = nextComplete.compareTo(BigDecimal.ZERO) > 0; nextOrderHasScrap = nextComplete.compareTo(nextScrap) == 0; break; } } // =============== 核心:计算颜色并赋值 =============== BigDecimal planQty = current.getPlanQuantity() == null ? BigDecimal.ZERO : current.getPlanQuantity(); BigDecimal completeQty = current.getCompleteQuantity() == null ? BigDecimal.ZERO : current.getCompleteQuantity(); // 1. 当前工序完成数量等于0 且 下一道工序已完成 → 红色(4) if (completeQty.compareTo(BigDecimal.ZERO) == 0 && nextOrderHasScrap) { current.setColor(4); } // 2. 需求数量 > 完成数量(未完成) 且 下一道工序完成数量 > 0 → 黄色(2) else if (planQty.compareTo(completeQty) > 0 && nextOrderHasComplete) { current.setColor(2); } // 3. 完成数量=0 → 灰色(1) else if (completeQty.compareTo(BigDecimal.ZERO) == 0) { current.setColor(1); } // 4. 完成数量=需求数量 → 绿色(3) else if (completeQty.compareTo(planQty) == 0) { current.setColor(3); } // 其他情况默认灰色(可选) else { current.setColor(1); } result.add(current); } return result; } @Override public int bindingRoute(ProductOrder productOrder) { //新增生产订单下的工艺路线主表 src/main/java/com/ruoyi/production/service/impl/ProductionProductInputServiceImpl.java
@@ -1,15 +1,24 @@ package com.ruoyi.production.service.impl; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum; import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum; import com.ruoyi.procurementrecord.utils.StockUtils; import com.ruoyi.production.dto.ProductionProductInputDto; import com.ruoyi.production.mapper.ProductStructureRecordMapper; import com.ruoyi.production.mapper.ProductionProductInputMapper; import com.ruoyi.production.pojo.ProductStructureRecord; import com.ruoyi.production.pojo.ProductionProductInput; import com.ruoyi.production.service.ProductionProductInputService; import lombok.AllArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.math.BigDecimal; import java.util.List; @Service @AllArgsConstructor @@ -17,8 +26,37 @@ @Autowired private ProductionProductInputMapper productionProductInputMapper; @Autowired private StockUtils stockUtils; @Autowired private ProductStructureRecordMapper productStructureRecordMapper; @Override public IPage<ProductionProductInputDto> listPageProductionProductInputDto(Page page, ProductionProductInputDto productionProductInputDto) { return productionProductInputMapper.listPageProductionProductInputDto(page, productionProductInputDto); } @Override public Object returnMaterial(List<ProductionProductInput> productionProductInput) { if(CollectionUtils.isEmpty(productionProductInput)){ return "请选择要退料的数据"; } for (ProductionProductInput input : productionProductInput) { ProductionProductInput productionProductInput1 = productionProductInputMapper.selectById(input.getId()); BigDecimal qty = input.getReturnQuantity() == null ? BigDecimal.ZERO : input.getReturnQuantity(); BigDecimal qty1 = productionProductInput1.getReturnQuantity() == null ? BigDecimal.ZERO : productionProductInput1.getReturnQuantity(); productionProductInput1.setReturnQuantity(qty.add(qty1)); productionProductInputMapper.updateById(productionProductInput1); // 退料入库 stockUtils.addStock(input.getProductModelId(), input.getReturnQuantity(), StockInQualifiedRecordTypeEnum.RETURN_MATERIAL_IN.getCode(), input.getId()); // 增加物料清单 ProductStructureRecord productStructureRecord = productStructureRecordMapper.selectById(input.getProductStructureRecordId()); if(productStructureRecord != null){ productStructureRecord.setCompletedQuantity(productStructureRecord.getCompletedQuantity().subtract(qty)); productStructureRecordMapper.updateById(productStructureRecord); } } return "退料成功"; } } src/main/resources/mapper/production/ProductWorkOrderMapper.xml
@@ -97,4 +97,38 @@ limit 1 ; </select> <select id="getProductWorkOrderList" resultType="com.ruoyi.production.dto.ProductWorkOrderDto" parameterType="com.ruoyi.production.dto.ProductWorkOrderDto"> SELECT pwo.*, pp.NAME as processName, pm.model, pm.unit, p.product_name AS productName, pm.drawing_number, po.nps_no AS productOrderNpsNo, ROUND(pwo.complete_quantity / pwo.plan_quantity * 100, 2) AS completionStatus, CASE WHEN pwo.work_order_no LIKE 'FG%' THEN '返工返修' ELSE '正常' END AS work_order_type FROM product_work_order pwo LEFT JOIN product_process_route_item ppri ON ppri.id = pwo.product_process_route_item_id LEFT JOIN product_order po ON po.id = pwo.product_order_id LEFT JOIN product_process pp ON pp.id = ppri.process_id LEFT JOIN product_model pm ON pm.id = ppri.product_model_id LEFT JOIN product p ON p.id = pm.product_id <where> <if test="c.workOrderNo != null and c.workOrderNo != ''"> and pwo.work_order_no like concat('%',#{c.workOrderNo},'%') </if> <if test="c.planStartTime != null and c.planEndTime != null"> and DATE(pwo.create_time) between #{c.planStartTime} and #{c.planEndTime} </if> <if test="c.productOrderId != null and c.productOrderId != ''"> and pwo.product_order_id = #{c.productOrderId} </if> </where> </select> </mapper>