chenhj
2026-04-22 2ab6b6860e4f7bee67a0f66831b9b1fb0f420710
Merge branch 'dev_New_pro' of http://114.132.189.42:9002/r/product-inventory-management-after into dev_New_pro
已添加24个文件
已修改62个文件
已删除14个文件
5255 ■■■■■ 文件已修改
src/main/java/com/ruoyi/basic/dto/ProductModelDto.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/home/dto/ProductionProgressDto.java 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/home/dto/ProductionProgressOrderDto.java 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/home/dto/ProductionTaskStatisticsDto.java 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/home/dto/ProductionTurnoverDto.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java 120 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/bean/dto/BomImportDto.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/bean/dto/ProductStructureDto.java 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/bean/dto/ProductionOperationTaskDto.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/bean/dto/ProductionOrderDto.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/bean/dto/ProductionOrderRoutingOperationParamDto.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/bean/dto/ProductionOrderRoutingOperationParamSyncDto.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/bean/dto/ProductionPlanDto.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/bean/dto/ProductionProductInputDto.java 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/bean/dto/ProductionProductMainDto.java 39 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/bean/dto/ProductionProductOutputDto.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/bean/dto/SalesLedgerProductionAccountingDto.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/bean/dto/UserAccountDto.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/bean/dto/UserProductionAccountingDto.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/bean/vo/ProductionOperationTaskVo.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/bean/vo/ProductionOrderRoutingOperationParamVo.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/bean/vo/ProductionOrderVo.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/controller/ProductionOperationTaskController.java 64 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/controller/ProductionOrderController.java 70 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/controller/ProductionOrderRoutingController.java 58 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/controller/ProductionOrderRoutingOperationParamController.java 70 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/controller/ProductionPlanController.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/controller/ProductionProductInputController.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/controller/ProductionProductMainController.java 96 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/controller/ProductionProductOutputController.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/enums/ProductOrderStatusEnum.java 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/mapper/ProductionAccountMapper.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/mapper/ProductionOperationTaskMapper.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/mapper/ProductionOrderMapper.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/mapper/ProductionPlanMapper.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/mapper/ProductionProductInputMapper.java 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/mapper/ProductionProductMainMapper.java 34 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/mapper/ProductionProductOutputMapper.java 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/pojo/ProductionOrder.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/pojo/ProductionPlan.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/pojo/ProductionProductInput.java 63 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/pojo/ProductionProductMain.java 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/pojo/ProductionProductOutput.java 67 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/ProductionOperationTaskService.java 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/ProductionOrderRoutingOperationParamService.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/ProductionOrderRoutingOperationService.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/ProductionOrderRoutingService.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/ProductionOrderService.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/ProductionPlanService.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/ProductionProductInputService.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/ProductionProductMainService.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/ProductionProductOutputService.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/SalesLedgerProductionAccountingService.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/ProductionOperationTaskServiceImpl.java 64 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/ProductionOrderRoutingOperationParamServiceImpl.java 208 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/ProductionOrderRoutingOperationServiceImpl.java 140 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/ProductionOrderRoutingServiceImpl.java 35 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/ProductionOrderServiceImpl.java 313 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/ProductionPlanServiceImpl.java 623 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/ProductionProductInputServiceImpl.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java 345 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/ProductionProductOutputServiceImpl.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/SalesLedgerProductionAccountingServiceImpl.java 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/quality/service/impl/QualityReportServiceImpl.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/quality/service/impl/QualityUnqualifiedServiceImpl.java 221 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/safe/controller/SafeCertificationController.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/safe/controller/SafeCertificationFileController.java 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/safe/service/impl/SafeTrainingServiceImpl.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java 293 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/staff/service/impl/SchemeApplicableStaffServiceImpl.java 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/technology/bean/dto/BomImportDto.java 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/technology/bean/dto/TechnologyRoutingOperationParamDto.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/technology/bean/dto/TechnologyRoutingOperationParamSyncDto.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/technology/bean/vo/TechnologyRoutingOperationParamVo.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/technology/controller/TechnologyBomController.java 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/technology/service/TechnologyBomService.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/technology/service/impl/TechnologyBomServiceImpl.java 21 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/application.yml 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProcessRouteItemMapper.xml 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProcessRouteMapper.xml 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProductBomMapper.xml 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProductOrderMapper.xml 113 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProductOrderMaterialMapper.xml 116 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProductProcessMapper.xml 54 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProductProcessRouteItemMapper.xml 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProductProcessRouteMapper.xml 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProductStructureMapper.xml 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProductWorkOrderFileMapper.xml 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProductWorkOrderMapper.xml 98 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProductionAccountMapper.xml 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProductionOperationTaskMapper.xml 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProductionOrderMapper.xml 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProductionPlanMapper.xml 98 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProductionProductInputMapper.xml 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProductionProductMainMapper.xml 93 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProductionProductOutputMapper.xml 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/SalesLedgerProductionAccountingMapper.xml 122 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/SalesLedgerSchedulingMapper.xml 121 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/SalesLedgerWorkMapper.xml 59 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/dto/ProductModelDto.java
@@ -1,7 +1,7 @@
package com.ruoyi.basic.dto;
import com.ruoyi.basic.pojo.ProductModel;
import com.ruoyi.production.dto.ProductStructureDto;
import com.ruoyi.production.bean.dto.ProductStructureDto;
import lombok.Data;
import java.util.List;
src/main/java/com/ruoyi/home/dto/ProductionProgressDto.java
@@ -1,11 +1,8 @@
package com.ruoyi.home.dto;
import com.ruoyi.production.dto.ProductOrderDto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.util.List;
@Data
@@ -21,5 +18,5 @@
    @ApiModelProperty("部分完成订单数")
    private Long partialCompletedOrderCount;
    @ApiModelProperty("订单详情")
    private List<ProductOrderDto> completedOrderDetails;
    private List<ProductionProgressOrderDto> completedOrderDetails;
}
src/main/java/com/ruoyi/home/dto/ProductionProgressOrderDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,57 @@
package com.ruoyi.home.dto;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.math.BigDecimal;
import java.time.LocalDate;
@Data
public class ProductionProgressOrderDto {
    @ApiModelProperty("生产订单号")
    private String npsNo;
    @ApiModelProperty("销售合同号")
    private String salesContractNo;
    @ApiModelProperty("项目名称")
    private String projectName;
    @ApiModelProperty("客户名称")
    private String customerName;
    @ApiModelProperty("产品名称")
    private String productCategory;
    @ApiModelProperty("规格型号")
    private String specificationModel;
    @ApiModelProperty("工艺路线编号")
    private String processRouteCode;
    @ApiModelProperty("需求数量")
    private BigDecimal quantity;
    @ApiModelProperty("完成数量")
    private BigDecimal completeQuantity;
    @ApiModelProperty("完成进度")
    private BigDecimal completionStatus;
    @ApiModelProperty("BOM编号")
    private String bomNo;
    @ApiModelProperty("交期偏差")
    private Integer deliveryDaysDiff;
    @ApiModelProperty("交期")
    @JsonFormat(pattern = "yyyy-MM-dd")
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private LocalDate deliveryDate;
    @ApiModelProperty("是否发货")
    private Boolean isFh;
}
src/main/java/com/ruoyi/home/dto/ProductionTaskStatisticsDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,50 @@
package com.ruoyi.home.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDate;
@Data
public class ProductionTaskStatisticsDto {
    @ApiModelProperty("工单ID")
    private Long id;
    @ApiModelProperty("工单编号")
    private String workOrderNo;
    @ApiModelProperty("计划开始时间")
    private LocalDate planStartTime;
    @ApiModelProperty("计划结束时间")
    private LocalDate planEndTime;
    @ApiModelProperty("实际开始时间")
    private LocalDate actualStartTime;
    @ApiModelProperty("实际结束时间")
    private LocalDate actualEndTime;
    @ApiModelProperty("计划数量")
    private BigDecimal planQuantity;
    @ApiModelProperty("完成数量")
    private BigDecimal completeQuantity;
    @ApiModelProperty("工序名称")
    private String processName;
    @ApiModelProperty("产品名称")
    private String productName;
    @ApiModelProperty("规格型号")
    private String model;
    @ApiModelProperty("单位")
    private String unit;
    @ApiModelProperty("生产订单号")
    private String productOrderNpsNo;
}
src/main/java/com/ruoyi/home/dto/ProductionTurnoverDto.java
@@ -1,6 +1,4 @@
package com.ruoyi.home.dto;
import com.ruoyi.production.dto.ProductOrderDto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java
@@ -3,16 +3,13 @@
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.account.mapper.AccountExpenseMapper;
import com.ruoyi.account.mapper.AccountIncomeMapper;
import com.ruoyi.account.pojo.AccountExpense;
import com.ruoyi.home.mapper.HomeMapper;
import com.ruoyi.account.mapper.AccountExpenseMapper;
import com.ruoyi.approve.mapper.ApproveProcessMapper;
import com.ruoyi.approve.pojo.ApproveProcess;
import com.ruoyi.basic.mapper.CustomerMapper;
import com.ruoyi.basic.mapper.ProductMapper;
import com.ruoyi.basic.mapper.ProductModelMapper;
import com.ruoyi.basic.mapper.SupplierManageMapper;
import com.ruoyi.basic.pojo.Customer;
import com.ruoyi.basic.pojo.Product;
@@ -27,20 +24,10 @@
import com.ruoyi.dto.MapDto;
import com.ruoyi.framework.security.LoginUser;
import com.ruoyi.home.dto.*;
import com.ruoyi.home.mapper.HomeMapper;
import com.ruoyi.home.service.HomeService;
import com.ruoyi.procurementrecord.mapper.ProcurementRecordMapper;
import com.ruoyi.procurementrecord.pojo.ProcurementRecordStorage;
import com.ruoyi.procurementrecord.utils.StockUtils;
import com.ruoyi.production.dto.ProductOrderDto;
import com.ruoyi.production.dto.ProductWorkOrderDto;
import com.ruoyi.production.mapper.ProductOrderMapper;
import com.ruoyi.production.mapper.ProductProcessMapper;
import com.ruoyi.production.mapper.ProductWorkOrderMapper;
import com.ruoyi.production.mapper.ProductionProductInputMapper;
import com.ruoyi.production.mapper.ProductionProductOutputMapper;
import com.ruoyi.production.mapper.SalesLedgerProductionAccountingMapper;
import com.ruoyi.production.pojo.ProductProcess;
import com.ruoyi.production.pojo.ProductWorkOrder;
import com.ruoyi.production.bean.dto.ProductionProductOutputDto;
import com.ruoyi.production.mapper.*;
import com.ruoyi.project.system.domain.SysDept;
import com.ruoyi.project.system.mapper.SysDeptMapper;
import com.ruoyi.purchase.mapper.PaymentRegistrationMapper;
@@ -114,10 +101,7 @@
    private NoticeMapper noticeMapper;
    @Autowired
    private ProductOrderMapper productOrderMapper;
    @Autowired
    private ProductWorkOrderMapper productWorkOrderMapper;
    private ProductionOrderMapper productionOrderMapper;
    @Autowired
    private ProductMapper productMapper;
@@ -144,7 +128,7 @@
    private QualityUnqualifiedMapper qualityUnqualifiedMapper;
    @Autowired
    private ProductProcessMapper productProcessMapper;
    private ProductionOperationTaskMapper productionOperationTaskMapper;
    
    @Autowired
    private AccountExpenseMapper accountExpenseMapper;
@@ -560,18 +544,15 @@
    @Override
    public ProductionProgressDto productionProgress() {
        ProductionProgressDto productionProgressDto = new ProductionProgressDto();
        ProductOrderDto orderDto = new ProductOrderDto();
        orderDto.setStartTime(LocalDateTime.now().minusMonths(1));
        orderDto.setEndTime(LocalDateTime.now());
        List<ProductOrderDto> productOrderDtos = productOrderMapper.pageProductOrder(new Page<>(1, -1), orderDto)
                .getRecords();
        productionProgressDto.setCompletedOrderDetails(productOrderDtos);
        long totalCount = productOrderDtos.size();
        long count = productOrderDtos.stream().filter(
                        productOrderDto -> productOrderDto.getCompleteQuantity().compareTo(productOrderDto.getQuantity()) >= 0)
        List<ProductionProgressOrderDto> orderDetails = productionOrderMapper.selectProgressOrders(
                LocalDateTime.now().minusMonths(1), LocalDateTime.now());
        productionProgressDto.setCompletedOrderDetails(orderDetails);
        long totalCount = orderDetails.size();
        long count = orderDetails.stream().filter(
                        item -> defaultDecimal(item.getCompleteQuantity()).compareTo(defaultDecimal(item.getQuantity())) >= 0)
                .count();
        long count2 = productOrderDtos.stream()
                .filter(productOrderDto -> productOrderDto.getCompleteQuantity().compareTo(BigDecimal.ZERO) == 0)
        long count2 = orderDetails.stream()
                .filter(item -> defaultDecimal(item.getCompleteQuantity()).compareTo(BigDecimal.ZERO) == 0)
                .count();
        productionProgressDto.setTotalOrderCount(totalCount);
        productionProgressDto.setCompletedOrderCount(count);
@@ -583,15 +564,11 @@
    @Override
    public ProductionTurnoverDto workInProcessTurnover() {
        ProductionTurnoverDto productionTurnoverDto = new ProductionTurnoverDto();
        ProductWorkOrderDto workOrder = new ProductWorkOrderDto();
        workOrder.setPlanStartTime(LocalDate.now().minusMonths(1));
        workOrder.setPlanEndTime(LocalDate.now());
        List<ProductWorkOrderDto> productWorkOrders = productWorkOrderMapper
                .pageProductWorkOrder(new Page<>(1, -1), workOrder).getRecords();
        long sum = productWorkOrders.stream()
                .filter(productWorkOrder -> productWorkOrder.getPlanQuantity()
                        .compareTo(productWorkOrder.getCompleteQuantity()) > 0)
                .map(ProductWorkOrder::getPlanQuantity)
        List<ProductionTaskStatisticsDto> taskList = productionOperationTaskMapper
                .selectTaskStatisticsByDate(LocalDate.now().minusMonths(1), LocalDate.now());
        long sum = taskList.stream()
                .filter(task -> defaultDecimal(task.getPlanQuantity()).compareTo(defaultDecimal(task.getCompleteQuantity())) > 0)
                .map(ProductionTaskStatisticsDto::getPlanQuantity)
                .mapToLong(BigDecimal::longValue)
                .sum();
        if (sum == 0)
@@ -600,23 +577,21 @@
        productionTurnoverDto.setAverageTurnoverDays(BigDecimal.valueOf(sum).divide(
                BigDecimal.valueOf(ChronoUnit.DAYS.between(LocalDateTime.now().minusMonths(1), LocalDateTime.now())), 2,
                RoundingMode.HALF_UP));
        long completeQuantity = productWorkOrders.stream()
                .filter(productWorkOrder -> productWorkOrder.getCompleteQuantity()
                        .compareTo(productWorkOrder.getPlanQuantity()) >= 0)
                .map(ProductWorkOrder::getCompleteQuantity)
        long completeQuantity = taskList.stream()
                .filter(task -> defaultDecimal(task.getCompleteQuantity()).compareTo(defaultDecimal(task.getPlanQuantity())) >= 0)
                .map(ProductionTaskStatisticsDto::getCompleteQuantity)
                .mapToLong(BigDecimal::longValue)
                .sum();
        productionTurnoverDto.setTurnoverEfficiency(
                BigDecimal.valueOf(completeQuantity).divide(BigDecimal.valueOf(sum), 2, RoundingMode.HALF_UP));
        Map<String, List<ProductWorkOrderDto>> map = productWorkOrders.stream()
                .filter(productWorkOrder -> productWorkOrder.getPlanQuantity()
                        .compareTo(productWorkOrder.getCompleteQuantity()) > 0)
                .collect(Collectors.groupingBy(ProductWorkOrderDto::getProcessName));
        Map<String, List<ProductionTaskStatisticsDto>> map = taskList.stream()
                .filter(task -> defaultDecimal(task.getPlanQuantity()).compareTo(defaultDecimal(task.getCompleteQuantity())) > 0)
                .collect(Collectors.groupingBy(ProductionTaskStatisticsDto::getProcessName));
        List<String> strings = new ArrayList<>();
        List<Long> processQuantityDetails = new ArrayList<>();
        map.entrySet().stream().forEach(entry -> {
            String key = entry.getKey();
            long completeSum = entry.getValue().stream().map(ProductWorkOrderDto::getCompleteQuantity)
            long completeSum = entry.getValue().stream().map(ProductionTaskStatisticsDto::getCompleteQuantity)
                    .mapToLong(BigDecimal::longValue).sum();
            strings.add(key);
            processQuantityDetails.add(completeSum);
@@ -1610,12 +1585,7 @@
                break;
        }
        ProductWorkOrderDto queryDto = new ProductWorkOrderDto();
        queryDto.setPlanStartTime(startDate);
        queryDto.setPlanEndTime(endDate);
        List<ProductWorkOrderDto> list = productWorkOrderMapper.pageProductWorkOrder(new Page<>(1, -1), queryDto)
                .getRecords();
        List<ProductionTaskStatisticsDto> list = productionOperationTaskMapper.selectTaskStatisticsByDate(startDate, endDate);
        if (CollectionUtils.isEmpty(list)) {
            return new ArrayList<>();
@@ -1624,9 +1594,9 @@
        Map<String, BigDecimal> processOutputMap = list.stream()
                .filter(item -> item.getProcessName() != null && item.getCompleteQuantity() != null)
                .collect(Collectors.groupingBy(
                        ProductWorkOrderDto::getProcessName,
                        ProductionTaskStatisticsDto::getProcessName,
                        Collectors.reducing(BigDecimal.ZERO,
                                ProductWorkOrderDto::getCompleteQuantity,
                                ProductionTaskStatisticsDto::getCompleteQuantity,
                                BigDecimal::add)));
        BigDecimal total = processOutputMap.values().stream()
@@ -1680,17 +1650,17 @@
        String startStr = startDate.atStartOfDay().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        String endStr = endDate.atTime(LocalTime.MAX).format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        List<ProductWorkOrderDto> startList = productWorkOrderMapper.selectWorkOrderStartStats(startStr, endStr);
        List<ProductionTaskStatisticsDto> startList = productionOperationTaskMapper.selectTaskStartStats(startStr, endStr);
        List<com.ruoyi.production.dto.ProductionProductOutputDto> outputList = productionProductOutputMapper
        List<ProductionProductOutputDto> outputList = productionProductOutputMapper
                .selectOutputStats(startStr, endStr);
        Map<String, WorkOrderEfficiencyDto> dateMap = new HashMap<>();
        if (!CollectionUtils.isEmpty(startList)) {
            for (ProductWorkOrderDto item : startList) {
                if (item.getPlanStartTime() != null) {
                    String date = item.getPlanStartTime().toString();
            for (ProductionTaskStatisticsDto item : startList) {
                if (item.getActualStartTime() != null) {
                    String date = item.getActualStartTime().toString();
                    WorkOrderEfficiencyDto dto = dateMap.getOrDefault(date, new WorkOrderEfficiencyDto());
                    dto.setDate(date);
                    BigDecimal qty = item.getPlanQuantity() != null ? item.getPlanQuantity() : BigDecimal.ZERO;
@@ -1702,7 +1672,7 @@
        // å®Œå·¥æ•°é‡å’Œè‰¯å“çއ
        if (!CollectionUtils.isEmpty(outputList)) {
            for (com.ruoyi.production.dto.ProductionProductOutputDto item : outputList) {
            for (ProductionProductOutputDto item : outputList) {
                if (item.getCreateTime() != null) {
                    String date = item.getCreateTime().toLocalDate().toString();
                    WorkOrderEfficiencyDto dto = dateMap.getOrDefault(date, new WorkOrderEfficiencyDto());
@@ -1776,7 +1746,7 @@
    }
    @Autowired
    private SalesLedgerProductionAccountingMapper salesLedgerProductionAccountingMapper;
    private ProductionAccountMapper salesLedgerProductionAccountingMapper;
    @Override
    public List<ProductionAccountingDto> productionAccountingAnalysis(Integer type) {
@@ -1841,16 +1811,16 @@
        String lastEnd = lastMonthDate.withDayOfMonth(lastMonthDate.lengthOfMonth()).atTime(LocalTime.MAX)
                .format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
        int currentCreated = productOrderMapper.countCreated(currentStart, currentEnd);
        int lastCreated = productOrderMapper.countCreated(lastStart, lastEnd);
        int currentCreated = productionOrderMapper.countCreated(currentStart, currentEnd);
        int lastCreated = productionOrderMapper.countCreated(lastStart, lastEnd);
        MapDto createdDto = createOrderCountDto("生产订单数", currentCreated, lastCreated);
        int currentCompleted = productOrderMapper.countCompleted(currentStart, currentEnd);
        int lastCompleted = productOrderMapper.countCompleted(lastStart, lastEnd);
        int currentCompleted = productionOrderMapper.countCompleted(currentStart, currentEnd);
        int lastCompleted = productionOrderMapper.countCompleted(lastStart, lastEnd);
        MapDto completedDto = createOrderCountDto("已完成订单数", currentCompleted, lastCompleted);
        int currentPending = productOrderMapper.countPending(currentStart, currentEnd);
        int lastPending = productOrderMapper.countPending(lastStart, lastEnd);
        int currentPending = productionOrderMapper.countPending(currentStart, currentEnd);
        int lastPending = productionOrderMapper.countPending(lastStart, lastEnd);
        MapDto pendingDto = createOrderCountDto("待生产订单数", currentPending, lastPending);
        return Arrays.asList(createdDto, completedDto, pendingDto);
@@ -2510,6 +2480,10 @@
        LocalDateTime startDateTime = startDate.atStartOfDay();
        LocalDateTime endDateTime = endDate.atTime(LocalTime.MAX);
        return productProcessMapper.calculateProductionStatistics(startDateTime, endDateTime, userId, processIds);
        return productionOperationTaskMapper.calculateProductionStatistics(startDateTime, endDateTime, userId, processIds);
    }
    private BigDecimal defaultDecimal(BigDecimal value) {
        return value == null ? BigDecimal.ZERO : value;
    }
}
src/main/java/com/ruoyi/production/bean/dto/BomImportDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,30 @@
package com.ruoyi.production.bean.dto;
import com.ruoyi.framework.aspectj.lang.annotation.Excel;
import lombok.Data;
import java.math.BigDecimal;
@Data
public class BomImportDto {
    @Excel(name = "父产品名称")
    private String parentName;
    @Excel(name = "父产品规格")
    private String parentSpec;
    @Excel(name = "子产品名称")
    private String childName;
    @Excel(name = "子产品规格")
    private String childSpec;
    @Excel(name = "单位用量")
    private BigDecimal unitQty;
    @Excel(name = "工序")
    private String process;
    @Excel(name = "备注")
    private String remark;
}
src/main/java/com/ruoyi/production/bean/dto/ProductStructureDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,21 @@
package com.ruoyi.production.bean.dto;
import lombok.Data;
import java.math.BigDecimal;
import java.util.List;
@Data
public class ProductStructureDto {
    private Long id;
    private Long bomId;
    private Long parentId;
    private Long productModelId;
    private BigDecimal unitQuantity;
    private String unit;
    private Long processId;
    private String processName;
    private String productName;
    private String model;
    private List<ProductStructureDto> children;
}
src/main/java/com/ruoyi/production/bean/dto/ProductionOperationTaskDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,8 @@
package com.ruoyi.production.bean.dto;
import com.ruoyi.production.pojo.ProductionOperationTask;
import lombok.Data;
@Data
public class ProductionOperationTaskDto extends ProductionOperationTask {
}
src/main/java/com/ruoyi/production/bean/dto/ProductionOrderDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,8 @@
package com.ruoyi.production.bean.dto;
import com.ruoyi.production.pojo.ProductionOrder;
import lombok.Data;
@Data
public class ProductionOrderDto extends ProductionOrder {
}
src/main/java/com/ruoyi/production/bean/dto/ProductionOrderRoutingOperationParamDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,8 @@
package com.ruoyi.production.bean.dto;
import com.ruoyi.production.pojo.ProductionOrderRoutingOperationParam;
import lombok.Data;
@Data
public class ProductionOrderRoutingOperationParamDto extends ProductionOrderRoutingOperationParam {
}
src/main/java/com/ruoyi/production/bean/dto/ProductionOrderRoutingOperationParamSyncDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,11 @@
package com.ruoyi.production.bean.dto;
import lombok.Data;
@Data
public class ProductionOrderRoutingOperationParamSyncDto {
    private Long productionOrderRoutingOperationId;
    private Boolean replaceExisting;
}
src/main/java/com/ruoyi/production/bean/dto/ProductionPlanDto.java
@@ -58,4 +58,11 @@
    @ApiModelProperty("关联物料信息表ID")
    private Long productMaterialId;
    /**
     * å¼ºåº¦
     */
    @ApiModelProperty("强度")
    @Excel(name = "强度")
    private String strength;
}
src/main/java/com/ruoyi/production/bean/dto/ProductionProductInputDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,27 @@
package com.ruoyi.production.bean.dto;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@Data
public class ProductionProductInputDto {
    private Long id;
    private Long productMainId;
    private Long productionProductMainId;
    private Long productModelId;
    private BigDecimal quantity;
    private BigDecimal inputQuantity;
    private LocalDateTime createTime;
    private LocalDateTime updateTime;
    private Long tenantId;
    private Integer createUser;
    private Integer updateUser;
    private Long deptId;
    private String productNo;
    private String model;
    private String productName;
    private String unit;
}
src/main/java/com/ruoyi/production/bean/dto/ProductionProductMainDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,39 @@
package com.ruoyi.production.bean.dto;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
@Data
public class ProductionProductMainDto {
    private Long id;
    private String productNo;
    private Long userId;
    private String userName;
    private Long productProcessRouteItemId;
    private Long workOrderId;
    private Long productionOperationTaskId;
    private Integer status;
    private LocalDateTime createTime;
    private LocalDateTime updateTime;
    private Long tenantId;
    private Integer createUser;
    private Integer updateUser;
    private Long deptId;
    private String workOrderNo;
    private String workOrderStatus;
    private String nickName;
    private BigDecimal quantity;
    private BigDecimal scrapQty;
    private String productName;
    private String productModelName;
    private String unit;
    private String salesContractNo;
    private LocalDate schedulingDate;
    private String schedulingUserName;
    private String customerName;
    private String process;
}
src/main/java/com/ruoyi/production/bean/dto/ProductionProductOutputDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,25 @@
package com.ruoyi.production.bean.dto;
import lombok.Data;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@Data
public class ProductionProductOutputDto {
    private Long id;
    private Long productMainId;
    private Long productionProductMainId;
    private Long productModelId;
    private BigDecimal quantity;
    private BigDecimal scrapQty;
    private LocalDateTime createTime;
    private LocalDateTime updateTime;
    private Long tenantId;
    private Integer createUser;
    private Integer updateUser;
    private Long deptId;
    private String productNo;
    private String model;
}
src/main/java/com/ruoyi/production/bean/dto/SalesLedgerProductionAccountingDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,14 @@
package com.ruoyi.production.bean.dto;
import lombok.Data;
import java.time.LocalDate;
@Data
public class SalesLedgerProductionAccountingDto {
    private Long userId;
    private String userName;
    private String process;
    private LocalDate startDate;
    private LocalDate endDate;
}
src/main/java/com/ruoyi/production/bean/dto/UserAccountDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,11 @@
package com.ruoyi.production.bean.dto;
import lombok.Data;
import java.math.BigDecimal;
@Data
public class UserAccountDto {
    private BigDecimal account = BigDecimal.ZERO;
    private BigDecimal accountBalance = BigDecimal.ZERO;
}
src/main/java/com/ruoyi/production/bean/dto/UserProductionAccountingDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,9 @@
package com.ruoyi.production.bean.dto;
import lombok.Data;
@Data
public class UserProductionAccountingDto {
    private Long userId;
    private String date;
}
src/main/java/com/ruoyi/production/bean/vo/ProductionOperationTaskVo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,8 @@
package com.ruoyi.production.bean.vo;
import com.ruoyi.production.pojo.ProductionOperationTask;
import lombok.Data;
@Data
public class ProductionOperationTaskVo extends ProductionOperationTask {
}
src/main/java/com/ruoyi/production/bean/vo/ProductionOrderRoutingOperationParamVo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,8 @@
package com.ruoyi.production.bean.vo;
import com.ruoyi.production.pojo.ProductionOrderRoutingOperationParam;
import lombok.Data;
@Data
public class ProductionOrderRoutingOperationParamVo extends ProductionOrderRoutingOperationParam {
}
src/main/java/com/ruoyi/production/bean/vo/ProductionOrderVo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,8 @@
package com.ruoyi.production.bean.vo;
import com.ruoyi.production.pojo.ProductionOrder;
import lombok.Data;
@Data
public class ProductionOrderVo extends ProductionOrder {
}
src/main/java/com/ruoyi/production/controller/ProductionOperationTaskController.java
@@ -1,18 +1,66 @@
package com.ruoyi.production.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.production.bean.dto.ProductionOperationTaskDto;
import com.ruoyi.production.bean.vo.ProductionOperationTaskVo;
import com.ruoyi.production.pojo.ProductionOperationTask;
import com.ruoyi.production.service.ProductionOperationTaskService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
 * <p>
 * ç”Ÿäº§å·¥å•表 å‰ç«¯æŽ§åˆ¶å™¨
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-04-21 03:55:52
 */
import java.util.List;
@RestController
@RequestMapping("/productionOperationTask")
@Api(tags = "生产工单")
@RequiredArgsConstructor
public class ProductionOperationTaskController {
    private final ProductionOperationTaskService productionOperationTaskService;
    @GetMapping("/page")
    @ApiOperation("分页查询")
    public R page(Page<ProductionOperationTaskDto> page, ProductionOperationTaskDto dto) {
        return R.ok(productionOperationTaskService.pageProductionOperationTask(page, dto));
    }
    @GetMapping("/list")
    @ApiOperation("工单列表")
    public R<List<ProductionOperationTaskVo>> list(ProductionOperationTaskDto dto) {
        return R.ok(productionOperationTaskService.listProductionOperationTask(dto));
    }
    @GetMapping("/{id}")
    @ApiOperation("工单详情")
    public R<ProductionOperationTaskVo> getInfo(@PathVariable("id") Long id) {
        return R.ok(productionOperationTaskService.getProductionOperationTaskInfo(id));
    }
    @PostMapping
    @ApiOperation("新增工单")
    public R<Boolean> add(@RequestBody ProductionOperationTask productionOperationTask) {
        return R.ok(productionOperationTaskService.saveProductionOperationTask(productionOperationTask));
    }
    @PutMapping
    @ApiOperation("修改工单")
    public R<Boolean> edit(@RequestBody ProductionOperationTask productionOperationTask) {
        return R.ok(productionOperationTaskService.saveProductionOperationTask(productionOperationTask));
    }
    @DeleteMapping("/delete")
    @ApiOperation("删除工单")
    public R<Boolean> remove(@RequestBody List<Long> ids) {
        return R.ok(productionOperationTaskService.removeProductionOperationTask(ids));
    }
}
src/main/java/com/ruoyi/production/controller/ProductionOrderController.java
@@ -1,18 +1,72 @@
package com.ruoyi.production.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.production.bean.dto.ProductionOrderDto;
import com.ruoyi.production.bean.vo.ProductionOrderVo;
import com.ruoyi.production.pojo.ProductionOrder;
import com.ruoyi.production.service.ProductionOrderService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
 * <p>
 * ç”Ÿäº§è®¢å•表 å‰ç«¯æŽ§åˆ¶å™¨
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-04-21 03:55:52
 */
import java.util.List;
@RestController
@RequestMapping("/productionOrder")
@Api(tags = "生产订单")
@RequiredArgsConstructor
public class ProductionOrderController {
    private final ProductionOrderService productionOrderService;
    @GetMapping("/page")
    @ApiOperation("分页查询")
    public R page(ProductionOrderDto dto, Page<ProductionOrderDto> page) {
        return R.ok(productionOrderService.pageProductionOrder(page, dto));
    }
    @GetMapping("/list")
    @ApiOperation("生产订单列表")
    public R<List<ProductionOrderVo>> list(ProductionOrderDto dto) {
        return R.ok(productionOrderService.listProductionOrder(dto));
    }
    @GetMapping("/{id}")
    @ApiOperation("生产订单详情")
    public R<ProductionOrderVo> getInfo(@PathVariable("id") Long id) {
        return R.ok(productionOrderService.getProductionOrderInfo(id));
    }
    @PostMapping
    @ApiOperation("新增生产订单")
    public R<Boolean> add(@RequestBody ProductionOrder productionOrder) {
        return R.ok(productionOrderService.saveProductionOrder(productionOrder));
    }
    @PutMapping
    @ApiOperation("修改生产订单")
    public R<Boolean> edit(@RequestBody ProductionOrder productionOrder) {
        return R.ok(productionOrderService.saveProductionOrder(productionOrder));
    }
    @PostMapping("/syncSnapshot/{id}")
    @ApiOperation("同步生产订单工艺/BOM快照")
    public R<Integer> syncSnapshot(@PathVariable("id") Long id) {
        return R.ok(productionOrderService.syncProductionOrderSnapshot(id));
    }
    @DeleteMapping("/delete")
    @ApiOperation("删除生产订单")
    public R<Boolean> remove(@RequestBody List<Long> ids) {
        return R.ok(productionOrderService.removeProductionOrder(ids));
    }
}
src/main/java/com/ruoyi/production/controller/ProductionOrderRoutingController.java
@@ -1,18 +1,56 @@
package com.ruoyi.production.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.production.pojo.ProductionOrderRoutingOperation;
import com.ruoyi.production.service.ProductionOrderRoutingOperationService;
import com.ruoyi.production.service.ProductionOrderRoutingService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
/**
 * <p>
 * ç”Ÿäº§è®¢å•工艺路线表 å‰ç«¯æŽ§åˆ¶å™¨
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-04-21 03:55:52
 */
@RestController
@RequestMapping("/productionOrderRouting")
@Api(tags = "生产订单工艺路线")
@RequiredArgsConstructor
public class ProductionOrderRoutingController {
    private final ProductionOrderRoutingService productionOrderRoutingService;
    private final ProductionOrderRoutingOperationService productionOrderRoutingOperationService;
    @GetMapping("list")
    @ApiOperation("根据Id查询工艺路线子表")
    public R list(Long orderId) {
        return R.ok(productionOrderRoutingService.listItem(orderId));
    }
    @GetMapping("listMain")
    @ApiOperation("根据Id查询工艺路线主表")
    public R listMain(Long orderId) {
        return R.ok(productionOrderRoutingService.listMain(orderId));
    }
    @PostMapping("/addRouteItem")
    @ApiOperation("新增生产订单的工艺路线详情")
    public R addRouteItem(@RequestBody ProductionOrderRoutingOperation productionOrderRoutingOperation) {
        return productionOrderRoutingOperationService.addRouteItem(productionOrderRoutingOperation);
    }
    @PostMapping("/updateRouteItem")
    @ApiOperation("修改生产订单的工艺路线详情")
    public R updateRouteItem(@RequestBody ProductionOrderRoutingOperation productionOrderRoutingOperation) {
        return R.ok(productionOrderRoutingOperationService.updateById(productionOrderRoutingOperation));
    }
    @DeleteMapping("/deleteRouteItem/{id}")
    @ApiOperation("删除生产工艺路线")
    public R deleteRouteItem(@PathVariable("id") Long id) {
        return productionOrderRoutingOperationService.deleteRouteItem(id);
    }
    @PostMapping("/sortRouteItem")
    @ApiOperation("排序")
    public R sortRouteItem(@RequestBody ProductionOrderRoutingOperation productionOrderRoutingOperation) {
        return R.ok(productionOrderRoutingOperationService.sortRouteItem(productionOrderRoutingOperation));
    }
}
src/main/java/com/ruoyi/production/controller/ProductionOrderRoutingOperationParamController.java
@@ -1,18 +1,68 @@
package com.ruoyi.production.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.production.bean.dto.ProductionOrderRoutingOperationParamDto;
import com.ruoyi.production.bean.dto.ProductionOrderRoutingOperationParamSyncDto;
import com.ruoyi.production.bean.vo.ProductionOrderRoutingOperationParamVo;
import com.ruoyi.production.pojo.ProductionOrderRoutingOperationParam;
import com.ruoyi.production.service.ProductionOrderRoutingOperationParamService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
/**
 * <p>
 * ç”Ÿäº§è®¢å•工艺路线工序参数表 å‰ç«¯æŽ§åˆ¶å™¨
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-04-21 03:55:52
 */
import java.util.List;
@RestController
@RequestMapping("/productionOrderRoutingOperationParam")
@Api(tags = "生产订单工艺路线工序参数")
@RequiredArgsConstructor
public class ProductionOrderRoutingOperationParamController {
    private final ProductionOrderRoutingOperationParamService productionOrderRoutingOperationParamService;
    @GetMapping("/page")
    @ApiOperation("生产订单工艺路线工序参数分页查询")
    public R<IPage<ProductionOrderRoutingOperationParamVo>> page(Page<ProductionOrderRoutingOperationParamDto> page,
                                                                 ProductionOrderRoutingOperationParamDto dto) {
        return R.ok(productionOrderRoutingOperationParamService.pageProductionOrderRoutingOperationParam(page, dto));
    }
    @GetMapping("/list")
    @ApiOperation("生产订单工艺路线工序参数列表")
    public R<List<ProductionOrderRoutingOperationParamVo>> list(ProductionOrderRoutingOperationParamDto dto) {
        return R.ok(productionOrderRoutingOperationParamService.listProductionOrderRoutingOperationParam(dto));
    }
    @GetMapping("/{id}")
    @ApiOperation("生产订单工艺路线工序参数详情")
    public R<ProductionOrderRoutingOperationParamVo> getInfo(@PathVariable("id") Long id) {
        return R.ok(productionOrderRoutingOperationParamService.getProductionOrderRoutingOperationParamInfo(id));
    }
    @PostMapping
    @ApiOperation("新增生产订单工艺路线工序参数")
    public R<Boolean> add(@RequestBody ProductionOrderRoutingOperationParam item) {
        return R.ok(productionOrderRoutingOperationParamService.saveProductionOrderRoutingOperationParam(item));
    }
    @PutMapping
    @ApiOperation("修改生产订单工艺路线工序参数")
    public R<Boolean> edit(@RequestBody ProductionOrderRoutingOperationParam item) {
        return R.ok(productionOrderRoutingOperationParamService.saveProductionOrderRoutingOperationParam(item));
    }
    @DeleteMapping("/{id}")
    @ApiOperation("删除生产订单工艺路线工序参数")
    public R<Boolean> remove(@PathVariable("id") Long id) {
        return R.ok(productionOrderRoutingOperationParamService.removeProductionOrderRoutingOperationParam(id));
    }
    @PostMapping("/sync")
    @ApiOperation("按订单工艺路线工序同步工序参数")
    public R<Integer> sync(@RequestBody ProductionOrderRoutingOperationParamSyncDto syncDto) {
        return R.ok(productionOrderRoutingOperationParamService.syncProductionOrderRoutingOperationParam(syncDto));
    }
}
src/main/java/com/ruoyi/production/controller/ProductionPlanController.java
@@ -12,11 +12,11 @@
import com.ruoyi.production.service.ProductionPlanService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.List;
src/main/java/com/ruoyi/production/controller/ProductionProductInputController.java
@@ -1,18 +1,25 @@
package com.ruoyi.production.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.production.bean.dto.ProductionProductInputDto;
import com.ruoyi.production.service.ProductionProductInputService;
import io.swagger.annotations.Api;
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;
/**
 * <p>
 * ç”Ÿäº§æŠ¥å·¥æŠ•入表 å‰ç«¯æŽ§åˆ¶å™¨
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-04-21 03:55:52
 */
@RequestMapping("productionProductInput")
@RestController
@RequestMapping("/productionProductInput")
@Api(value = "生产投入")
public class ProductionProductInputController {
    @Autowired
    private ProductionProductInputService productionProductInputService;
    @GetMapping("listPage")
    public R page(Page<ProductionProductInputDto> page, ProductionProductInputDto productionProductInputDto) {
        return R.ok(productionProductInputService.listPageProductionProductInputDto(page, productionProductInputDto));
    }
}
src/main/java/com/ruoyi/production/controller/ProductionProductMainController.java
@@ -1,18 +1,92 @@
package com.ruoyi.production.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.production.bean.dto.ProductionProductMainDto;
import com.ruoyi.production.service.ProductionProductMainService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
/**
 * <p>
 * ç”Ÿäº§æŠ¥å·¥è¡¨ å‰ç«¯æŽ§åˆ¶å™¨
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-04-21 03:55:52
 */
import java.util.List;
@RequestMapping("productionProductMain")
@RestController
@RequestMapping("/productionProductMain")
@Api(value = "生产报工")
public class ProductionProductMainController {
    @Autowired
    private ProductionProductMainService productionProductMainService;
    /**
     * æŠ¥å·¥æŸ¥è¯¢
     * @param page
     * @param productionProductMainDto
     * @return
     */
    @GetMapping("listPage")
    public R page(Page<ProductionProductMainDto> page, ProductionProductMainDto productionProductMainDto) {
        return R.ok(productionProductMainService.listPageProductionProductMainDto(page, productionProductMainDto));
    }
    @GetMapping("/page")
    @ApiOperation("生产报工分页查询")
    public R pageProductionProductMain(Page<ProductionProductMainDto> page, ProductionProductMainDto productionProductMainDto) {
        return R.ok(productionProductMainService.pageProductionProductMain(page, productionProductMainDto));
    }
    @GetMapping("/{id}")
    @ApiOperation("生产报工详情")
    public R getInfo(@PathVariable("id") Long id) {
        return R.ok(productionProductMainService.getProductionProductMainInfo(id));
    }
    /**
     * æŠ¥å·¥æ–°å¢žæ›´æ–°
     * @param productionProductMainDto
     * @return
     */
    @PostMapping("addProductMain")
    public R addProductMain(@RequestBody ProductionProductMainDto productionProductMainDto) {
        return R.ok(productionProductMainService.addProductMain(productionProductMainDto));
    }
    @PostMapping
    @ApiOperation("新增生产报工")
    public R add(@RequestBody ProductionProductMainDto productionProductMainDto) {
        return R.ok(productionProductMainService.saveProductionProductMain(productionProductMainDto));
    }
    @PutMapping
    @ApiOperation("修改生产报工")
    public R edit(@RequestBody ProductionProductMainDto productionProductMainDto) {
        return R.ok(productionProductMainService.saveProductionProductMain(productionProductMainDto));
    }
    @ApiOperation("删除报工")
    @DeleteMapping("/delete")
    public R delete(@RequestBody ProductionProductMainDto productionProductMainDto) {
        return R.ok(productionProductMainService.removeProductMain(productionProductMainDto.getId()));
    }
    @DeleteMapping("/{id}")
    @ApiOperation("删除生产报工")
    public R remove(@PathVariable("id") Long id) {
        return R.ok(productionProductMainService.removeProductMain(id));
    }
    /**
     * å¯¼å‡º
     */
    @PostMapping("/export")
    public void export(HttpServletResponse response, ProductionProductMainDto productionProductMainDto) {
        List<ProductionProductMainDto> list;
        list = productionProductMainService.listPageProductionProductMainDto(new Page<>(1, -1), productionProductMainDto).getRecords();
        ExcelUtil<ProductionProductMainDto> util = new ExcelUtil<ProductionProductMainDto>(ProductionProductMainDto.class);
        util.exportExcel(response, list, "生产报工数据");
    }
}
src/main/java/com/ruoyi/production/controller/ProductionProductOutputController.java
@@ -1,18 +1,25 @@
package com.ruoyi.production.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.production.bean.dto.ProductionProductOutputDto;
import com.ruoyi.production.service.ProductionProductOutputService;
import io.swagger.annotations.Api;
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;
/**
 * <p>
 * ç”Ÿäº§æŠ¥å·¥äº§å‡ºè¡¨ å‰ç«¯æŽ§åˆ¶å™¨
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-04-21 03:55:52
 */
@RequestMapping("productionProductOutput")
@RestController
@RequestMapping("/productionProductOutput")
@Api(value = "生产产出")
public class ProductionProductOutputController {
    @Autowired
    private ProductionProductOutputService productionProductOutputService;
    @GetMapping("listPage")
    public R page(Page<ProductionProductOutputDto> page, ProductionProductOutputDto productionProductOutputDto) {
        return R.ok(productionProductOutputService.listPageProductionProductOutputDto(page, productionProductOutputDto));
    }
}
src/main/java/com/ruoyi/production/enums/ProductOrderStatusEnum.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,65 @@
package com.ruoyi.production.enums;
import lombok.Getter;
/**
 * <br>
 * ç”Ÿäº§è®¢å•状态枚举类
 * </br>
 *
 * @author deslrey
 * @version 1.0
 * @since 2026/03/18 14:18
 */
@Getter
public enum ProductOrderStatusEnum {
    WAIT(1, "待开始"),
    RUNNING(2, "进行中"),
    FINISHED(3, "已完成"),
    CANCEL(4, "已取消");
    private final Integer code;
    private final String desc;
    ProductOrderStatusEnum(Integer code, String desc) {
        this.code = code;
        this.desc = desc;
    }
    /**
     * æ ¹æ®code获取枚举
     */
    public static ProductOrderStatusEnum getByCode(Integer code) {
        if (code == null) {
            return null;
        }
        for (ProductOrderStatusEnum item : values()) {
            if (item.getCode().equals(code)) {
                return item;
            }
        }
        return null;
    }
    /**
     * åˆ¤æ–­æ˜¯å¦å…è®¸åˆ é™¤ï¼ˆ4)
     */
    public static boolean canDelete(Integer code) {
        return WAIT.getCode().equals(code) || CANCEL.getCode().equals(code);
    }
    /**
     * åˆ¤æ–­æ˜¯å¦å…è®¸æ’¤å›žï¼ˆ1)
     */
    public static boolean canRevoke(Integer code) {
        return WAIT.getCode().equals(code);
    }
    /**
     * åˆ¤æ–­æ˜¯å¦å·²å¼€å§‹ç”Ÿäº§ï¼ˆ2、3)
     */
    public static boolean isStarted(Integer code) {
        return RUNNING.getCode().equals(code) || FINISHED.getCode().equals(code);
    }
}
src/main/java/com/ruoyi/production/mapper/ProductionAccountMapper.java
@@ -1,8 +1,13 @@
package com.ruoyi.production.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.production.bean.dto.UserAccountDto;
import com.ruoyi.production.pojo.ProductionAccount;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
import java.util.Map;
/**
 * <p>
@@ -14,5 +19,8 @@
 */
@Mapper
public interface ProductionAccountMapper extends BaseMapper<ProductionAccount> {
    UserAccountDto selectUserAccount(@Param("userId") Long userId, @Param("date") String date);
    List<Map<String, Object>> selectDailyWagesStats(@Param("startDate") String startDate, @Param("endDate") String endDate);
}
src/main/java/com/ruoyi/production/mapper/ProductionOperationTaskMapper.java
@@ -1,8 +1,15 @@
package com.ruoyi.production.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.home.dto.ProductionTaskStatisticsDto;
import com.ruoyi.home.dto.processDataProductionStatisticsDto;
import com.ruoyi.production.pojo.ProductionOperationTask;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
/**
 * <p>
@@ -15,4 +22,15 @@
@Mapper
public interface ProductionOperationTaskMapper extends BaseMapper<ProductionOperationTask> {
    List<ProductionTaskStatisticsDto> selectTaskStatisticsByDate(@Param("startDate") LocalDate startDate,
                                                                 @Param("endDate") LocalDate endDate);
    List<ProductionTaskStatisticsDto> selectTaskStartStats(@Param("startDateTime") String startDateTime,
                                                           @Param("endDateTime") String endDateTime);
    List<processDataProductionStatisticsDto> calculateProductionStatistics(@Param("startDateTime") LocalDateTime startDateTime,
                                                                           @Param("endDateTime") LocalDateTime endDateTime,
                                                                           @Param("userId") Long userId,
                                                                           @Param("processIds") List<Long> processIds);
}
src/main/java/com/ruoyi/production/mapper/ProductionOrderMapper.java
@@ -1,8 +1,13 @@
package com.ruoyi.production.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.ruoyi.home.dto.ProductionProgressOrderDto;
import com.ruoyi.production.pojo.ProductionOrder;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.time.LocalDateTime;
import java.util.List;
/**
 * <p>
@@ -15,4 +20,13 @@
@Mapper
public interface ProductionOrderMapper extends BaseMapper<ProductionOrder> {
    List<ProductionProgressOrderDto> selectProgressOrders(@Param("startTime") LocalDateTime startTime,
                                                          @Param("endTime") LocalDateTime endTime);
    Integer countCreated(@Param("startDate") String startDate, @Param("endDate") String endDate);
    Integer countCompleted(@Param("startDate") String startDate, @Param("endDate") String endDate);
    Integer countPending(@Param("startDate") String startDate, @Param("endDate") String endDate);
}
src/main/java/com/ruoyi/production/mapper/ProductionPlanMapper.java
@@ -1,8 +1,14 @@
package com.ruoyi.production.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.production.bean.dto.ProductionPlanDto;
import com.ruoyi.production.pojo.ProductionPlan;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
 * <p>
@@ -15,4 +21,10 @@
@Mapper
public interface ProductionPlanMapper extends BaseMapper<ProductionPlan> {
    IPage<ProductionPlanDto> listPage(Page page, @Param("c") ProductionPlanDto productionPlanDto);
    List<ProductionPlanDto> selectWithMaterialByIds(@Param("ids") List<Long> ids);
    ProductionPlanDto selectProductionPlanDtoById(@Param("productionPlanId") Long productionPlanId);
}
src/main/java/com/ruoyi/production/mapper/ProductionProductInputMapper.java
@@ -1,18 +1,24 @@
package com.ruoyi.production.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.production.bean.dto.ProductionProductInputDto;
import com.ruoyi.production.pojo.ProductionProductInput;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
/**
 * <p>
 * ç”Ÿäº§æŠ¥å·¥æŠ•入表 Mapper æŽ¥å£
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-04-21 03:55:52
 */
import java.util.List;
import java.util.Map;
@Mapper
public interface ProductionProductInputMapper extends BaseMapper<ProductionProductInput> {
    IPage<ProductionProductInputDto> listPageProductionProductInputDto(Page page, @Param("c") ProductionProductInputDto productionProductInputDto);
    /**
     * æ ¹æ®ç”Ÿäº§ä¸»è¡¨ID批量删除投入表数据
     */
    int deleteByProductMainIds(@Param("productMainIds") List<Long> productMainIds);
    List<Map<String, Object>> selectInputStats(@Param("startDate") String startDate, @Param("endDate") String endDate);
}
src/main/java/com/ruoyi/production/mapper/ProductionProductMainMapper.java
@@ -1,18 +1,36 @@
package com.ruoyi.production.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.production.bean.dto.ProductionProductMainDto;
import com.ruoyi.production.bean.dto.SalesLedgerProductionAccountingDto;
import com.ruoyi.production.pojo.ProductionOrder;
import com.ruoyi.production.pojo.ProductionProductMain;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
/**
 * <p>
 * ç”Ÿäº§æŠ¥å·¥è¡¨ Mapper æŽ¥å£
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-04-21 03:55:52
 */
import java.util.ArrayList;
import java.util.List;
@Mapper
public interface ProductionProductMainMapper extends BaseMapper<ProductionProductMain> {
    IPage<ProductionProductMainDto> listPageProductionProductMainDto(Page page, @Param("c") ProductionProductMainDto productionProductMainDto);
    /**
     * æ ¹æ®å·¥å•ID批量删除生产主表数据
     */
    int deleteByWorkOrderIds(@Param("workOrderIds") List<Long> workOrderIds);
    /**
     * æ ¹æ®æŠ¥å·¥id查询生产订单
     * @param productMainId
     * @return
     */
    ProductionOrder getOrderByMainId(@Param("productMainId") Long productMainId);
    IPage<ProductionProductMainDto> listProductionDetails(@Param("ew") SalesLedgerProductionAccountingDto salesLedgerProductionAccountingDto, Page page);
    ArrayList<Long> listMain(List<Long> idList);
}
src/main/java/com/ruoyi/production/mapper/ProductionProductOutputMapper.java
@@ -1,18 +1,26 @@
package com.ruoyi.production.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.production.bean.dto.ProductionProductOutputDto;
import com.ruoyi.production.pojo.ProductionProductOutput;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
/**
 * <p>
 * ç”Ÿäº§æŠ¥å·¥äº§å‡ºè¡¨ Mapper æŽ¥å£
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-04-21 03:55:52
 */
import java.util.List;
import java.util.Map;
@Mapper
public interface ProductionProductOutputMapper extends BaseMapper<ProductionProductOutput> {
    IPage<ProductionProductOutputDto> listPageProductionProductOutputDto(Page page, @Param("c") ProductionProductOutputDto productionProductOutputDto);
    /**
     * æ ¹æ®ç”Ÿäº§ä¸»è¡¨ID批量删除产出表数据
     */
    int deleteByProductMainIds(@Param("productMainIds") List<Long> productMainIds);
    List<ProductionProductOutputDto> selectOutputStats(@Param("startDate") String startDate, @Param("endDate") String endDate);
    List<Map<String, Object>> selectDailyOutputStats(@Param("startDate") String startDate, @Param("endDate") String endDate);
}
src/main/java/com/ruoyi/production/pojo/ProductionOrder.java
@@ -1,13 +1,16 @@
package com.ruoyi.production.pojo;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
/**
@@ -74,4 +77,15 @@
    @ApiModelProperty("部门ID")
    @TableField(fill = FieldFill.INSERT)
    private Long deptId;
    @ApiModelProperty(value = "计划完成时间")
    @JsonFormat(pattern = "yyyy-MM-dd")
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private LocalDate planCompleteTime;
    @ApiModelProperty(value = "状态(1.待开始、2.进行中、3.已完成、4.已取消)")
    private Integer status;
    @ApiModelProperty("强度")
    private String strength;
}
src/main/java/com/ruoyi/production/pojo/ProductionPlan.java
@@ -6,6 +6,7 @@
import lombok.Getter;
import lombok.Setter;
import java.io.Serial;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@@ -24,6 +25,7 @@
@ApiModel(value = "ProductionPlan对象", description = "生产计划表")
public class ProductionPlan implements Serializable {
    @Serial
    private static final long serialVersionUID = 1L;
    @ApiModelProperty("id")
src/main/java/com/ruoyi/production/pojo/ProductionProductInput.java
@@ -1,57 +1,54 @@
package com.ruoyi.production.pojo;
import com.baomidou.mybatisplus.annotation.*;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
 * <p>
 * ç”Ÿäº§æŠ¥å·¥æŠ•入表
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-04-21 03:55:52
 */
@Getter
@Setter
@Data
@TableName("production_product_input")
@ApiModel(value = "ProductionProductInput对象", description = "生产报工投入表")
public class ProductionProductInput implements Serializable {
public class ProductionProductInput {
    private static final long serialVersionUID = 1L;
    @ApiModelProperty("id")
    @TableId(value = "id", type = IdType.AUTO)
    @TableId(type = IdType.AUTO)
    private Long id;
    @ApiModelProperty("投入数量")
    private BigDecimal inputQuantity;
    @ApiModelProperty(value = "报工id")
    private Long productMainId;
    @ApiModelProperty("报工表id")
    @ApiModelProperty(value = "生产报工主表id")
    private Long productionProductMainId;
    @ApiModelProperty("产品型号id")
    @ApiModelProperty(value = "产品id")
    private Long productModelId;
    @ApiModelProperty("更新时间")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;
    @ApiModelProperty(value = "数量")
    private BigDecimal quantity;
    @ApiModelProperty("创建人ID")
    @TableField(fill = FieldFill.INSERT)
    private Long createUser;
    @ApiModelProperty(value = "投入数量")
    private BigDecimal inputQuantity;
    @ApiModelProperty("录入时间")
    @ApiModelProperty(value = "创建时间")
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;
    @ApiModelProperty("更新用户")
    @ApiModelProperty(value = "更新时间")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Long updateUser;
    private LocalDateTime updateTime;
    @ApiModelProperty(value = "租户ID")
    @TableField(fill = FieldFill.INSERT)
    private Long tenantId;
    @ApiModelProperty(value = "创建用户")
    @TableField(fill = FieldFill.INSERT)
    private Integer createUser;
    @ApiModelProperty(value = "更新用户")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Integer updateUser;
    @TableField(fill = FieldFill.INSERT)
    private Long deptId;
}
src/main/java/com/ruoyi/production/pojo/ProductionProductMain.java
@@ -1,57 +1,68 @@
package com.ruoyi.production.pojo;
import com.baomidou.mybatisplus.annotation.*;
import io.swagger.annotations.ApiModel;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.framework.aspectj.lang.annotation.Excel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
 * <p>
 * ç”Ÿäº§æŠ¥å·¥è¡¨
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-04-21 03:55:52
 */
@Getter
@Setter
@Data
@TableName("production_product_main")
@ApiModel(value = "ProductionProductMain对象", description = "生产报工表")
public class ProductionProductMain implements Serializable {
public class ProductionProductMain {
    private static final long serialVersionUID = 1L;
    @ApiModelProperty("id")
    @TableId(value = "id", type = IdType.AUTO)
    @TableId(type = IdType.AUTO)
    private Long id;
    @ApiModelProperty("报工单号")
    @ApiModelProperty(value = "报工单号")
    @Excel(name = "报工单号")
    private String productNo;
    @ApiModelProperty("工单id")
    @ApiModelProperty(value = "报工人员id")
    private Long userId;
    @ApiModelProperty(value = "报工人员")
    private String userName;
    @ApiModelProperty(value = "生产项目id")
    private Long productProcessRouteItemId;
    @ApiModelProperty(value = "工单id")
    private Long workOrderId;
    @ApiModelProperty(value = "生产工序工单id")
    private Long productionOperationTaskId;
    @ApiModelProperty("部门ID")
    @ApiModelProperty(value = "报工状态")
    private Integer status;
    @ApiModelProperty(value = "创建时间")
    @TableField(fill = FieldFill.INSERT)
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @Excel(name = "创建时间")
    private LocalDateTime createTime;
    @ApiModelProperty(value = "更新时间")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime updateTime;
    @ApiModelProperty(value = "租户ID")
    @TableField(fill = FieldFill.INSERT)
    private Long tenantId;
    @ApiModelProperty(value = "创建用户")
    @TableField(fill = FieldFill.INSERT)
    private Integer createUser;
    @ApiModelProperty(value = "更新用户")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Integer updateUser;
    @TableField(fill = FieldFill.INSERT)
    private Long deptId;
    @ApiModelProperty("更新时间")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;
    @ApiModelProperty("创建人ID")
    @TableField(fill = FieldFill.INSERT)
    private Long createUser;
    @ApiModelProperty("录入时间")
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;
    @ApiModelProperty("更新用户")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Long updateUser;
}
src/main/java/com/ruoyi/production/pojo/ProductionProductOutput.java
@@ -1,59 +1,54 @@
package com.ruoyi.production.pojo;
import com.baomidou.mybatisplus.annotation.*;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
import lombok.Data;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
 * <p>
 * ç”Ÿäº§æŠ¥å·¥äº§å‡ºè¡¨
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-04-21 03:55:52
 */
@Getter
@Setter
@Data
@TableName("production_product_output")
@ApiModel(value = "ProductionProductOutput对象", description = "生产报工产出表")
public class ProductionProductOutput implements Serializable {
public class ProductionProductOutput {
    private static final long serialVersionUID = 1L;
    @TableId(value = "id", type = IdType.AUTO)
    @TableId(type = IdType.AUTO)
    private Long id;
    @ApiModelProperty("报工单id")
    @ApiModelProperty(value = "报工id")
    private Long productMainId;
    @ApiModelProperty(value = "生产报工主表id")
    private Long productionProductMainId;
    @ApiModelProperty("产品规格id")
    @ApiModelProperty(value = "产品id")
    private Long productModelId;
    @ApiModelProperty("报工数量")
    @ApiModelProperty(value = "报工数量(总数量)")
    private BigDecimal quantity;
    @ApiModelProperty("报废数量")
    private BigDecimal scrapQty;
    @ApiModelProperty("更新时间")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;
    @ApiModelProperty("创建人ID")
    @TableField(fill = FieldFill.INSERT)
    private Long createUser;
    @ApiModelProperty("录入时间")
    @ApiModelProperty(value = "创建时间")
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;
    @ApiModelProperty("更新用户")
    @ApiModelProperty(value = "更新时间")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Long updateUser;
    private LocalDateTime updateTime;
    @ApiModelProperty(value = "租户ID")
    @TableField(fill = FieldFill.INSERT)
    private Long tenantId;
    @ApiModelProperty(value = "报废数量")
    private BigDecimal scrapQty;
    @ApiModelProperty(value = "创建用户")
    @TableField(fill = FieldFill.INSERT)
    private Integer createUser;
    @ApiModelProperty(value = "更新用户")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Integer updateUser;
    @TableField(fill = FieldFill.INSERT)
    private Long deptId;
}
src/main/java/com/ruoyi/production/service/ProductionOperationTaskService.java
@@ -1,16 +1,24 @@
package com.ruoyi.production.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.production.bean.dto.ProductionOperationTaskDto;
import com.ruoyi.production.bean.vo.ProductionOperationTaskVo;
import com.ruoyi.production.pojo.ProductionOperationTask;
/**
 * <p>
 * ç”Ÿäº§å·¥å•表 æœåŠ¡ç±»
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-04-21 03:55:52
 */
import java.util.List;
public interface ProductionOperationTaskService extends IService<ProductionOperationTask> {
    IPage<ProductionOperationTaskVo> pageProductionOperationTask(Page<ProductionOperationTaskDto> page,
                                                                 ProductionOperationTaskDto productionOperationTaskDto);
    List<ProductionOperationTaskVo> listProductionOperationTask(ProductionOperationTaskDto productionOperationTaskDto);
    ProductionOperationTaskVo getProductionOperationTaskInfo(Long id);
    boolean saveProductionOperationTask(ProductionOperationTask productionOperationTask);
    boolean removeProductionOperationTask(List<Long> ids);
}
src/main/java/com/ruoyi/production/service/ProductionOrderRoutingOperationParamService.java
@@ -1,7 +1,14 @@
package com.ruoyi.production.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.production.bean.dto.ProductionOrderRoutingOperationParamDto;
import com.ruoyi.production.bean.dto.ProductionOrderRoutingOperationParamSyncDto;
import com.ruoyi.production.bean.vo.ProductionOrderRoutingOperationParamVo;
import com.ruoyi.production.pojo.ProductionOrderRoutingOperationParam;
import java.util.List;
/**
 * <p>
@@ -13,4 +20,16 @@
 */
public interface ProductionOrderRoutingOperationParamService extends IService<ProductionOrderRoutingOperationParam> {
    IPage<ProductionOrderRoutingOperationParamVo> pageProductionOrderRoutingOperationParam(Page<ProductionOrderRoutingOperationParamDto> page,
                                                                                           ProductionOrderRoutingOperationParamDto dto);
    List<ProductionOrderRoutingOperationParamVo> listProductionOrderRoutingOperationParam(ProductionOrderRoutingOperationParamDto dto);
    ProductionOrderRoutingOperationParamVo getProductionOrderRoutingOperationParamInfo(Long id);
    boolean saveProductionOrderRoutingOperationParam(ProductionOrderRoutingOperationParam item);
    boolean removeProductionOrderRoutingOperationParam(Long id);
    int syncProductionOrderRoutingOperationParam(ProductionOrderRoutingOperationParamSyncDto syncDto);
}
src/main/java/com/ruoyi/production/service/ProductionOrderRoutingOperationService.java
@@ -1,16 +1,14 @@
package com.ruoyi.production.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.production.pojo.ProductionOrderRoutingOperation;
/**
 * <p>
 * ç”Ÿäº§è®¢å•工艺路线工序表 æœåŠ¡ç±»
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-04-21 03:55:52
 */
public interface ProductionOrderRoutingOperationService extends IService<ProductionOrderRoutingOperation> {
    R addRouteItem(ProductionOrderRoutingOperation productionOrderRoutingOperation);
    R deleteRouteItem(Long id);
    int sortRouteItem(ProductionOrderRoutingOperation productionOrderRoutingOperation);
}
src/main/java/com/ruoyi/production/service/ProductionOrderRoutingService.java
@@ -2,15 +2,13 @@
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.production.pojo.ProductionOrderRouting;
import com.ruoyi.production.pojo.ProductionOrderRoutingOperation;
/**
 * <p>
 * ç”Ÿäº§è®¢å•工艺路线表 æœåŠ¡ç±»
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-04-21 03:55:52
 */
import java.util.List;
public interface ProductionOrderRoutingService extends IService<ProductionOrderRouting> {
    ProductionOrderRouting listMain(Long orderId);
    List<ProductionOrderRoutingOperation> listItem(Long orderId);
}
src/main/java/com/ruoyi/production/service/ProductionOrderService.java
@@ -1,16 +1,25 @@
package com.ruoyi.production.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.production.bean.dto.ProductionOrderDto;
import com.ruoyi.production.bean.vo.ProductionOrderVo;
import com.ruoyi.production.pojo.ProductionOrder;
/**
 * <p>
 * ç”Ÿäº§è®¢å•表 æœåŠ¡ç±»
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-04-21 03:55:52
 */
import java.util.List;
public interface ProductionOrderService extends IService<ProductionOrder> {
    IPage<ProductionOrderVo> pageProductionOrder(Page<ProductionOrderDto> page, ProductionOrderDto productionOrderDto);
    List<ProductionOrderVo> listProductionOrder(ProductionOrderDto productionOrderDto);
    ProductionOrderVo getProductionOrderInfo(Long id);
    boolean saveProductionOrder(ProductionOrder productionOrder);
    boolean removeProductionOrder(List<Long> ids);
    int syncProductionOrderSnapshot(Long productionOrderId);
}
src/main/java/com/ruoyi/production/service/ProductionPlanService.java
@@ -6,9 +6,9 @@
import com.ruoyi.production.bean.dto.ProductionPlanDto;
import com.ruoyi.production.bean.vo.ProductionPlanVo;
import com.ruoyi.production.pojo.ProductionPlan;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
/**
@@ -21,7 +21,7 @@
 */
public interface ProductionPlanService extends IService<ProductionPlan> {
    IPage<ProductionPlanVo> listPage(Page page, ProductionPlanDto productionPlanDto);
    IPage<ProductionPlanVo> listPage(Page<ProductionPlanDto> page, ProductionPlanDto productionPlanDto);
    /**
     * æ‰‹åŠ¨åŒæ­¥
src/main/java/com/ruoyi/production/service/ProductionProductInputService.java
@@ -1,16 +1,11 @@
package com.ruoyi.production.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.production.bean.dto.ProductionProductInputDto;
import com.ruoyi.production.pojo.ProductionProductInput;
/**
 * <p>
 * ç”Ÿäº§æŠ¥å·¥æŠ•入表 æœåŠ¡ç±»
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-04-21 03:55:52
 */
public interface ProductionProductInputService extends IService<ProductionProductInput> {
    IPage<ProductionProductInputDto> listPageProductionProductInputDto(Page page, ProductionProductInputDto productionProductInputDto);
}
src/main/java/com/ruoyi/production/service/ProductionProductMainService.java
@@ -1,16 +1,26 @@
package com.ruoyi.production.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.production.bean.dto.ProductionProductMainDto;
import com.ruoyi.production.pojo.ProductionProductMain;
/**
 * <p>
 * ç”Ÿäº§æŠ¥å·¥è¡¨ æœåŠ¡ç±»
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-04-21 03:55:52
 */
public interface ProductionProductMainService extends IService<ProductionProductMain> {
import java.util.ArrayList;
import java.util.List;
public interface ProductionProductMainService extends IService<ProductionProductMain> {
    IPage<ProductionProductMainDto> listPageProductionProductMainDto(Page page, ProductionProductMainDto productionProductMainDto);
    IPage<ProductionProductMainDto> pageProductionProductMain(Page page, ProductionProductMainDto productionProductMainDto);
    ProductionProductMainDto getProductionProductMainInfo(Long id);
    Boolean addProductMain(ProductionProductMainDto productionProductMainDto);
    Boolean saveProductionProductMain(ProductionProductMainDto productionProductMainDto);
    Boolean removeProductMain(Long id);
    ArrayList<Long> listMain(List<Long> idList);
}
src/main/java/com/ruoyi/production/service/ProductionProductOutputService.java
@@ -1,16 +1,11 @@
package com.ruoyi.production.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.production.bean.dto.ProductionProductOutputDto;
import com.ruoyi.production.pojo.ProductionProductOutput;
/**
 * <p>
 * ç”Ÿäº§æŠ¥å·¥äº§å‡ºè¡¨ æœåŠ¡ç±»
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-04-21 03:55:52
 */
public interface ProductionProductOutputService extends IService<ProductionProductOutput> {
    IPage<ProductionProductOutputDto> listPageProductionProductOutputDto(Page page, ProductionProductOutputDto productionProductOutputDto);
}
src/main/java/com/ruoyi/production/service/SalesLedgerProductionAccountingService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,8 @@
package com.ruoyi.production.service;
import com.ruoyi.production.bean.dto.UserAccountDto;
import com.ruoyi.production.bean.dto.UserProductionAccountingDto;
public interface SalesLedgerProductionAccountingService {
    UserAccountDto getByUserId(UserProductionAccountingDto dto);
}
src/main/java/com/ruoyi/production/service/impl/ProductionOperationTaskServiceImpl.java
@@ -1,20 +1,64 @@
package com.ruoyi.production.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.production.bean.dto.ProductionOperationTaskDto;
import com.ruoyi.production.bean.vo.ProductionOperationTaskVo;
import com.ruoyi.production.mapper.ProductionOperationTaskMapper;
import com.ruoyi.production.pojo.ProductionOperationTask;
import com.ruoyi.production.service.ProductionOperationTaskService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
/**
 * <p>
 * ç”Ÿäº§å·¥å•表 æœåŠ¡å®žçŽ°ç±»
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-04-21 03:55:52
 */
@Service
public class ProductionOperationTaskServiceImpl extends ServiceImpl<ProductionOperationTaskMapper, ProductionOperationTask> implements ProductionOperationTaskService {
import java.util.List;
@Service
@RequiredArgsConstructor
public class ProductionOperationTaskServiceImpl extends ServiceImpl<ProductionOperationTaskMapper, ProductionOperationTask>
        implements ProductionOperationTaskService {
    @Override
    public IPage<ProductionOperationTaskVo> pageProductionOperationTask(Page<ProductionOperationTaskDto> page,
                                                                         ProductionOperationTaskDto dto) {
        Page<ProductionOperationTask> entityPage = new Page<>(page.getCurrent(), page.getSize(), page.getTotal());
        return this.page(entityPage, buildQueryWrapper(dto)).convert(item -> BeanUtil.copyProperties(item, ProductionOperationTaskVo.class));
    }
    @Override
    public List<ProductionOperationTaskVo> listProductionOperationTask(ProductionOperationTaskDto dto) {
        return BeanUtil.copyToList(this.list(buildQueryWrapper(dto)), ProductionOperationTaskVo.class);
    }
    @Override
    public ProductionOperationTaskVo getProductionOperationTaskInfo(Long id) {
        ProductionOperationTask item = this.getById(id);
        return item == null ? null : BeanUtil.copyProperties(item, ProductionOperationTaskVo.class);
    }
    @Override
    public boolean saveProductionOperationTask(ProductionOperationTask productionOperationTask) {
        return this.saveOrUpdate(productionOperationTask);
    }
    @Override
    public boolean removeProductionOperationTask(List<Long> ids) {
        return ids != null && !ids.isEmpty() && this.removeByIds(ids);
    }
    private LambdaQueryWrapper<ProductionOperationTask> buildQueryWrapper(ProductionOperationTaskDto dto) {
        ProductionOperationTask query = dto == null ? new ProductionOperationTask() : dto;
        return Wrappers.<ProductionOperationTask>lambdaQuery()
                .eq(query.getId() != null, ProductionOperationTask::getId, query.getId())
                .eq(query.getProductionOrderId() != null, ProductionOperationTask::getProductionOrderId, query.getProductionOrderId())
                .eq(query.getTechnologyRoutingOperationId() != null,
                        ProductionOperationTask::getTechnologyRoutingOperationId, query.getTechnologyRoutingOperationId())
                .eq(query.getStatus() != null, ProductionOperationTask::getStatus, query.getStatus())
                .like(query.getWorkOrderNo() != null && !query.getWorkOrderNo().trim().isEmpty(),
                        ProductionOperationTask::getWorkOrderNo, query.getWorkOrderNo())
                .orderByDesc(ProductionOperationTask::getId);
    }
}
src/main/java/com/ruoyi/production/service/impl/ProductionOrderRoutingOperationParamServiceImpl.java
@@ -1,20 +1,210 @@
package com.ruoyi.production.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.production.bean.dto.ProductionOrderRoutingOperationParamDto;
import com.ruoyi.production.bean.dto.ProductionOrderRoutingOperationParamSyncDto;
import com.ruoyi.production.bean.vo.ProductionOrderRoutingOperationParamVo;
import com.ruoyi.production.mapper.ProductionOrderMapper;
import com.ruoyi.production.mapper.ProductionOrderRoutingOperationMapper;
import com.ruoyi.production.mapper.ProductionOrderRoutingOperationParamMapper;
import com.ruoyi.production.pojo.ProductionOrder;
import com.ruoyi.production.pojo.ProductionOrderRoutingOperation;
import com.ruoyi.production.pojo.ProductionOrderRoutingOperationParam;
import com.ruoyi.production.service.ProductionOrderRoutingOperationParamService;
import com.ruoyi.technology.mapper.TechnologyRoutingOperationParamMapper;
import com.ruoyi.technology.pojo.TechnologyRoutingOperationParam;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
 * <p>
 * ç”Ÿäº§è®¢å•工艺路线工序参数表 æœåŠ¡å®žçŽ°ç±»
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-04-21 03:55:52
 */
import java.util.List;
@Service
public class ProductionOrderRoutingOperationParamServiceImpl extends ServiceImpl<ProductionOrderRoutingOperationParamMapper, ProductionOrderRoutingOperationParam> implements ProductionOrderRoutingOperationParamService {
@Transactional(rollbackFor = Exception.class)
@RequiredArgsConstructor
public class ProductionOrderRoutingOperationParamServiceImpl extends ServiceImpl<ProductionOrderRoutingOperationParamMapper, ProductionOrderRoutingOperationParam>
        implements ProductionOrderRoutingOperationParamService {
    private final ProductionOrderRoutingOperationParamMapper productionOrderRoutingOperationParamMapper;
    private final ProductionOrderRoutingOperationMapper productionOrderRoutingOperationMapper;
    private final ProductionOrderMapper productionOrderMapper;
    private final TechnologyRoutingOperationParamMapper technologyRoutingOperationParamMapper;
    @Override
    public IPage<ProductionOrderRoutingOperationParamVo> pageProductionOrderRoutingOperationParam(Page<ProductionOrderRoutingOperationParamDto> page,
                                                                                                  ProductionOrderRoutingOperationParamDto dto) {
        Page<ProductionOrderRoutingOperationParam> entityPage = new Page<>(page.getCurrent(), page.getSize(), page.getTotal());
        return this.page(entityPage, buildQueryWrapper(dto))
                .convert(item -> BeanUtil.copyProperties(item, ProductionOrderRoutingOperationParamVo.class));
    }
    @Override
    public List<ProductionOrderRoutingOperationParamVo> listProductionOrderRoutingOperationParam(ProductionOrderRoutingOperationParamDto dto) {
        return BeanUtil.copyToList(this.list(buildQueryWrapper(dto)), ProductionOrderRoutingOperationParamVo.class);
    }
    @Override
    public ProductionOrderRoutingOperationParamVo getProductionOrderRoutingOperationParamInfo(Long id) {
        ProductionOrderRoutingOperationParam item = this.getById(id);
        return item == null ? null : BeanUtil.copyProperties(item, ProductionOrderRoutingOperationParamVo.class);
    }
    @Override
    public boolean saveProductionOrderRoutingOperationParam(ProductionOrderRoutingOperationParam item) {
        ProductionOrderRoutingOperation routingOperation = getRoutingOperation(item.getTechnologyRoutingOperationId());
        fillFromSourceParam(item, routingOperation);
        validateManualFields(item);
        checkDuplicate(item);
        return this.saveOrUpdate(item);
    }
    @Override
    public boolean removeProductionOrderRoutingOperationParam(Long id) {
        return this.removeById(id);
    }
    @Override
    public int syncProductionOrderRoutingOperationParam(ProductionOrderRoutingOperationParamSyncDto syncDto) {
        if (syncDto == null || syncDto.getProductionOrderRoutingOperationId() == null) {
            throw new ServiceException("productionOrderRoutingOperationId is required");
        }
        ProductionOrderRoutingOperation routingOperation = getRoutingOperation(syncDto.getProductionOrderRoutingOperationId());
        List<TechnologyRoutingOperationParam> sourceParamList = technologyRoutingOperationParamMapper.selectList(
                Wrappers.<TechnologyRoutingOperationParam>lambdaQuery()
                        .eq(TechnologyRoutingOperationParam::getTechnologyRoutingOperationId, routingOperation.getTechnologyRoutingOperationId())
                        .orderByAsc(TechnologyRoutingOperationParam::getId)
        );
        boolean replaceExisting = syncDto.getReplaceExisting() == null || syncDto.getReplaceExisting();
        if (replaceExisting) {
            productionOrderRoutingOperationParamMapper.delete(
                    Wrappers.<ProductionOrderRoutingOperationParam>lambdaQuery()
                            .eq(ProductionOrderRoutingOperationParam::getTechnologyRoutingOperationId, routingOperation.getId())
            );
        }
        int successCount = 0;
        for (TechnologyRoutingOperationParam sourceParam : sourceParamList) {
            boolean exists = productionOrderRoutingOperationParamMapper.selectCount(
                    Wrappers.<ProductionOrderRoutingOperationParam>lambdaQuery()
                            .eq(ProductionOrderRoutingOperationParam::getTechnologyRoutingOperationId, routingOperation.getId())
                            .eq(ProductionOrderRoutingOperationParam::getTechnologyRoutingOperationParamId, sourceParam.getId())
            ) > 0;
            if (!replaceExisting && exists) {
                continue;
            }
            ProductionOrderRoutingOperationParam target = new ProductionOrderRoutingOperationParam();
            target.setTechnologyRoutingOperationId(routingOperation.getId());
            target.setTechnologyRoutingOperationParamId(sourceParam.getId());
            target.setProductionOrderId(routingOperation.getProductionOrderId());
            target.setTechnologyOperationId(sourceParam.getTechnologyOperationId());
            target.setTechnologyOperationParamId(sourceParam.getTechnologyOperationParamId());
            target.setParamId(sourceParam.getParamId());
            target.setParamCode(sourceParam.getParamCode());
            target.setParamName(sourceParam.getParamName());
            target.setParamType(sourceParam.getParamType());
            target.setParamFormat(sourceParam.getParamFormat());
            target.setUnit(sourceParam.getUnit());
            target.setIsRequired(sourceParam.getIsRequired());
            target.setRemark(sourceParam.getRemark());
            target.setStandardValue(sourceParam.getStandardValue());
            productionOrderRoutingOperationParamMapper.insert(target);
            successCount++;
        }
        return successCount;
    }
    private LambdaQueryWrapper<ProductionOrderRoutingOperationParam> buildQueryWrapper(ProductionOrderRoutingOperationParamDto dto) {
        ProductionOrderRoutingOperationParam query = dto == null ? new ProductionOrderRoutingOperationParam() : dto;
        return Wrappers.<ProductionOrderRoutingOperationParam>lambdaQuery()
                .eq(query.getId() != null, ProductionOrderRoutingOperationParam::getId, query.getId())
                .eq(query.getProductionOrderId() != null, ProductionOrderRoutingOperationParam::getProductionOrderId, query.getProductionOrderId())
                .eq(query.getTechnologyRoutingOperationId() != null,
                        ProductionOrderRoutingOperationParam::getTechnologyRoutingOperationId, query.getTechnologyRoutingOperationId())
                .eq(query.getTechnologyOperationId() != null,
                        ProductionOrderRoutingOperationParam::getTechnologyOperationId, query.getTechnologyOperationId())
                .eq(query.getTechnologyRoutingOperationParamId() != null,
                        ProductionOrderRoutingOperationParam::getTechnologyRoutingOperationParamId, query.getTechnologyRoutingOperationParamId())
                .eq(query.getTechnologyOperationParamId() != null,
                        ProductionOrderRoutingOperationParam::getTechnologyOperationParamId, query.getTechnologyOperationParamId())
                .like(query.getParamCode() != null && !query.getParamCode().trim().isEmpty(),
                        ProductionOrderRoutingOperationParam::getParamCode, query.getParamCode())
                .like(query.getParamName() != null && !query.getParamName().trim().isEmpty(),
                        ProductionOrderRoutingOperationParam::getParamName, query.getParamName())
                .orderByAsc(ProductionOrderRoutingOperationParam::getTechnologyRoutingOperationId)
                .orderByAsc(ProductionOrderRoutingOperationParam::getId);
    }
    private ProductionOrderRoutingOperation getRoutingOperation(Long productionOrderRoutingOperationId) {
        if (productionOrderRoutingOperationId == null) {
            throw new ServiceException("productionOrderRoutingOperationId is required");
        }
        ProductionOrderRoutingOperation routingOperation = productionOrderRoutingOperationMapper.selectById(productionOrderRoutingOperationId);
        if (routingOperation == null) {
            throw new ServiceException("Production order routing operation not found");
        }
        return routingOperation;
    }
    private void fillFromSourceParam(ProductionOrderRoutingOperationParam item, ProductionOrderRoutingOperation routingOperation) {
        item.setTechnologyRoutingOperationId(routingOperation.getId());
        item.setProductionOrderId(routingOperation.getProductionOrderId());
        ProductionOrder productionOrder = productionOrderMapper.selectById(routingOperation.getProductionOrderId());
        if (productionOrder == null) {
            throw new ServiceException("Production order not found");
        }
        if (item.getTechnologyRoutingOperationParamId() == null) {
            return;
        }
        TechnologyRoutingOperationParam sourceParam = technologyRoutingOperationParamMapper.selectById(item.getTechnologyRoutingOperationParamId());
        if (sourceParam == null) {
            throw new ServiceException("Technology routing operation param not found");
        }
        if (!routingOperation.getTechnologyRoutingOperationId().equals(sourceParam.getTechnologyRoutingOperationId())) {
            throw new ServiceException("Source param does not belong to routing operation");
        }
        item.setTechnologyOperationId(sourceParam.getTechnologyOperationId());
        item.setTechnologyOperationParamId(sourceParam.getTechnologyOperationParamId());
        item.setParamId(sourceParam.getParamId());
        item.setParamCode(sourceParam.getParamCode());
        item.setParamName(sourceParam.getParamName());
        item.setParamType(sourceParam.getParamType());
        item.setParamFormat(sourceParam.getParamFormat());
        item.setUnit(sourceParam.getUnit());
        item.setIsRequired(sourceParam.getIsRequired());
        if (item.getRemark() == null || item.getRemark().trim().isEmpty()) {
            item.setRemark(sourceParam.getRemark());
        }
        if (item.getStandardValue() == null) {
            item.setStandardValue(sourceParam.getStandardValue());
        }
    }
    private void validateManualFields(ProductionOrderRoutingOperationParam item) {
        if (item.getParamCode() == null || item.getParamCode().trim().isEmpty()) {
            throw new ServiceException("paramCode is required");
        }
        if (item.getParamName() == null || item.getParamName().trim().isEmpty()) {
            throw new ServiceException("paramName is required");
        }
    }
    private void checkDuplicate(ProductionOrderRoutingOperationParam item) {
        boolean duplicate = productionOrderRoutingOperationParamMapper.selectCount(
                Wrappers.<ProductionOrderRoutingOperationParam>lambdaQuery()
                        .eq(ProductionOrderRoutingOperationParam::getTechnologyRoutingOperationId, item.getTechnologyRoutingOperationId())
                        .eq(item.getTechnologyRoutingOperationParamId() != null,
                                ProductionOrderRoutingOperationParam::getTechnologyRoutingOperationParamId, item.getTechnologyRoutingOperationParamId())
                        .eq(item.getTechnologyRoutingOperationParamId() == null && item.getParamCode() != null,
                                ProductionOrderRoutingOperationParam::getParamCode, item.getParamCode())
                        .ne(item.getId() != null, ProductionOrderRoutingOperationParam::getId, item.getId())
        ) > 0;
        if (duplicate) {
            throw new ServiceException("Duplicate production order routing operation param");
        }
    }
}
src/main/java/com/ruoyi/production/service/impl/ProductionOrderRoutingOperationServiceImpl.java
@@ -1,20 +1,142 @@
package com.ruoyi.production.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.production.mapper.ProductionOperationTaskMapper;
import com.ruoyi.production.mapper.ProductionOrderRoutingOperationMapper;
import com.ruoyi.production.mapper.ProductionProductMainMapper;
import com.ruoyi.production.pojo.ProductionOperationTask;
import com.ruoyi.production.pojo.ProductionOrderRoutingOperation;
import com.ruoyi.production.pojo.ProductionProductMain;
import com.ruoyi.production.service.ProductionOrderRoutingOperationService;
import com.ruoyi.production.service.ProductionProductMainService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
 * <p>
 * ç”Ÿäº§è®¢å•工艺路线工序表 æœåŠ¡å®žçŽ°ç±»
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-04-21 03:55:52
 */
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.List;
@Service
public class ProductionOrderRoutingOperationServiceImpl extends ServiceImpl<ProductionOrderRoutingOperationMapper, ProductionOrderRoutingOperation> implements ProductionOrderRoutingOperationService {
@Transactional(rollbackFor = Exception.class)
@RequiredArgsConstructor
public class ProductionOrderRoutingOperationServiceImpl extends ServiceImpl<ProductionOrderRoutingOperationMapper, ProductionOrderRoutingOperation>
        implements ProductionOrderRoutingOperationService {
    private final ProductionOrderRoutingOperationMapper productionOrderRoutingOperationMapper;
    private final ProductionOperationTaskMapper productionOperationTaskMapper;
    private final ProductionProductMainMapper productionProductMainMapper;
    private final ProductionProductMainService productionProductMainService;
    @Override
    public R addRouteItem(ProductionOrderRoutingOperation productionOrderRoutingOperation) {
        int insert = productionOrderRoutingOperationMapper.insert(productionOrderRoutingOperation);
        String datePrefix = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        if (insert > 0) {
            ProductionOperationTask lastTask = productionOperationTaskMapper.selectOne(
                    Wrappers.<ProductionOperationTask>lambdaQuery()
                            .likeRight(ProductionOperationTask::getWorkOrderNo, "GD" + datePrefix)
                            .orderByDesc(ProductionOperationTask::getWorkOrderNo)
                            .last("limit 1"));
            int sequenceNumber = 1;
            if (lastTask != null && lastTask.getWorkOrderNo() != null) {
                String lastNo = lastTask.getWorkOrderNo();
                if (lastNo.startsWith("GD" + datePrefix)) {
                    String seqStr = lastNo.substring(("GD" + datePrefix).length());
                    try {
                        sequenceNumber = Integer.parseInt(seqStr) + 1;
                    } catch (NumberFormatException e) {
                        sequenceNumber = 1;
                    }
                }
            }
            String workOrderNoStr = "GD" + String.format("%s%03d", datePrefix, sequenceNumber);
            ProductionOperationTask productionOperationTask = new ProductionOperationTask();
            productionOperationTask.setTechnologyRoutingOperationId(productionOrderRoutingOperation.getId());
            productionOperationTask.setProductionOrderId(productionOrderRoutingOperation.getProductionOrderId());
            productionOperationTask.setPlanQuantity(BigDecimal.ZERO);
            productionOperationTask.setCompleteQuantity(BigDecimal.ZERO);
            productionOperationTask.setWorkOrderNo(workOrderNoStr);
            productionOperationTask.setStatus(1);
            productionOperationTaskMapper.insert(productionOperationTask);
        }
        return R.ok();
    }
    @Override
    public R deleteRouteItem(Long id) {
        try {
            ProductionOperationTask productionOperationTask = productionOperationTaskMapper.selectOne(
                    new LambdaQueryWrapper<ProductionOperationTask>()
                            .eq(ProductionOperationTask::getTechnologyRoutingOperationId, id)
                            .last("limit 1"));
            if (productionOperationTask == null) {
                throw new RuntimeException("删除失败:未找到关联的生产工单");
            }
            if (productionOperationTask.getCompleteQuantity() != null
                    && BigDecimal.ZERO.compareTo(productionOperationTask.getCompleteQuantity()) < 0) {
                throw new RuntimeException("删除失败:该工单已开始生产,请先删除生产报工");
            }
            List<ProductionProductMain> productionProductMains = productionProductMainMapper.selectList(
                    new LambdaQueryWrapper<ProductionProductMain>()
                            .eq(ProductionProductMain::getProductionOperationTaskId, productionOperationTask.getId()));
            for (ProductionProductMain main : productionProductMains) {
                productionProductMainService.removeProductMain(main.getId());
            }
            Long productionOrderId = productionOperationTask.getProductionOrderId();
            Long routingId = null;
            ProductionOrderRoutingOperation deleteItem = productionOrderRoutingOperationMapper.selectById(id);
            if (deleteItem != null) {
                routingId = deleteItem.getTechnologyRoutingId();
            }
            productionOperationTaskMapper.delete(new LambdaQueryWrapper<ProductionOperationTask>()
                    .eq(ProductionOperationTask::getTechnologyRoutingOperationId, id));
            productionOrderRoutingOperationMapper.deleteById(id);
            if (routingId != null) {
                List<ProductionOrderRoutingOperation> operationList = productionOrderRoutingOperationMapper.selectList(
                        Wrappers.<ProductionOrderRoutingOperation>lambdaQuery()
                                .eq(ProductionOrderRoutingOperation::getTechnologyRoutingId, routingId)
                                .eq(ProductionOrderRoutingOperation::getProductionOrderId, productionOrderId)
                                .orderByAsc(ProductionOrderRoutingOperation::getDragSort));
                for (int i = 0; i < operationList.size(); i++) {
                    ProductionOrderRoutingOperation item = operationList.get(i);
                    if (!Integer.valueOf(i + 1).equals(item.getDragSort())) {
                        item.setDragSort(i + 1);
                        productionOrderRoutingOperationMapper.updateById(item);
                    }
                }
            }
            return R.ok();
        } catch (Exception e) {
            throw new RuntimeException("删除生产工艺路线失败:" + e.getMessage());
        }
    }
    @Override
    public int sortRouteItem(ProductionOrderRoutingOperation productionOrderRoutingOperation) {
        ProductionOrderRoutingOperation oldItem = productionOrderRoutingOperationMapper.selectById(productionOrderRoutingOperation.getId());
        List<ProductionOrderRoutingOperation> operationList = productionOrderRoutingOperationMapper.selectList(
                Wrappers.<ProductionOrderRoutingOperation>lambdaQuery()
                        .eq(ProductionOrderRoutingOperation::getTechnologyRoutingId, oldItem.getTechnologyRoutingId())
                        .orderByAsc(ProductionOrderRoutingOperation::getDragSort));
        Integer targetPosition = productionOrderRoutingOperation.getDragSort();
        if (targetPosition != null && targetPosition >= 1) {
            operationList.removeIf(item -> item.getId().equals(oldItem.getId()));
            operationList.add(targetPosition - 1, oldItem);
            for (int i = 0; i < operationList.size(); i++) {
                ProductionOrderRoutingOperation item = operationList.get(i);
                int dragSort = i + 1;
                if (!Integer.valueOf(dragSort).equals(item.getDragSort())) {
                    item.setDragSort(dragSort);
                    productionOrderRoutingOperationMapper.updateById(item);
                }
            }
            return 1;
        }
        return 0;
    }
}
src/main/java/com/ruoyi/production/service/impl/ProductionOrderRoutingServiceImpl.java
@@ -1,20 +1,39 @@
package com.ruoyi.production.service.impl;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.production.mapper.ProductionOrderRoutingMapper;
import com.ruoyi.production.mapper.ProductionOrderRoutingOperationMapper;
import com.ruoyi.production.pojo.ProductionOrderRouting;
import com.ruoyi.production.pojo.ProductionOrderRoutingOperation;
import com.ruoyi.production.service.ProductionOrderRoutingService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
/**
 * <p>
 * ç”Ÿäº§è®¢å•工艺路线表 æœåŠ¡å®žçŽ°ç±»
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-04-21 03:55:52
 */
import java.util.List;
@Service
@RequiredArgsConstructor
public class ProductionOrderRoutingServiceImpl extends ServiceImpl<ProductionOrderRoutingMapper, ProductionOrderRouting> implements ProductionOrderRoutingService {
    private final ProductionOrderRoutingMapper productionOrderRoutingMapper;
    private final ProductionOrderRoutingOperationMapper productionOrderRoutingOperationMapper;
    @Override
    public ProductionOrderRouting listMain(Long orderId) {
        return productionOrderRoutingMapper.selectOne(
                Wrappers.<ProductionOrderRouting>lambdaQuery()
                        .eq(ProductionOrderRouting::getProductionOrderId, orderId)
                        .orderByDesc(ProductionOrderRouting::getId)
                        .last("limit 1"));
    }
    @Override
    public List<ProductionOrderRoutingOperation> listItem(Long orderId) {
        return productionOrderRoutingOperationMapper.selectList(
                Wrappers.<ProductionOrderRoutingOperation>lambdaQuery()
                        .eq(ProductionOrderRoutingOperation::getProductionOrderId, orderId)
                        .orderByAsc(ProductionOrderRoutingOperation::getDragSort)
                        .orderByAsc(ProductionOrderRoutingOperation::getId));
    }
}
src/main/java/com/ruoyi/production/service/impl/ProductionOrderServiceImpl.java
@@ -1,20 +1,317 @@
package com.ruoyi.production.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.production.bean.dto.ProductionOrderDto;
import com.ruoyi.production.bean.vo.ProductionOrderVo;
import com.ruoyi.production.mapper.ProductionBomStructureMapper;
import com.ruoyi.production.mapper.ProductionOperationTaskMapper;
import com.ruoyi.production.mapper.ProductionOrderBomMapper;
import com.ruoyi.production.mapper.ProductionOrderMapper;
import com.ruoyi.production.mapper.ProductionOrderRoutingMapper;
import com.ruoyi.production.mapper.ProductionOrderRoutingOperationMapper;
import com.ruoyi.production.mapper.ProductionOrderRoutingOperationParamMapper;
import com.ruoyi.production.mapper.ProductionProductMainMapper;
import com.ruoyi.production.pojo.ProductionBomStructure;
import com.ruoyi.production.pojo.ProductionOperationTask;
import com.ruoyi.production.pojo.ProductionOrder;
import com.ruoyi.production.pojo.ProductionOrderBom;
import com.ruoyi.production.pojo.ProductionOrderRouting;
import com.ruoyi.production.pojo.ProductionOrderRoutingOperation;
import com.ruoyi.production.pojo.ProductionOrderRoutingOperationParam;
import com.ruoyi.production.pojo.ProductionProductMain;
import com.ruoyi.production.service.ProductionOrderService;
import com.ruoyi.technology.mapper.TechnologyBomMapper;
import com.ruoyi.technology.mapper.TechnologyBomStructureMapper;
import com.ruoyi.technology.mapper.TechnologyRoutingMapper;
import com.ruoyi.technology.mapper.TechnologyRoutingOperationMapper;
import com.ruoyi.technology.mapper.TechnologyRoutingOperationParamMapper;
import com.ruoyi.technology.pojo.TechnologyBom;
import com.ruoyi.technology.pojo.TechnologyBomStructure;
import com.ruoyi.technology.pojo.TechnologyRouting;
import com.ruoyi.technology.pojo.TechnologyRoutingOperation;
import com.ruoyi.technology.pojo.TechnologyRoutingOperationParam;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
 * <p>
 * ç”Ÿäº§è®¢å•表 æœåŠ¡å®žçŽ°ç±»
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-04-21 03:55:52
 */
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
@Service
@Transactional(rollbackFor = Exception.class)
@RequiredArgsConstructor
public class ProductionOrderServiceImpl extends ServiceImpl<ProductionOrderMapper, ProductionOrder> implements ProductionOrderService {
    private final ProductionOrderRoutingMapper productionOrderRoutingMapper;
    private final ProductionOrderRoutingOperationMapper productionOrderRoutingOperationMapper;
    private final ProductionOrderRoutingOperationParamMapper productionOrderRoutingOperationParamMapper;
    private final ProductionOperationTaskMapper productionOperationTaskMapper;
    private final ProductionOrderBomMapper productionOrderBomMapper;
    private final ProductionBomStructureMapper productionBomStructureMapper;
    private final ProductionProductMainMapper productionProductMainMapper;
    private final TechnologyRoutingMapper technologyRoutingMapper;
    private final TechnologyRoutingOperationMapper technologyRoutingOperationMapper;
    private final TechnologyRoutingOperationParamMapper technologyRoutingOperationParamMapper;
    private final TechnologyBomMapper technologyBomMapper;
    private final TechnologyBomStructureMapper technologyBomStructureMapper;
    @Override
    public com.baomidou.mybatisplus.core.metadata.IPage<ProductionOrderVo> pageProductionOrder(Page<ProductionOrderDto> page, ProductionOrderDto dto) {
        Page<ProductionOrder> entityPage = new Page<>(page.getCurrent(), page.getSize(), page.getTotal());
        return this.page(entityPage, buildQueryWrapper(dto)).convert(item -> BeanUtil.copyProperties(item, ProductionOrderVo.class));
    }
    @Override
    public List<ProductionOrderVo> listProductionOrder(ProductionOrderDto dto) {
        return BeanUtil.copyToList(this.list(buildQueryWrapper(dto)), ProductionOrderVo.class);
    }
    @Override
    public ProductionOrderVo getProductionOrderInfo(Long id) {
        ProductionOrder item = this.getById(id);
        return item == null ? null : BeanUtil.copyProperties(item, ProductionOrderVo.class);
    }
    @Override
    public boolean saveProductionOrder(ProductionOrder productionOrder) {
        ProductionOrder oldOrder = productionOrder.getId() == null ? null : this.getById(productionOrder.getId());
        if (productionOrder.getNpsNo() == null || productionOrder.getNpsNo().trim().isEmpty()) {
            productionOrder.setNpsNo(generateNextOrderNo());
        }
        if (productionOrder.getCompleteQuantity() == null) {
            productionOrder.setCompleteQuantity(BigDecimal.ZERO);
        }
        boolean saved = this.saveOrUpdate(productionOrder);
        if (!saved) {
            return false;
        }
        boolean needSync = productionOrder.getTechnologyRoutingId() != null
                && (oldOrder == null
                || !Objects.equals(oldOrder.getTechnologyRoutingId(), productionOrder.getTechnologyRoutingId())
                || productionOrderRoutingMapper.selectCount(Wrappers.<ProductionOrderRouting>lambdaQuery()
                        .eq(ProductionOrderRouting::getProductionOrderId, productionOrder.getId())) == 0);
        if (needSync) {
            syncProductionOrderSnapshot(productionOrder.getId());
        }
        return true;
    }
    @Override
    public boolean removeProductionOrder(List<Long> ids) {
        if (ids == null || ids.isEmpty()) {
            return false;
        }
        for (Long id : ids) {
            clearProductionSnapshot(id);
        }
        return this.removeByIds(ids);
    }
    @Override
    public int syncProductionOrderSnapshot(Long productionOrderId) {
        ProductionOrder productionOrder = this.getById(productionOrderId);
        if (productionOrder == null) {
            throw new ServiceException("Production order not found");
        }
        if (productionOrder.getTechnologyRoutingId() == null) {
            throw new ServiceException("technologyRoutingId is required");
        }
        TechnologyRouting technologyRouting = technologyRoutingMapper.selectById(productionOrder.getTechnologyRoutingId());
        if (technologyRouting == null) {
            throw new ServiceException("Technology routing not found");
        }
        clearProductionSnapshot(productionOrderId);
        ProductionOrderRouting orderRouting = new ProductionOrderRouting();
        orderRouting.setProductionOrderId(productionOrder.getId());
        orderRouting.setTechnologyRoutingId(technologyRouting.getId());
        orderRouting.setProductModelId(technologyRouting.getProductModelId());
        orderRouting.setProcessRouteCode(technologyRouting.getProcessRouteCode());
        orderRouting.setDescription(technologyRouting.getDescription());
        orderRouting.setBomId(technologyRouting.getBomId());
        productionOrderRoutingMapper.insert(orderRouting);
        int syncedParamCount = 0;
        List<TechnologyRoutingOperation> routingOperations = technologyRoutingOperationMapper.selectList(
                Wrappers.<TechnologyRoutingOperation>lambdaQuery()
                        .eq(TechnologyRoutingOperation::getTechnologyRoutingId, technologyRouting.getId())
                        .orderByAsc(TechnologyRoutingOperation::getDragSort)
                        .orderByAsc(TechnologyRoutingOperation::getId));
        for (TechnologyRoutingOperation sourceOperation : routingOperations) {
            ProductionOrderRoutingOperation targetOperation = new ProductionOrderRoutingOperation();
            targetOperation.setProductionOrderId(productionOrder.getId());
            targetOperation.setTechnologyRoutingOperationId(sourceOperation.getId());
            targetOperation.setTechnologyRoutingId(orderRouting.getId());
            targetOperation.setProductModelId(sourceOperation.getProductModelId());
            targetOperation.setDragSort(sourceOperation.getDragSort());
            targetOperation.setIsQuality(sourceOperation.getIsQuality());
            productionOrderRoutingOperationMapper.insert(targetOperation);
            ProductionOperationTask task = new ProductionOperationTask();
            task.setTechnologyRoutingOperationId(targetOperation.getId());
            task.setProductionOrderId(productionOrder.getId());
            task.setPlanQuantity(defaultDecimal(productionOrder.getQuantity()));
            task.setCompleteQuantity(BigDecimal.ZERO);
            task.setWorkOrderNo(generateNextTaskNo());
            task.setStatus(1);
            productionOperationTaskMapper.insert(task);
            List<TechnologyRoutingOperationParam> sourceParams = technologyRoutingOperationParamMapper.selectList(
                    Wrappers.<TechnologyRoutingOperationParam>lambdaQuery()
                            .eq(TechnologyRoutingOperationParam::getTechnologyRoutingOperationId, sourceOperation.getId())
                            .orderByAsc(TechnologyRoutingOperationParam::getId));
            for (TechnologyRoutingOperationParam sourceParam : sourceParams) {
                ProductionOrderRoutingOperationParam targetParam = new ProductionOrderRoutingOperationParam();
                targetParam.setProductionOrderId(productionOrder.getId());
                targetParam.setTechnologyRoutingOperationId(targetOperation.getId());
                targetParam.setTechnologyRoutingOperationParamId(sourceParam.getId());
                targetParam.setParamId(sourceParam.getParamId());
                targetParam.setTechnologyOperationId(sourceParam.getTechnologyOperationId());
                targetParam.setTechnologyOperationParamId(sourceParam.getTechnologyOperationParamId());
                targetParam.setParamCode(sourceParam.getParamCode());
                targetParam.setParamName(sourceParam.getParamName());
                targetParam.setParamType(sourceParam.getParamType());
                targetParam.setParamFormat(sourceParam.getParamFormat());
                targetParam.setUnit(sourceParam.getUnit());
                targetParam.setIsRequired(sourceParam.getIsRequired());
                targetParam.setRemark(sourceParam.getRemark());
                targetParam.setStandardValue(sourceParam.getStandardValue());
                productionOrderRoutingOperationParamMapper.insert(targetParam);
                syncedParamCount++;
            }
        }
        syncProductionOrderBomSnapshot(productionOrder, technologyRouting);
        return syncedParamCount;
    }
    private void syncProductionOrderBomSnapshot(ProductionOrder productionOrder, TechnologyRouting technologyRouting) {
        if (technologyRouting.getBomId() == null) {
            return;
        }
        TechnologyBom technologyBom = technologyBomMapper.selectById(technologyRouting.getBomId());
        if (technologyBom == null) {
            throw new ServiceException("Technology BOM not found");
        }
        List<TechnologyBomStructure> structureList = technologyBomStructureMapper.selectList(
                Wrappers.<TechnologyBomStructure>lambdaQuery()
                        .eq(TechnologyBomStructure::getBomId, technologyBom.getId())
                        .orderByAsc(TechnologyBomStructure::getId));
        TechnologyBomStructure root = structureList.stream().filter(item -> item.getParentId() == null).findFirst().orElse(null);
        ProductionOrderBom orderBom = new ProductionOrderBom();
        orderBom.setProductionOrderId(productionOrder.getId());
        orderBom.setBomId(Long.valueOf(technologyBom.getId()));
        orderBom.setProductModelId(root != null ? root.getProductModelId() : productionOrder.getProductModelId());
        orderBom.setTechnologyOperationId(root == null ? null : root.getOperationId());
        orderBom.setUnitQuantity(root != null && root.getUnitQuantity() != null ? root.getUnitQuantity() : BigDecimal.ONE);
        orderBom.setDemandedQuantity(root != null && root.getDemandedQuantity() != null ? root.getDemandedQuantity() : defaultDecimal(productionOrder.getQuantity()));
        orderBom.setUnit(root == null ? null : root.getUnit());
        productionOrderBomMapper.insert(orderBom);
        Map<Long, Long> idMap = new HashMap<>();
        for (TechnologyBomStructure source : structureList) {
            ProductionBomStructure target = new ProductionBomStructure();
            target.setProductionOrderId(productionOrder.getId());
            target.setProductionOrderBomId(orderBom.getId());
            target.setParentId(source.getParentId() == null ? null : idMap.get(source.getParentId()));
            target.setProductModelId(source.getProductModelId());
            target.setTechnologyOperationId(source.getOperationId());
            target.setUnitQuantity(source.getUnitQuantity());
            target.setDemandedQuantity(source.getDemandedQuantity());
            target.setUnit(source.getUnit());
            productionBomStructureMapper.insert(target);
            idMap.put(source.getId(), target.getId());
        }
    }
    private void clearProductionSnapshot(Long productionOrderId) {
        List<Long> taskIds = productionOperationTaskMapper.selectList(
                        Wrappers.<ProductionOperationTask>lambdaQuery()
                                .eq(ProductionOperationTask::getProductionOrderId, productionOrderId))
                .stream().map(ProductionOperationTask::getId).collect(Collectors.toList());
        if (!taskIds.isEmpty()) {
            boolean started = productionProductMainMapper.selectCount(
                    Wrappers.<ProductionProductMain>lambdaQuery()
                            .in(ProductionProductMain::getProductionOperationTaskId, taskIds)) > 0;
            if (started) {
                throw new ServiceException("Production order already started, snapshot cannot be regenerated");
            }
            productionOperationTaskMapper.delete(Wrappers.<ProductionOperationTask>lambdaQuery()
                    .eq(ProductionOperationTask::getProductionOrderId, productionOrderId));
        }
        productionOrderRoutingOperationParamMapper.delete(Wrappers.<ProductionOrderRoutingOperationParam>lambdaQuery()
                .eq(ProductionOrderRoutingOperationParam::getProductionOrderId, productionOrderId));
        productionOrderRoutingOperationMapper.delete(Wrappers.<ProductionOrderRoutingOperation>lambdaQuery()
                .eq(ProductionOrderRoutingOperation::getProductionOrderId, productionOrderId));
        productionOrderRoutingMapper.delete(Wrappers.<ProductionOrderRouting>lambdaQuery()
                .eq(ProductionOrderRouting::getProductionOrderId, productionOrderId));
        productionBomStructureMapper.delete(Wrappers.<ProductionBomStructure>lambdaQuery()
                .eq(ProductionBomStructure::getProductionOrderId, productionOrderId));
        productionOrderBomMapper.delete(Wrappers.<ProductionOrderBom>lambdaQuery()
                .eq(ProductionOrderBom::getProductionOrderId, productionOrderId));
    }
    private LambdaQueryWrapper<ProductionOrder> buildQueryWrapper(ProductionOrderDto dto) {
        ProductionOrder query = dto == null ? new ProductionOrder() : dto;
        return Wrappers.<ProductionOrder>lambdaQuery()
                .eq(query.getId() != null, ProductionOrder::getId, query.getId())
                .eq(query.getSalesLedgerId() != null, ProductionOrder::getSalesLedgerId, query.getSalesLedgerId())
                .eq(query.getProductModelId() != null, ProductionOrder::getProductModelId, query.getProductModelId())
                .eq(query.getTechnologyRoutingId() != null, ProductionOrder::getTechnologyRoutingId, query.getTechnologyRoutingId())
                .like(query.getNpsNo() != null && !query.getNpsNo().trim().isEmpty(), ProductionOrder::getNpsNo, query.getNpsNo())
                .orderByDesc(ProductionOrder::getId);
    }
    private String generateNextOrderNo() {
        String datePrefix = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        String prefix = "SC" + datePrefix;
        ProductionOrder latestOrder = this.getOne(Wrappers.<ProductionOrder>lambdaQuery()
                .likeRight(ProductionOrder::getNpsNo, prefix)
                .orderByDesc(ProductionOrder::getNpsNo)
                .last("limit 1"));
        int sequence = 1;
        if (latestOrder != null && latestOrder.getNpsNo() != null && latestOrder.getNpsNo().startsWith(prefix)) {
            try {
                sequence = Integer.parseInt(latestOrder.getNpsNo().substring(prefix.length())) + 1;
            } catch (NumberFormatException ignored) {
                sequence = 1;
            }
        }
        return prefix + String.format("%04d", sequence);
    }
    private String generateNextTaskNo() {
        String datePrefix = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        String prefix = "GD" + datePrefix;
        ProductionOperationTask lastTask = productionOperationTaskMapper.selectOne(
                Wrappers.<ProductionOperationTask>lambdaQuery()
                        .likeRight(ProductionOperationTask::getWorkOrderNo, prefix)
                        .orderByDesc(ProductionOperationTask::getWorkOrderNo)
                        .last("limit 1"));
        int sequence = 1;
        if (lastTask != null && lastTask.getWorkOrderNo() != null && lastTask.getWorkOrderNo().startsWith(prefix)) {
            try {
                sequence = Integer.parseInt(lastTask.getWorkOrderNo().substring(prefix.length())) + 1;
            } catch (NumberFormatException ignored) {
                sequence = 1;
            }
        }
        return prefix + String.format("%03d", sequence);
    }
    private BigDecimal defaultDecimal(BigDecimal value) {
        return value == null ? BigDecimal.ZERO : value;
    }
}
src/main/java/com/ruoyi/production/service/impl/ProductionPlanServiceImpl.java
@@ -1,558 +1,65 @@
//package com.ruoyi.production.service.impl;
//
//import com.alibaba.fastjson2.JSONArray;
//import com.alibaba.fastjson2.JSONObject;
//import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
//import com.baomidou.mybatisplus.core.metadata.IPage;
//import com.baomidou.mybatisplus.core.toolkit.Wrappers;
//import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
//import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
//import com.ruoyi.common.exception.ServiceException;
//import com.ruoyi.common.exception.base.BaseException;
//import com.ruoyi.common.utils.StringUtils;
//import com.ruoyi.common.utils.bean.BeanUtils;
//import com.ruoyi.common.utils.poi.ExcelUtil;
//import com.ruoyi.production.bean.dto.ProductionPlanDto;
//import com.ruoyi.production.bean.dto.ProductionPlanImportDto;
//import com.ruoyi.production.bean.vo.ProductionPlanVo;
//import com.ruoyi.production.mapper.ProductionPlanMapper;
//import com.ruoyi.production.pojo.ProductionPlan;
//import com.ruoyi.production.service.ProductionPlanService;
//import lombok.RequiredArgsConstructor;
//import org.springframework.stereotype.Service;
//import org.springframework.transaction.annotation.Transactional;
//import org.springframework.web.multipart.MultipartFile;
//
//import javax.servlet.http.HttpServletResponse;
//import java.math.BigDecimal;
//import java.time.Instant;
//import java.time.LocalDateTime;
//import java.time.ZoneId;
//import java.util.*;
//import java.util.concurrent.locks.ReentrantLock;
//import java.util.stream.Collectors;
//
///**
// * <p>
// * ç”Ÿäº§è®¡åˆ’表 æœåŠ¡å®žçŽ°ç±»
// * </p>
// *
// * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
// * @since 2026-04-21 02:11:10
// */
//@Service
//@RequiredArgsConstructor
//public class ProductionPlanServiceImpl extends ServiceImpl<ProductionPlanMapper, ProductionPlan> implements ProductionPlanService {
//
//    private ProductionPlanMapper productionPlanMapper;
//
//
//    /**
//     * åŒæ­¥é”ï¼Œç¡®ä¿æ‰‹åŠ¨å’Œå®šæ—¶ä»»åŠ¡ä¸åŒæ—¶æ‰§è¡Œ
//     */
//    private final ReentrantLock syncLock = new ReentrantLock();
//
//    @Override
//    public IPage<ProductionPlanVo> listPage(Page<ProductionPlanDto> page, ProductionPlanDto productionPlanDto) {
//
//        return productionPlanMapper.selectPage(page, null);
//    }
//
//    /**
//     * é¡µé¢æ‰‹åŠ¨åŒæ­¥
//     */
//    @Override
//    public void loadProdData() {
//        syncProdData(1);
//    }
//
//    /**
//     * å®šæ—¶ä»»åŠ¡åŒæ­¥
//     */
//    @Override
//    public void syncProdDataJob() {
//        syncProdData(2);
//    }
//
//    /**
//     * åˆå¹¶ç”Ÿäº§è®¡åˆ’
//     */
//    @Override
//    @Transactional(rollbackFor = Exception.class)
//    public boolean combine(ProductionPlanDto productionPlanDto) {
//        if (productionPlanDto.getIds() == null || productionPlanDto.getIds().isEmpty()) {
//            return false;
//        }
//
//        //  æŸ¥è¯¢ä¸»ç”Ÿäº§è®¡åˆ’
//        List<ProductionPlanDto> plans = productionPlanMapper.selectWithMaterialByIds(productionPlanDto.getIds());
//
//        if (plans == null || plans.isEmpty()) {
//            throw new ServiceException("下发失败,生产计划不存在");
//        }
//
//        //  æ ¡éªŒæ˜¯å¦å­˜åœ¨ä¸åŒçš„产品名称
//        String firstProductName = plans.get(0).getProductName();
//        if (plans.stream().anyMatch(p -> p.getProductName() == null || !p.getProductName().equals(firstProductName))) {
//            throw new BaseException("合并失败,存在不同的产品名称");
//        }
//
//        // æ ¡éªŒæ˜¯å¦å­˜åœ¨ä¸åŒçš„产品规格
//        String firstProductSpec = plans.get(0).getModel();
//        if (plans.stream().anyMatch(p -> p.getModel() == null || !p.getModel().equals(firstProductSpec))) {
//            throw new BaseException("合并失败,存在不同的产品规格");
//        }
//
//        // å åŠ å‰©ä½™æ–¹æ•°
//        BigDecimal totalRemainingVolume = plans.stream()
//                .map(ProductionPlan::getRemainingVolume)
//                .filter(Objects::nonNull)
//                .reduce(BigDecimal.ZERO, BigDecimal::add);
//        // åˆ¤æ–­ä¸‹å‘数量是否大于等于剩余方数
//        if (productionPlanDto.getTotalAssignedQuantity().compareTo(totalRemainingVolume) > 0) {
//            throw new BaseException("操作失败,下发数量不能大于剩余方数");
//        }
//
//        // åˆ›å»ºç”Ÿäº§è®¢å•
//        ProductOrder productOrder = new ProductOrder();
//        productOrder.setQuantity(productionPlanDto.getTotalAssignedQuantity());
//        productOrder.setPlanCompleteTime(productionPlanDto.getPlanCompleteTime());
//        productOrder.setStatus(ProductOrderStatusEnum.WAIT.getCode());
//        productOrder.setStrength(productionPlanDto.getStrength());
//        productOrder.setProductMaterialSkuId(plans.get(0).getProductMaterialSkuId());
//
//        Long orderId = productOrderService.insertProductOrder(productOrder);
//
//        //  å½“下发的产品为砌块或板材,就拉取BOM子集与工艺路线子集数据存入到附表中
//        if ("砌块".equals(productionPlanDto.getProductName())) {
//            productOrder.setRouteId(productionOrderAppendixService.populateBlocks(orderId, productionPlanDto));
//        }
//        if ("板材".equals(productionPlanDto.getProductName())) {
//            productOrder.setRouteId(productionOrderAppendixService.populatePlates(orderId, productionPlanDto));
//        }
//        //  æ›´æ–°ç»‘定的工艺路线
//        productOrderService.updateById(productOrder);
//
//        // æ ¹æ®ä¸‹å‘数量,从第一个生产计划开始分配方数
//        BigDecimal assignedVolume = BigDecimal.ZERO;
//        for (ProductionPlan plan : plans) {
//            BigDecimal volume = plan.getVolume();
//            if (volume == null) {
//                continue;
//            }
//            // è®¡ç®—剩余方数
//            BigDecimal remainingVolume = plan.getRemainingVolume();
//            if (remainingVolume.compareTo(BigDecimal.ZERO) <= 0) {
//                continue;
//            }
//
//            ProductOrderPlan productOrderPlan = new ProductOrderPlan();
//            productOrderPlan.setProductOrderId(productOrder.getId());
//            productOrderPlan.setProductionPlanId(plan.getId());
//
//            if (assignedVolume.add(remainingVolume).compareTo(productionPlanDto.getTotalAssignedQuantity()) >= 0) {
//                // æœ€åŽä¸€ä¸ªè®¡åˆ’,分配剩余方数
//                BigDecimal lastRemainingVolume = productionPlanDto.getTotalAssignedQuantity().subtract(assignedVolume);
//                BigDecimal assignedQuantity = Optional.ofNullable(plan.getAssignedQuantity()).orElse(BigDecimal.ZERO).add(lastRemainingVolume);
//                plan.setAssignedQuantity(assignedQuantity);
//                plan.setStatus(assignedQuantity.compareTo(plan.getVolume()) >= 0 ? 2 : 1);
//                productOrderPlan.setAssignedQuantity(lastRemainingVolume);
//                productionPlanMapper.updateById(plan);
//                productOrderPlanMapper.insert(productOrderPlan);
//                break;
//            }
//
//            // åˆ†é…å½“前计划方数
//            BigDecimal assignedQuantity = Optional.ofNullable(plan.getAssignedQuantity()).orElse(BigDecimal.ZERO).add(remainingVolume);
//            plan.setAssignedQuantity(assignedQuantity);
//            plan.setStatus(assignedQuantity.compareTo(plan.getVolume()) >= 0 ? 2 : 1);
//            productOrderPlan.setAssignedQuantity(remainingVolume);
//            // æ›´æ–°ç”Ÿäº§è®¡åˆ’
//            productionPlanMapper.updateById(plan);
//            // åˆ›å»ºå…³è”关系
//            productOrderPlanMapper.insert(productOrderPlan);
//            assignedVolume = assignedVolume.add(remainingVolume);
//        }
//
//        for (ProductionPlan plan : plans) {
//            BigDecimal assignedQuantity = Optional.ofNullable(plan.getAssignedQuantity()).orElse(BigDecimal.ZERO);
//            BigDecimal volume = Optional.ofNullable(plan.getVolume()).orElse(BigDecimal.ZERO);
//            if (assignedQuantity.compareTo(BigDecimal.ZERO) <= 0) {
//                plan.setStatus(0);
//            } else if (assignedQuantity.compareTo(volume) >= 0) {
//                plan.setStatus(2);
//            } else {
//                plan.setStatus(1);
//            }
//            productionPlanMapper.updateById(plan);
//        }
//        return true;
//    }
//
//    @Override
//    @Transactional(rollbackFor = Exception.class)
//    public boolean add(ProductionPlanDto productionPlanDto) {
//        if (StringUtils.isEmpty(productionPlanDto.getApplyNo())) {
//            throw new ServiceException("新增失败,申请单编号不能为空");
//        }
//        Long count = productionPlanMapper.selectCount(Wrappers.<ProductionPlan>lambdaQuery()
//                .eq(ProductionPlan::getApplyNo, productionPlanDto.getApplyNo()));
//        if (count > 0) {
//            throw new ServiceException("新增失败,申请单编号 " + productionPlanDto.getApplyNo() + " å·²å­˜åœ¨");
//        }
//        productionPlanDto.setDataSourceType(DataSourceTypeEnum.MANUAL.getCode());
//        productionPlanDto.setStatus(0);
//        productionPlanMapper.insert(productionPlanDto);
//        return true;
//    }
//
//    @Override
//    @Transactional(rollbackFor = Exception.class)
//    public boolean update(ProductionPlanDto productionPlanDto) {
//        if (productionPlanDto == null || productionPlanDto.getId() == null) {
//            throw new ServiceException("编辑失败,数据不能为空");
//        }
//        ProductionPlan productionPlan = getById(productionPlanDto.getId());
//        if (productionPlan == null) {
//            throw new ServiceException("编辑失败,主生产计划不存在");
//        }
//
//        if (StringUtils.isNotEmpty(productionPlanDto.getApplyNo())
//                && !productionPlanDto.getApplyNo().equals(productionPlan.getApplyNo())) {
//
//            Long count = productionPlanMapper.selectCount(Wrappers.<ProductionPlan>lambdaQuery()
//                    .eq(ProductionPlan::getApplyNo, productionPlanDto.getApplyNo())
//                    .ne(ProductionPlan::getId, productionPlanDto.getId())); // æŽ’除自身
//
//            if (count > 0) {
//                throw new ServiceException("编辑失败,申请单编号 " + productionPlanDto.getApplyNo() + " å·²è¢«å ç”¨");
//            }
//        }
//        // å·²ä¸‹å‘状态,不能编辑
//        if (productionPlan.getStatus() != 0) {
//            throw new BaseException("编辑失败,该生产计划已下发或部分下发状态,禁止编辑");
//        }
//
//        // æŸ¥è¯¢æ˜¯å¦æœ‰å…³è”订单
//        boolean hasProductOrderPlan = productOrderPlanMapper.selectList(Wrappers.<ProductOrderPlan>lambdaQuery()
//                        .eq(ProductOrderPlan::getProductionPlanId, productionPlanDto.getId()))
//                .stream().anyMatch(p -> p.getProductOrderId() != null);
//
//        if (hasProductOrderPlan) {
//            if (productionPlanDto.getVolume().compareTo(productionPlan.getVolume()) < 0) {
//                throw new BaseException("方数不能递减");
//            }
//        }
//
//        return productionPlanMapper.updateById(productionPlanDto) > 0;
//    }
//
//    @Override
//    @Transactional(rollbackFor = Exception.class)
//    public boolean delete(List<Long> ids) {
//        // å¦‚果存在已下发的计划,则不能删除
//        if (productionPlanMapper.selectList(Wrappers.<ProductionPlan>lambdaQuery().in(ProductionPlan::getId, ids)).stream().anyMatch(p -> p.getStatus() == 1 || p.getStatus() == 2)) {
//            throw new BaseException("删除失败,存在已下发或部分下发的计划");
//        }
//        // å¦‚果有关联订单,则不能删除
//        if (productOrderPlanMapper.selectList(Wrappers.<ProductOrderPlan>lambdaQuery().in(ProductOrderPlan::getProductionPlanId, ids)).stream().anyMatch(p -> p.getProductOrderId() != null)) {
//            throw new BaseException("删除失败,存在关联订单");
//        }
//
//        return productionPlanMapper.deleteBatchIds(ids) > 0;
//    }
//
//    /**
//     * åŒæ­¥æ•°æ®
//     */
//    @Transactional(rollbackFor = Exception.class)
//    public void syncProdData(Integer dataSyncType) {
//        if (!syncLock.tryLock()) {
//            log.warn("同步正在进行中,本次 {} åŒæ­¥è¯·æ±‚被跳过", dataSyncType == 1 ? "手动同步" : "定时任务同步");
//            return;
//        }
//
//        try {
//            JSONArray searchConditions = new JSONArray();
//            JSONObject condition = new JSONObject();
//            condition.put("key", "processApprovedResult");
//            JSONArray valueArray = new JSONArray();
//            valueArray.add("agree");
//
//            condition.put("value", valueArray);
//            condition.put("type", "ARRAY");
//            condition.put("operator", "in");
//            condition.put("componentName", "SelectField");
//            searchConditions.add(condition);
//
//            String searchFieldJson = searchConditions.toJSONString();
//
//            JSONArray dataArr = AliDingUtils.getFormDataList(aliDingConfig, aliDingConfig.getProducePlanFormUuid(), searchFieldJson, this, ProductionPlan::getFormModifiedTime);
//
//            if (dataArr.isEmpty()) {
//                log.info("没有更多新数据需要同步");
//                return;
//            }
//
//            //  è§£æžå¹¶ä¿å­˜æ•°æ®
//            List<ProductionPlan> list = parseProductionPlans(dataArr, dataSyncType, dataArr.size());
//            if (!list.isEmpty()) {
//                //  å¤„理更新或新增
//                int affected = processSaveOrUpdate(list);
//                log.info("数据同步完成,共同步 {} æ¡æ•°æ®", affected);
//            }
//
//        } catch (Exception e) {
//            log.error("同步生产计划异常", e);
//        } finally {
//            // é‡Šæ”¾é”
//            syncLock.unlock();
//        }
//    }
//
//    private List<ProductionPlan> parseProductionPlans(JSONArray dataArr, Integer dataSyncType, Integer totalCount) {
//        List<ProductionPlan> list = new ArrayList<>();
//        LocalDateTime now = LocalDateTime.now();
//
//        for (int i = 0; i < dataArr.size(); i++) {
//            JSONObject item = dataArr.getJSONObject(i);
//            String formInstanceId = item.getString("formInstanceId");
//            String serialNo = item.getString("serialNo");
//
//            JSONObject originator = item.getJSONObject("originator");
//            String originatorName = originator != null && originator.containsKey("userName")
//                    ? originator.getJSONObject("userName").getString("nameInChinese") : "未知";
//
//            JSONObject formData = item.getJSONObject("formData");
//            JSONArray tableArr = formData.getJSONArray("tableField_l7fytfcn");
//            if (tableArr == null || tableArr.isEmpty()) {
//                continue;
//            }
//
//            for (int j = 0; j < tableArr.size(); j++) {
//                JSONObject row = tableArr.getJSONObject(j);
//                ProductionPlan plan = new ProductionPlan();
//
//                plan.setFormInstanceId(formInstanceId);
//                plan.setSerialNo(serialNo);
//                plan.setApplyNo(formData.getString("textField_l7fytfco"));
//                plan.setCustomerName(formData.getString("textField_lbkozohg"));
//
//                String materialCode = row.getString("textField_l9xo62q5");
//                // æ ¹æ®ç‰©æ–™ç¼–码查询物料信息表,关联物料ID
//                if (StringUtils.isNotEmpty(materialCode)) {
//                    LambdaQueryWrapper<ProductMaterialSku> skuQueryWrapper = new LambdaQueryWrapper<>();
//                    skuQueryWrapper.eq(ProductMaterialSku::getMaterialCode, materialCode);
//                    ProductMaterialSku sku = productMaterialSkuService.getOne(skuQueryWrapper);
//                    if (sku != null) {
//                        plan.setProductMaterialSkuId(sku.getId());
//                    }
//                }
//
//                plan.setLength(row.getInteger("numberField_lb7lgatg_value"));
//                plan.setWidth(row.getInteger("numberField_lb7lgath_value"));
//                plan.setHeight(row.getInteger("numberField_lb7lgati_value"));
//                plan.setQuantity(row.getInteger("numberField_lb7lgatj_value"));
//                plan.setVolume(row.getBigDecimal("numberField_l7fytfd3_value"));
//                plan.setStrength(row.getString("radioField_m9urarr2_id"));
//
//                JSONArray dateArr = row.getJSONArray("cascadeDateField_lfxqqluw");
//                if (dateArr != null && dateArr.size() == 2) {
//                    try {
//                        long start = Long.parseLong(dateArr.getString(0));
//                        long end = Long.parseLong(dateArr.getString(1));
//
//                        Date startDate = Date.from(Instant.ofEpochMilli(start)
//                                .atZone(ZoneId.systemDefault())
//                                .toLocalDate()
//                                .atStartOfDay(ZoneId.systemDefault())
//                                .toInstant());
//                        Date endDate = Date.from(Instant.ofEpochMilli(end)
//                                .atZone(ZoneId.systemDefault())
//                                .toLocalDate()
//                                .atStartOfDay(ZoneId.systemDefault())
//                                .toInstant());
//
//                        plan.setStartDate(startDate);
//                        plan.setEndDate(endDate);
//                    } catch (Exception e) {
//                        log.warn("解析日期失败: {}", dateArr);
//                    }
//                }
//
//                plan.setSubmitter(originatorName);
//                plan.setSubmitOrg("宁夏中创绿能实业集团有限公司");
//                plan.setRemarkOne(formData.getString("textareaField_l7fytfcy"));
//                plan.setRemarkTwo(formData.getString("textField_l7fytfcx"));
//                plan.setCreatorName(originatorName);
//
//                JSONObject modifyUser = item.getJSONObject("modifyUser");
//                if (modifyUser != null && modifyUser.containsKey("userName")) {
//                    plan.setModifierName(modifyUser.getJSONObject("userName").getString("nameInChinese"));
//                }
//
//                plan.setFormCreatedTime(AliDingUtils.parseUtcTime(item.getString("createdTimeGMT")));
//                plan.setFormModifiedTime(AliDingUtils.parseUtcTime(item.getString("modifiedTimeGMT")));
//                plan.setDataSourceType(DataSourceTypeEnum.DING_TALK.getCode());
//                plan.setCreateTime(now);
//                plan.setUpdateTime(now);
//                plan.setTotalCount(totalCount);
//
//                list.add(plan);
//            }
//        }
//        return list;
//    }
//
//    private int processSaveOrUpdate(List<ProductionPlan> list) {
//        if (list == null || list.isEmpty()) {
//            return 0;
//        }
//        int affected = 0;
//
//        //  åŽ»é‡ formInstanceId
//        Set<String> formIds = list.stream()
//                .map(ProductionPlan::getFormInstanceId)
//                .collect(Collectors.toSet());
//
//        //  æŸ¥è¯¢æ•°æ®åº“已有数据
//        List<ProductionPlan> existList = this.list(new LambdaQueryWrapper<ProductionPlan>().in(ProductionPlan::getFormInstanceId, formIds));
//
//        //  Map (formInstanceId + materialCode)
//        Map<String, ProductionPlan> existMap = new HashMap<>();
//        for (ProductionPlan p : existList) {
//            String key = p.getFormInstanceId() + "_" + p.getProductMaterialSkuId();
//            existMap.put(key, p);
//        }
//
//        //  éåŽ†åŒæ­¥æ•°æ®
//        for (ProductionPlan plan : list) {
//            String key = plan.getFormInstanceId() + "_" + plan.getProductMaterialSkuId();
//            ProductionPlan exist = existMap.get(key);
//            if (exist == null) {
//                // æ–°å¢ž
//                this.save(plan);
//                affected++;
//                log.info("新增数据 formInstanceId={}, materialCode={}", plan.getFormInstanceId(), plan.getProductMaterialSkuId());
//            } else {
//                // åˆ¤æ–­æ˜¯å¦éœ€è¦æ›´æ–°
//                if (exist.getFormModifiedTime() == null || !exist.getFormModifiedTime().equals(plan.getFormModifiedTime())) {
//                    plan.setId(exist.getId());
//                    plan.setCreateTime(exist.getCreateTime());
//                    this.updateById(plan);
//                    affected++;
//                    log.info("更新数据 formInstanceId={}, materialCode={}", plan.getFormInstanceId(), plan.getProductMaterialSkuId());
//                }
//            }
//        }
//        return affected;
//    }
//
//    @Override
//    public List<ProductionPlanSummaryDto> summaryByProductType(ProductionPlanSummaryDto query) {
//        return baseMapper.selectSummaryByProductType(query);
//    }
//
//    @Override
//    @Transactional(rollbackFor = Exception.class)
//    public void importProdData(MultipartFile file) {
//        if (file == null || file.isEmpty()) {
//            throw new ServiceException("导入数据不能为空");
//        }
//        ExcelUtil<ProductionPlanImportDto> excelUtil = new ExcelUtil<>(ProductionPlanImportDto.class);
//        List<ProductionPlanImportDto> list;
//        try {
//            list = excelUtil.importExcel(file.getInputStream());
//        } catch (Exception e) {
//            log.error("生产需求Excel导入失败", e);
//            throw new ServiceException("Excel解析失败");
//        }
//
//        if (list == null || list.isEmpty()) {
//            throw new ServiceException("Excel没有数据");
//        }
//
//        Set<String> applyNos = new HashSet<>();
//        Set<String> materialCodes = new HashSet<>();
//        for (int i = 0; i < list.size(); i++) {
//            ProductionPlanImportDto dto = list.get(i);
//            String applyNo = dto.getApplyNo();
//            String materialCode = dto.getMaterialCode();
//
//            if (StringUtils.isEmpty(applyNo)) {
//                throw new ServiceException("导入失败:第 " + (i + 2) + " è¡Œç”³è¯·å•编号不能为空");
//            }
//            if (!applyNos.add(applyNo)) {
//                throw new ServiceException("导入失败:Excel ä¸­å­˜åœ¨é‡å¤çš„申请单编号: " + applyNo);
//            }
//            if (StringUtils.isEmpty(materialCode)) {
//                throw new ServiceException("导入失败:第 " + (i + 2) + " è¡Œç‰©æ–™ç¼–码不能为空");
//            }
//
//            String strength = dto.getStrength();
//            if (StringUtils.isNotEmpty(strength)) {
//                if (!"A3.5".equals(strength) && !"A5.0".equals(strength)) {
//                    throw new ServiceException("导入失败:第 " + (i + 2) + " è¡Œå¼ºåº¦åªèƒ½æ˜¯ A3.5 æˆ– A5.0");
//                }
//            }
//
//            materialCodes.add(materialCode);
//        }
//
//        //  ç”³è¯·å•编号是否已存在
//        Long existApplyNoCount = baseMapper.selectCount(Wrappers.<ProductionPlan>lambdaQuery()
//                .in(ProductionPlan::getApplyNo, applyNos));
//        if (existApplyNoCount > 0) {
//            List<String> existApplyNos = baseMapper.selectList(Wrappers.<ProductionPlan>lambdaQuery()
//                            .in(ProductionPlan::getApplyNo, applyNos))
//                    .stream().map(ProductionPlan::getApplyNo).collect(Collectors.toList());
//            throw new ServiceException("导入失败,申请单编号已存在: " + String.join(", ", existApplyNos));
//        }
//
//        Map<String, Long> skuMap = productMaterialSkuService.list(Wrappers.<ProductMaterialSku>lambdaQuery()
//                        .in(ProductMaterialSku::getMaterialCode, materialCodes))
//                .stream().collect(Collectors.toMap(ProductMaterialSku::getMaterialCode, ProductMaterialSku::getId, (k1, k2) -> k1));
//
//        List<String> missingCodes = materialCodes.stream()
//                .filter(code -> !skuMap.containsKey(code))
//                .collect(Collectors.toList());
//        if (!missingCodes.isEmpty()) {
//            throw new ServiceException("导入失败,以下物料编码不存在: " + String.join(", ", missingCodes));
//        }
//
//        LocalDateTime now = LocalDateTime.now();
//        List<ProductionPlan> entityList = list.stream().map(dto -> {
//            ProductionPlan entity = new ProductionPlan();
//            BeanUtils.copyProperties(dto, entity);
//            entity.setProductMaterialSkuId(skuMap.get(dto.getMaterialCode()));
//            entity.setAssignedQuantity(BigDecimal.ZERO);
//            entity.setDataSourceType(DataSourceTypeEnum.MANUAL.getCode());
//            entity.setStatus(0);
//            entity.setCreateTime(now);
//            entity.setUpdateTime(now);
//            return entity;
//        }).collect(Collectors.toList());
//
//        this.saveBatch(entityList);
//    }
//
//    @Override
//    public void exportProdData(HttpServletResponse response, List<Long> ids) {
//        List<ProductionPlan> list;
//        if (ids != null && !ids.isEmpty()) {
//            list = baseMapper.selectBatchIds(ids);
//        } else {
//            list = baseMapper.selectList(null);
//        }
//
//        List<ProductionPlanImportDto> exportList = new ArrayList<>();
//        for (ProductionPlan entity : list) {
//            ProductionPlanImportDto dto = new ProductionPlanImportDto();
//            BeanUtils.copyProperties(entity, dto);
//            exportList.add(dto);
//        }
//        ExcelUtil<ProductionPlanImportDto> util = new ExcelUtil<>(ProductionPlanImportDto.class);
//        util.exportExcel(response, exportList, "销售生产需求数据");
//    }
//
//}
package com.ruoyi.production.service.impl;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.production.bean.dto.ProductionPlanDto;
import com.ruoyi.production.bean.vo.ProductionPlanVo;
import com.ruoyi.production.mapper.ProductionPlanMapper;
import com.ruoyi.production.pojo.ProductionPlan;
import com.ruoyi.production.service.ProductionPlanService;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
@Service
@RequiredArgsConstructor
public class ProductionPlanServiceImpl extends ServiceImpl<ProductionPlanMapper, ProductionPlan> implements ProductionPlanService {
    @Override
    public IPage<ProductionPlanVo> listPage(Page<ProductionPlanDto> page, ProductionPlanDto productionPlanDto) {
        return null;
    }
    @Override
    public void loadProdData() {
    }
    @Override
    public void syncProdDataJob() {
    }
    @Override
    public boolean combine(ProductionPlanDto productionPlanDto) {
        return false;
    }
    @Override
    public boolean add(ProductionPlanDto productionPlanDto) {
        return false;
    }
    @Override
    public boolean update(ProductionPlanDto productionPlanDto) {
        return false;
    }
    @Override
    public boolean delete(List<Long> ids) {
        return false;
    }
    @Override
    public void importProdData(MultipartFile file) {
    }
    @Override
    public void exportProdData(HttpServletResponse response, List<Long> ids) {
    }
}
src/main/java/com/ruoyi/production/service/impl/ProductionProductInputServiceImpl.java
@@ -1,20 +1,24 @@
package com.ruoyi.production.service.impl;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.production.bean.dto.ProductionProductInputDto;
import com.ruoyi.production.mapper.ProductionProductInputMapper;
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;
/**
 * <p>
 * ç”Ÿäº§æŠ¥å·¥æŠ•入表 æœåŠ¡å®žçŽ°ç±»
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-04-21 03:55:52
 */
@Service
@AllArgsConstructor
public class ProductionProductInputServiceImpl extends ServiceImpl<ProductionProductInputMapper, ProductionProductInput> implements ProductionProductInputService {
    @Autowired
    private ProductionProductInputMapper productionProductInputMapper;
    @Override
    public IPage<ProductionProductInputDto> listPageProductionProductInputDto(Page page, ProductionProductInputDto productionProductInputDto) {
        return productionProductInputMapper.listPageProductionProductInputDto(page, productionProductInputDto);
    }
}
src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java
@@ -1,20 +1,345 @@
package com.ruoyi.production.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.production.mapper.ProductionProductMainMapper;
import com.ruoyi.production.pojo.ProductionProductMain;
import com.ruoyi.basic.mapper.ProductMapper;
import com.ruoyi.basic.mapper.ProductModelMapper;
import com.ruoyi.basic.pojo.Product;
import com.ruoyi.basic.pojo.ProductModel;
import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum;
import com.ruoyi.common.enums.StockInUnQualifiedRecordTypeEnum;
import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.procurementrecord.utils.StockUtils;
import com.ruoyi.production.bean.dto.ProductStructureDto;
import com.ruoyi.production.bean.dto.ProductionProductMainDto;
import com.ruoyi.production.mapper.*;
import com.ruoyi.production.pojo.*;
import com.ruoyi.production.service.ProductionProductMainService;
import com.ruoyi.project.system.domain.SysUser;
import com.ruoyi.project.system.mapper.SysUserMapper;
import com.ruoyi.quality.mapper.*;
import com.ruoyi.quality.pojo.*;
import com.ruoyi.technology.mapper.TechnologyOperationMapper;
import com.ruoyi.technology.mapper.TechnologyRoutingOperationMapper;
import com.ruoyi.technology.pojo.TechnologyOperation;
import com.ruoyi.technology.pojo.TechnologyRoutingOperation;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
/**
 * <p>
 * ç”Ÿäº§æŠ¥å·¥è¡¨ æœåŠ¡å®žçŽ°ç±»
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-04-21 03:55:52
 */
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Service
@AllArgsConstructor
@Transactional(rollbackFor = Exception.class)
public class ProductionProductMainServiceImpl extends ServiceImpl<ProductionProductMainMapper, ProductionProductMain> implements ProductionProductMainService {
    private final ProductionProductMainMapper productionProductMainMapper;
    private final SysUserMapper userMapper;
    private final ProductionProductOutputMapper productionProductOutputMapper;
    private final ProductModelMapper productModelMapper;
    private final QualityInspectMapper qualityInspectMapper;
    private final QualityUnqualifiedMapper qualityUnqualifiedMapper;
    private final ProductMapper productMapper;
    private final QualityTestStandardParamMapper qualityTestStandardParamMapper;
    private final QualityTestStandardMapper qualityTestStandardMapper;
    private final QualityInspectParamMapper qualityInspectParamMapper;
    private final ProductionProductInputMapper productionProductInputMapper;
    private final ProductionAccountMapper productionAccountMapper;
    private final ProductionOperationTaskMapper productionOperationTaskMapper;
    private final ProductionOrderMapper productionOrderMapper;
    private final ProductionOrderRoutingOperationMapper productionOrderRoutingOperationMapper;
    private final TechnologyRoutingOperationMapper technologyRoutingOperationMapper;
    private final TechnologyOperationMapper technologyOperationMapper;
    private final StockUtils stockUtils;
    @Override
    public IPage<ProductionProductMainDto> listPageProductionProductMainDto(Page page, ProductionProductMainDto productionProductMainDto) {
        return productionProductMainMapper.listPageProductionProductMainDto(page, productionProductMainDto);
    }
    @Override
    public IPage<ProductionProductMainDto> pageProductionProductMain(Page page, ProductionProductMainDto productionProductMainDto) {
        return listPageProductionProductMainDto(page, productionProductMainDto);
    }
    @Override
    public ProductionProductMainDto getProductionProductMainInfo(Long id) {
        return productionProductMainMapper.listPageProductionProductMainDto(new Page<>(1, 1), new ProductionProductMainDto() {{
            setId(id);
        }}).getRecords().stream().findFirst().orElse(null);
    }
    @Override
    public Boolean addProductMain(ProductionProductMainDto dto) {
        if (dto.getProductionOperationTaskId() == null) {
            throw new ServiceException("请传入生产工单ID");
        }
        return addProductMainByProductionTask(dto);
    }
    @Override
    public Boolean saveProductionProductMain(ProductionProductMainDto productionProductMainDto) {
        return addProductMain(productionProductMainDto);
    }
    @Override
    public Boolean removeProductMain(Long id) {
        ProductionProductMain currentMain = productionProductMainMapper.selectById(id);
        if (currentMain == null) {
            return true;
        }
        return removeProductMainByProductionTask(currentMain);
    }
    private Boolean addProductMainByProductionTask(ProductionProductMainDto dto) {
        SysUser user = userMapper.selectUserById(dto.getUserId());
        ProductionOperationTask productionOperationTask = productionOperationTaskMapper.selectById(dto.getProductionOperationTaskId());
        if (productionOperationTask == null) {
            throw new ServiceException("生产工单不存在");
        }
        ProductionOrderRoutingOperation routingOperation = productionOrderRoutingOperationMapper.selectById(productionOperationTask.getTechnologyRoutingOperationId());
        if (routingOperation == null) {
            throw new ServiceException("订单工艺路线工序不存在");
        }
        ProductionOrder productionOrder = productionOrderMapper.selectById(productionOperationTask.getProductionOrderId());
        if (productionOrder == null) {
            throw new ServiceException("生产订单不存在");
        }
        TechnologyRoutingOperation technologyRoutingOperation = technologyRoutingOperationMapper.selectById(routingOperation.getTechnologyRoutingOperationId());
        TechnologyOperation technologyOperation = technologyRoutingOperation == null ? null
                : technologyOperationMapper.selectById(technologyRoutingOperation.getTechnologyOperationId());
        ProductModel productModel = productModelMapper.selectById(
                routingOperation.getProductModelId() != null ? routingOperation.getProductModelId() : productionOrder.getProductModelId());
        if (productModel == null) {
            throw new ServiceException("产品规格不存在");
        }
        ProductionProductMain productionProductMain = new ProductionProductMain();
        productionProductMain.setProductNo(generateProductNo());
        productionProductMain.setUserId(dto.getUserId());
        productionProductMain.setUserName(dto.getUserName());
        productionProductMain.setProductionOperationTaskId(productionOperationTask.getId());
        productionProductMain.setWorkOrderId(productionOperationTask.getId());
        productionProductMain.setStatus(0);
        productionProductMainMapper.insert(productionProductMain);
        List<ProductStructureDto> productStructureDtos = new ArrayList<>();
        ProductStructureDto productStructureDto = new ProductStructureDto();
        productStructureDto.setProductModelId(productModel.getId());
        productStructureDto.setUnitQuantity(BigDecimal.ONE);
        productStructureDtos.add(productStructureDto);
        for (ProductStructureDto item : productStructureDtos) {
            ProductionProductInput productionProductInput = new ProductionProductInput();
            productionProductInput.setProductionProductMainId(productionProductMain.getId());
            productionProductInput.setProductMainId(productionProductMain.getId());
            productionProductInput.setProductModelId(item.getProductModelId());
            productionProductInput.setInputQuantity(item.getUnitQuantity().multiply(defaultDecimal(dto.getQuantity())));
            productionProductInput.setQuantity(productionProductInput.getInputQuantity());
            productionProductInputMapper.insert(productionProductInput);
            stockUtils.substractStock(item.getProductModelId(), productionProductInput.getInputQuantity(),
                    StockOutQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_OUT.getCode(), productionProductMain.getId());
        }
        ProductionProductOutput productionProductOutput = new ProductionProductOutput();
        productionProductOutput.setProductionProductMainId(productionProductMain.getId());
        productionProductOutput.setProductMainId(productionProductMain.getId());
        productionProductOutput.setProductModelId(productModel.getId());
        productionProductOutput.setQuantity(defaultDecimal(dto.getQuantity()));
        productionProductOutput.setScrapQty(defaultDecimal(dto.getScrapQty()));
        productionProductOutputMapper.insert(productionProductOutput);
        BigDecimal productQty = productionProductOutput.getQuantity().subtract(productionProductOutput.getScrapQty());
        List<ProductionOrderRoutingOperation> routingOperationList = productionOrderRoutingOperationMapper.selectList(
                Wrappers.<ProductionOrderRoutingOperation>lambdaQuery()
                        .eq(ProductionOrderRoutingOperation::getTechnologyRoutingId, routingOperation.getTechnologyRoutingId())
                        .eq(ProductionOrderRoutingOperation::getProductionOrderId, routingOperation.getProductionOrderId()));
        boolean isLastOperation = routingOperation.getDragSort() != null && routingOperation.getDragSort().equals(routingOperationList.size());
        if (productQty.compareTo(BigDecimal.ZERO) > 0) {
            if (Boolean.TRUE.equals(routingOperation.getIsQuality())) {
                int inspectType = isLastOperation ? 2 : 1;
                String process = isLastOperation ? null : technologyOperation == null ? null : technologyOperation.getName();
                Product product = productMapper.selectById(productModel.getProductId());
                QualityInspect qualityInspect = new QualityInspect();
                qualityInspect.setProductId(product.getId());
                qualityInspect.setProductName(product.getProductName());
                qualityInspect.setModel(productModel.getModel());
                qualityInspect.setUnit(productModel.getUnit());
                qualityInspect.setQuantity(productQty);
                qualityInspect.setProcess(process);
                qualityInspect.setInspectState(0);
                qualityInspect.setInspectType(inspectType);
                qualityInspect.setProductMainId(productionProductMain.getId());
                qualityInspect.setProductModelId(productModel.getId());
                qualityInspectMapper.insert(qualityInspect);
                List<QualityTestStandard> qualityTestStandard = qualityTestStandardMapper.getQualityTestStandardByProductId(product.getId(), inspectType, process);
                if (qualityTestStandard.size() > 0) {
                    qualityInspect.setTestStandardId(qualityTestStandard.get(0).getId());
                    qualityInspectMapper.updateById(qualityInspect);
                    qualityTestStandardParamMapper.selectList(Wrappers.<QualityTestStandardParam>lambdaQuery()
                                    .eq(QualityTestStandardParam::getTestStandardId, qualityTestStandard.get(0).getId()))
                            .forEach(qualityTestStandardParam -> {
                                QualityInspectParam param = new QualityInspectParam();
                                BeanUtils.copyProperties(qualityTestStandardParam, param);
                                param.setId(null);
                                param.setInspectId(qualityInspect.getId());
                                qualityInspectParamMapper.insert(param);
                            });
                }
            } else {
                stockUtils.addStock(productModel.getId(), productQty,
                        StockInQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_IN.getCode(), productionProductMain.getId());
            }
            productionOperationTask.setCompleteQuantity(defaultDecimal(productionOperationTask.getCompleteQuantity()).add(productQty));
            if (ObjectUtils.isNull(productionOperationTask.getActualStartTime())) {
                productionOperationTask.setActualStartTime(LocalDate.now());
            }
            if (productionOperationTask.getPlanQuantity() != null
                    && productionOperationTask.getCompleteQuantity().compareTo(productionOperationTask.getPlanQuantity()) >= 0) {
                productionOperationTask.setActualEndTime(LocalDate.now());
            }
            productionOperationTaskMapper.updateById(productionOperationTask);
            if (ObjectUtils.isNull(productionOrder.getStartTime())) {
                productionOrder.setStartTime(LocalDateTime.now());
            }
            if (isLastOperation) {
                productionOrder.setCompleteQuantity(defaultDecimal(productionOrder.getCompleteQuantity()).add(productQty));
                if (productionOrder.getQuantity() != null
                        && productionOrder.getCompleteQuantity().compareTo(productionOrder.getQuantity()) >= 0) {
                    productionOrder.setEndTime(LocalDateTime.now());
                }
            }
            productionOrderMapper.updateById(productionOrder);
            BigDecimal workHours = BigDecimal.ZERO;
            if (technologyOperation != null && technologyOperation.getSalaryQuota() != null) {
                workHours = Integer.valueOf(1).equals(technologyOperation.getType())
                        ? technologyOperation.getSalaryQuota().multiply(productQty)
                        : technologyOperation.getSalaryQuota();
            }
            ProductionAccount productionAccount = new ProductionAccount();
            productionAccount.setProductionProductMainId(productionProductMain.getId());
            productionAccount.setSalesLedgerId(productionOrder.getSalesLedgerId());
            productionAccount.setSalesLedgerProductId(productionOrder.getSaleLedgerProductId() == null ? null : productionOrder.getSaleLedgerProductId().longValue());
            productionAccount.setSchedulingUserId(user == null ? null : user.getUserId());
            productionAccount.setSchedulingUserName(user == null ? dto.getUserName() : user.getNickName());
            productionAccount.setFinishedNum(productQty);
            productionAccount.setWorkHours(workHours);
            productionAccount.setTechnologyOperationName(technologyOperation == null ? null : technologyOperation.getName());
            productionAccount.setSchedulingDate(LocalDateTime.now());
            productionAccountMapper.insert(productionAccount);
        }
        if (defaultDecimal(dto.getScrapQty()).compareTo(BigDecimal.ZERO) > 0) {
            stockUtils.addUnStock(productModel.getId(), dto.getScrapQty(),
                    StockInUnQualifiedRecordTypeEnum.PRODUCTION_SCRAP.getCode(), productionProductMain.getId());
        }
        return true;
    }
    private Boolean removeProductMainByProductionTask(ProductionProductMain productionProductMain) {
        List<QualityInspect> qualityInspects = qualityInspectMapper.selectList(
                Wrappers.<QualityInspect>lambdaQuery().eq(QualityInspect::getProductMainId, productionProductMain.getId()));
        if (qualityInspects.size() > 0) {
            List<QualityUnqualified> qualityUnqualifieds = qualityUnqualifiedMapper.selectList(
                    Wrappers.<QualityUnqualified>lambdaQuery()
                            .in(QualityUnqualified::getInspectId, qualityInspects.stream().map(QualityInspect::getId).collect(Collectors.toList())));
            if (qualityUnqualifieds.size() > 0 && qualityUnqualifieds.get(0).getInspectState() == 1) {
                throw new ServiceException("该条报工已经不合格处理了,不允许删除");
            }
        }
        ProductionProductOutput productionProductOutput = productionProductOutputMapper.selectList(
                Wrappers.<ProductionProductOutput>lambdaQuery()
                        .eq(ProductionProductOutput::getProductionProductMainId, productionProductMain.getId()))
                .stream().findFirst().orElse(null);
        productionAccountMapper.delete(new LambdaQueryWrapper<ProductionAccount>()
                .eq(ProductionAccount::getProductionProductMainId, productionProductMain.getId()));
        ProductionOperationTask productionOperationTask = productionOperationTaskMapper.selectById(productionProductMain.getProductionOperationTaskId());
        if (productionOperationTask != null && productionProductOutput != null) {
            BigDecimal validQuantity = defaultDecimal(productionProductOutput.getQuantity()).subtract(defaultDecimal(productionProductOutput.getScrapQty()));
            productionOperationTask.setCompleteQuantity(defaultDecimal(productionOperationTask.getCompleteQuantity()).subtract(validQuantity));
            productionOperationTask.setActualEndTime(null);
            productionOperationTaskMapper.updateById(productionOperationTask);
            ProductionOrder productionOrder = productionOrderMapper.selectById(productionOperationTask.getProductionOrderId());
            ProductionOrderRoutingOperation routingOperation = productionOrderRoutingOperationMapper.selectById(productionOperationTask.getTechnologyRoutingOperationId());
            if (productionOrder != null && routingOperation != null) {
                List<ProductionOrderRoutingOperation> routingOperationList = productionOrderRoutingOperationMapper.selectList(
                        Wrappers.<ProductionOrderRoutingOperation>lambdaQuery()
                                .eq(ProductionOrderRoutingOperation::getTechnologyRoutingId, routingOperation.getTechnologyRoutingId())
                                .eq(ProductionOrderRoutingOperation::getProductionOrderId, routingOperation.getProductionOrderId()));
                boolean isLastOperation = routingOperation.getDragSort() != null && routingOperation.getDragSort().equals(routingOperationList.size());
                if (isLastOperation) {
                    BigDecimal newCompleteQty = defaultDecimal(productionOrder.getCompleteQuantity()).subtract(validQuantity);
                    productionOrder.setCompleteQuantity(newCompleteQty.compareTo(BigDecimal.ZERO) < 0 ? BigDecimal.ZERO : newCompleteQty);
                    productionOrder.setEndTime(null);
                    productionOrderMapper.updateById(productionOrder);
                }
            }
        }
        qualityInspectMapper.selectList(new LambdaQueryWrapper<QualityInspect>()
                .eq(QualityInspect::getProductMainId, productionProductMain.getId())).forEach(q -> {
            qualityInspectParamMapper.delete(new LambdaQueryWrapper<QualityInspectParam>()
                    .eq(QualityInspectParam::getInspectId, q.getId()));
            qualityInspectMapper.deleteById(q.getId());
            stockUtils.deleteStockInRecord(q.getId(), StockInQualifiedRecordTypeEnum.QUALITYINSPECT_STOCK_IN.getCode());
        });
        productionProductOutputMapper.delete(new LambdaQueryWrapper<ProductionProductOutput>()
                .eq(ProductionProductOutput::getProductionProductMainId, productionProductMain.getId()));
        productionProductInputMapper.delete(new LambdaQueryWrapper<ProductionProductInput>()
                .eq(ProductionProductInput::getProductionProductMainId, productionProductMain.getId()));
        stockUtils.deleteStockInRecord(productionProductMain.getId(), StockInUnQualifiedRecordTypeEnum.PRODUCTION_SCRAP.getCode());
        stockUtils.deleteStockInRecord(productionProductMain.getId(), StockInQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_IN.getCode());
        stockUtils.deleteStockOutRecord(productionProductMain.getId(), StockOutQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_OUT.getCode());
        productionProductMainMapper.deleteById(productionProductMain.getId());
        return true;
    }
    private String generateProductNo() {
        String datePrefix = "BG" + LocalDate.now().format(DateTimeFormatter.ofPattern("yyMMdd"));
        QueryWrapper<ProductionProductMain> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("MAX(product_no) as maxNo").likeRight("product_no", datePrefix);
        List<Map<String, Object>> resultList = productionProductMainMapper.selectMaps(queryWrapper);
        int sequenceNumber = 1;
        if (resultList != null && !resultList.isEmpty()) {
            Map<String, Object> result = resultList.get(0);
            if (result != null && result.get("maxNo") != null) {
                String lastNo = result.get("maxNo").toString();
                if (lastNo.startsWith(datePrefix)) {
                    try {
                        sequenceNumber = Integer.parseInt(lastNo.substring(datePrefix.length())) + 1;
                    } catch (NumberFormatException e) {
                        sequenceNumber = 1;
                    }
                }
            }
        }
        return String.format("%s%03d", datePrefix, sequenceNumber);
    }
    private BigDecimal defaultDecimal(BigDecimal value) {
        return value == null ? BigDecimal.ZERO : value;
    }
    @Override
    public ArrayList<Long> listMain(List<Long> idList) {
        return productionProductMainMapper.listMain(idList);
    }
}
src/main/java/com/ruoyi/production/service/impl/ProductionProductOutputServiceImpl.java
@@ -1,20 +1,24 @@
package com.ruoyi.production.service.impl;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.production.bean.dto.ProductionProductOutputDto;
import com.ruoyi.production.mapper.ProductionProductOutputMapper;
import com.ruoyi.production.pojo.ProductionProductOutput;
import com.ruoyi.production.service.ProductionProductOutputService;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
 * <p>
 * ç”Ÿäº§æŠ¥å·¥äº§å‡ºè¡¨ æœåŠ¡å®žçŽ°ç±»
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-04-21 03:55:52
 */
@Service
@AllArgsConstructor
public class ProductionProductOutputServiceImpl extends ServiceImpl<ProductionProductOutputMapper, ProductionProductOutput> implements ProductionProductOutputService {
    @Autowired
    private ProductionProductOutputMapper productionProductOutputMapper;
    @Override
    public IPage<ProductionProductOutputDto> listPageProductionProductOutputDto(Page page, ProductionProductOutputDto productionProductOutputDto) {
        return productionProductOutputMapper.listPageProductionProductOutputDto(page, productionProductOutputDto);
    }
}
src/main/java/com/ruoyi/production/service/impl/SalesLedgerProductionAccountingServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,24 @@
package com.ruoyi.production.service.impl;
import com.ruoyi.production.bean.dto.UserAccountDto;
import com.ruoyi.production.bean.dto.UserProductionAccountingDto;
import com.ruoyi.production.mapper.ProductionAccountMapper;
import com.ruoyi.production.service.SalesLedgerProductionAccountingService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
@Service
@RequiredArgsConstructor
public class SalesLedgerProductionAccountingServiceImpl implements SalesLedgerProductionAccountingService {
    private final ProductionAccountMapper productionAccountMapper;
    @Override
    public UserAccountDto getByUserId(UserProductionAccountingDto dto) {
        if (dto == null || dto.getUserId() == null || dto.getDate() == null || dto.getDate().trim().isEmpty()) {
            return new UserAccountDto();
        }
        UserAccountDto result = productionAccountMapper.selectUserAccount(dto.getUserId(), dto.getDate());
        return result == null ? new UserAccountDto() : result;
    }
}
src/main/java/com/ruoyi/quality/service/impl/QualityReportServiceImpl.java
@@ -1,9 +1,6 @@
package com.ruoyi.quality.service.impl;
import com.ruoyi.basic.service.IProductModelService;
import com.ruoyi.basic.service.IProductService;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.production.service.ProductOrderService;
import com.ruoyi.quality.dto.*;
import com.ruoyi.quality.mapper.QualityInspectMapper;
import com.ruoyi.quality.service.QualityReportService;
src/main/java/com/ruoyi/quality/service/impl/QualityUnqualifiedServiceImpl.java
@@ -1,24 +1,26 @@
package com.ruoyi.quality.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
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.common.enums.StockInUnQualifiedRecordTypeEnum;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.procurementrecord.utils.StockUtils;
import com.ruoyi.production.mapper.ProductProcessRouteItemMapper;
import com.ruoyi.production.mapper.ProductProcessRouteMapper;
import com.ruoyi.production.mapper.ProductWorkOrderMapper;
import com.ruoyi.production.mapper.ProductionOperationTaskMapper;
import com.ruoyi.production.mapper.ProductionOrderMapper;
import com.ruoyi.production.mapper.ProductionOrderRoutingMapper;
import com.ruoyi.production.mapper.ProductionOrderRoutingOperationMapper;
import com.ruoyi.production.mapper.ProductionProductMainMapper;
import com.ruoyi.production.pojo.*;
import com.ruoyi.production.service.ProductOrderService;
import com.ruoyi.production.pojo.ProductionOperationTask;
import com.ruoyi.production.pojo.ProductionOrder;
import com.ruoyi.production.pojo.ProductionOrderRouting;
import com.ruoyi.production.pojo.ProductionOrderRoutingOperation;
import com.ruoyi.production.pojo.ProductionProductMain;
import com.ruoyi.quality.mapper.QualityUnqualifiedMapper;
import com.ruoyi.quality.pojo.QualityInspect;
import com.ruoyi.quality.pojo.QualityUnqualified;
@@ -32,21 +34,23 @@
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@AllArgsConstructor
@Service
public class QualityUnqualifiedServiceImpl extends ServiceImpl<QualityUnqualifiedMapper, QualityUnqualified> implements IQualityUnqualifiedService {
    private final StockUtils stockUtils;
    private QualityUnqualifiedMapper qualityUnqualifiedMapper;
    private IQualityInspectService qualityInspectService;
    private ProductOrderService productOrderService;
    private ProductionProductMainMapper productionProductMainMapper;
    private ProductProcessRouteMapper productProcessRouteMapper;
    private ProductProcessRouteItemMapper productProcessRouteItemMapper;
    private ProductWorkOrderMapper productWorkOrderMapper;
    private StockUninventoryService stockUninventoryService;
    private final QualityUnqualifiedMapper qualityUnqualifiedMapper;
    private final IQualityInspectService qualityInspectService;
    private final ProductionProductMainMapper productionProductMainMapper;
    private final ProductionOrderMapper productionOrderMapper;
    private final ProductionOrderRoutingMapper productionOrderRoutingMapper;
    private final ProductionOrderRoutingOperationMapper productionOrderRoutingOperationMapper;
    private final ProductionOperationTaskMapper productionOperationTaskMapper;
    private final StockUninventoryService stockUninventoryService;
    @Override
    public IPage<QualityUnqualified> qualityUnqualifiedListPage(Page page, QualityUnqualified qualityUnqualified) {
@@ -56,7 +60,7 @@
    @Override
    public void qualityUnqualifiedExport(HttpServletResponse response, QualityUnqualified qualityUnqualified) {
        List<QualityUnqualified> qualityUnqualifieds = qualityUnqualifiedMapper.qualityUnqualifiedExport(qualityUnqualified);
        ExcelUtil<QualityUnqualified> util = new ExcelUtil<QualityUnqualified>(QualityUnqualified.class);
        ExcelUtil<QualityUnqualified> util = new ExcelUtil<>(QualityUnqualified.class);
        util.exportExcel(response, qualityUnqualifieds, "不合格管理导出");
    }
@@ -68,92 +72,41 @@
            switch (qualityUnqualified.getDealResult()) {
                case "返修":
                case "返工":
                    //判断质检表是否有相关的报工id,如果有报工id,那么返工需要重新创建生产订单重新生产
                    if (ObjectUtils.isNotNull(qualityInspect.getProductMainId())) {
                        //返工需要重新创建生产订单重新生产
                        ProductOrder productOrder = productionProductMainMapper.getOrderByMainId(qualityInspect.getProductMainId());
                        ProductOrder order = new ProductOrder();
                        BeanUtils.copyProperties(productOrder, order);
                        order.setId(null);
                        order.setQuantity(unqualified.getQuantity());
                        order.setCompleteQuantity(BigDecimal.ZERO);
                        order.setStartTime(null);
                        order.setEndTime(null);
                        productOrderService.save(order);
                        //新增生产订单下的工艺路线主表
                        ProductProcessRoute productProcessRoute = productProcessRouteMapper.selectList(Wrappers.<ProductProcessRoute>lambdaQuery().eq(ProductProcessRoute::getProductOrderId, productOrder.getId()).orderByDesc(ProductProcessRoute::getId)).get(0);
                        ProductProcessRoute newProcessRoute = new ProductProcessRoute();
                        BeanUtils.copyProperties(productProcessRoute, newProcessRoute);
                        newProcessRoute.setId(null);
                        newProcessRoute.setProductOrderId(order.getId());
                        productProcessRouteMapper.insert(newProcessRoute);
                        //新增生产订单下的工艺路线子表
                        List<ProductProcessRouteItem> processRouteItems = productProcessRouteItemMapper.selectList(new QueryWrapper<ProductProcessRouteItem>().lambda().eq(ProductProcessRouteItem::getProductRouteId, productProcessRoute.getId()));
                        // ç”Ÿæˆå½“前日期的前缀:年月日
                        String datePrefix = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
                        for (ProductProcessRouteItem processRouteItem : processRouteItems) {
                            ProductProcessRouteItem productProcessRouteItem = new ProductProcessRouteItem();
                            BeanUtils.copyProperties(processRouteItem, productProcessRouteItem);
                            productProcessRouteItem.setId(null);
                            productProcessRouteItem.setProductRouteId(newProcessRoute.getId());
                            int insert = productProcessRouteItemMapper.insert(productProcessRouteItem);
                            if (insert > 0) {
                                // æŸ¥è¯¢ä»Šæ—¥å·²å­˜åœ¨çš„æœ€å¤§å·¥å•号
                                ProductWorkOrder lastWorkOrder = productWorkOrderMapper.selectMax(datePrefix);
                                int sequenceNumber = 1; // é»˜è®¤åºå·
                                if (lastWorkOrder != null && lastWorkOrder.getWorkOrderNo() != null) {
                                    String lastNo = lastWorkOrder.getWorkOrderNo().toString();
                                    if (lastNo.startsWith(datePrefix)) {
                                        String seqStr = lastNo.substring(datePrefix.length());
                                        try {
                                            sequenceNumber = Integer.parseInt(seqStr) + 1;
                                        } catch (NumberFormatException e) {
                                            sequenceNumber = 1;
                                        }
                                    }
                                }
                                // ç”Ÿæˆå®Œæ•´çš„工单号
                                String workOrderNoStr = "FG" + String.format("%s%03d", datePrefix, sequenceNumber);
                                ProductWorkOrder productWorkOrder = new ProductWorkOrder();
                                productWorkOrder.setProductProcessRouteItemId(productProcessRouteItem.getId());
                                productWorkOrder.setProductOrderId(order.getId());
                                productWorkOrder.setPlanQuantity(order.getQuantity());
                                productWorkOrder.setWorkOrderNo(workOrderNoStr);
                                productWorkOrder.setStatus(1);
                                productWorkOrderMapper.insert(productWorkOrder);
                            }
                        ProductionProductMain sourceMain = productionProductMainMapper.selectById(qualityInspect.getProductMainId());
                        if (sourceMain == null || sourceMain.getProductionOperationTaskId() == null) {
                            throw new ServiceException("历史报工未绑定生产工单,无法按新模型返修/返工");
                        }
                        createReworkProductionByNewModel(sourceMain, unqualified.getQuantity());
                    }
                    break;
                case "报废":
                    //调用不合格库存接口 å…¥ä¸åˆæ ¼åº“
                    stockUtils.addUnStock(qualityInspect.getProductModelId(), unqualified.getQuantity(), StockInUnQualifiedRecordTypeEnum.DEFECTIVE_SCRAP.getCode(), unqualified.getId());
                    stockUtils.addUnStock(qualityInspect.getProductModelId(), unqualified.getQuantity(),
                            StockInUnQualifiedRecordTypeEnum.DEFECTIVE_SCRAP.getCode(), unqualified.getId());
                    break;
                case "让步放行":
                    //调用提交合格的接口
                    stockUtils.addStock(qualityInspect.getProductModelId(), unqualified.getQuantity(), StockInQualifiedRecordTypeEnum.DEFECTIVE_PASS.getCode(), unqualified.getId());
                    stockUtils.addStock(qualityInspect.getProductModelId(), unqualified.getQuantity(),
                            StockInQualifiedRecordTypeEnum.DEFECTIVE_PASS.getCode(), unqualified.getId());
                    break;
                default:
                    break;
            }
        } else {
            //查询对应的规格型号id
            Long modelId = qualityUnqualifiedMapper.getModelId(qualityUnqualified.getProductName(), qualityUnqualified.getModel());
            switch (qualityUnqualified.getDealResult()) {
                case "报废":
                    //调用不合格库存接口 å…¥ä¸åˆæ ¼åº“
                    stockUtils.addUnStock(modelId, unqualified.getQuantity(), StockInUnQualifiedRecordTypeEnum.DEFECTIVE_SCRAP.getCode(), unqualified.getId());
                    stockUtils.addUnStock(modelId, unqualified.getQuantity(),
                            StockInUnQualifiedRecordTypeEnum.DEFECTIVE_SCRAP.getCode(), unqualified.getId());
                    break;
                case "让步放行":
                    //调用提交合格的接口
                    stockUtils.addStock(modelId, unqualified.getQuantity(), StockInQualifiedRecordTypeEnum.DEFECTIVE_PASS.getCode(), unqualified.getId());
                    stockUtils.addStock(modelId, unqualified.getQuantity(),
                            StockInQualifiedRecordTypeEnum.DEFECTIVE_PASS.getCode(), unqualified.getId());
                    break;
                default:
                    break;
            }
        }
        qualityUnqualified.setInspectState(1);//已处理
        qualityUnqualified.setInspectState(1);
        return qualityUnqualifiedMapper.updateById(qualityUnqualified);
    }
@@ -161,4 +114,110 @@
    public QualityUnqualified getUnqualified(Integer id) {
        return qualityUnqualifiedMapper.getUnqualified(id);
    }
    private void createReworkProductionByNewModel(ProductionProductMain sourceMain, BigDecimal quantity) {
        ProductionOperationTask sourceTask = productionOperationTaskMapper.selectById(sourceMain.getProductionOperationTaskId());
        if (sourceTask == null) {
            throw new ServiceException("关联的生产工单不存在");
        }
        ProductionOrder sourceOrder = productionOrderMapper.selectById(sourceTask.getProductionOrderId());
        if (sourceOrder == null) {
            throw new ServiceException("关联的生产订单不存在");
        }
        ProductionOrder newOrder = new ProductionOrder();
        BeanUtils.copyProperties(sourceOrder, newOrder);
        newOrder.setId(null);
        newOrder.setNpsNo(generateNextProductionOrderNo("FG"));
        newOrder.setQuantity(defaultDecimal(quantity));
        newOrder.setCompleteQuantity(BigDecimal.ZERO);
        newOrder.setStartTime(null);
        newOrder.setEndTime(null);
        newOrder.setCreateTime(null);
        newOrder.setUpdateTime(null);
        productionOrderMapper.insert(newOrder);
        Map<Long, Long> routingIdMap = new HashMap<>();
        List<ProductionOrderRouting> sourceRoutings = productionOrderRoutingMapper.selectList(
                Wrappers.<ProductionOrderRouting>lambdaQuery()
                        .eq(ProductionOrderRouting::getProductionOrderId, sourceOrder.getId())
                        .orderByAsc(ProductionOrderRouting::getId));
        for (ProductionOrderRouting sourceRouting : sourceRoutings) {
            ProductionOrderRouting newRouting = new ProductionOrderRouting();
            BeanUtils.copyProperties(sourceRouting, newRouting);
            newRouting.setId(null);
            newRouting.setProductionOrderId(newOrder.getId());
            newRouting.setCreateTime(null);
            newRouting.setUpdateTime(null);
            productionOrderRoutingMapper.insert(newRouting);
            routingIdMap.put(sourceRouting.getId(), newRouting.getId());
        }
        List<ProductionOrderRoutingOperation> sourceOperations = productionOrderRoutingOperationMapper.selectList(
                Wrappers.<ProductionOrderRoutingOperation>lambdaQuery()
                        .eq(ProductionOrderRoutingOperation::getProductionOrderId, sourceOrder.getId())
                        .orderByAsc(ProductionOrderRoutingOperation::getDragSort)
                        .orderByAsc(ProductionOrderRoutingOperation::getId));
        for (ProductionOrderRoutingOperation sourceOperation : sourceOperations) {
            ProductionOrderRoutingOperation newOperation = new ProductionOrderRoutingOperation();
            BeanUtils.copyProperties(sourceOperation, newOperation);
            newOperation.setId(null);
            newOperation.setProductionOrderId(newOrder.getId());
            newOperation.setTechnologyRoutingId(routingIdMap.get(sourceOperation.getTechnologyRoutingId()));
            newOperation.setCreateTime(null);
            newOperation.setUpdateTime(null);
            productionOrderRoutingOperationMapper.insert(newOperation);
            ProductionOperationTask newTask = new ProductionOperationTask();
            newTask.setTechnologyRoutingOperationId(newOperation.getId());
            newTask.setProductionOrderId(newOrder.getId());
            newTask.setPlanQuantity(newOrder.getQuantity());
            newTask.setCompleteQuantity(BigDecimal.ZERO);
            newTask.setWorkOrderNo(generateNextTaskNo("FG"));
            newTask.setStatus(1);
            productionOperationTaskMapper.insert(newTask);
        }
    }
    private String generateNextProductionOrderNo(String prefix) {
        String datePrefix = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        String orderPrefix = prefix + datePrefix;
        ProductionOrder latestOrder = productionOrderMapper.selectOne(
                Wrappers.<ProductionOrder>lambdaQuery()
                        .likeRight(ProductionOrder::getNpsNo, orderPrefix)
                        .orderByDesc(ProductionOrder::getNpsNo)
                        .last("limit 1"));
        int sequence = 1;
        if (latestOrder != null && latestOrder.getNpsNo() != null && latestOrder.getNpsNo().startsWith(orderPrefix)) {
            try {
                sequence = Integer.parseInt(latestOrder.getNpsNo().substring(orderPrefix.length())) + 1;
            } catch (NumberFormatException ignored) {
                sequence = 1;
            }
        }
        return orderPrefix + String.format("%04d", sequence);
    }
    private String generateNextTaskNo(String prefix) {
        String datePrefix = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        String taskPrefix = prefix + datePrefix;
        ProductionOperationTask latestTask = productionOperationTaskMapper.selectOne(
                Wrappers.<ProductionOperationTask>lambdaQuery()
                        .likeRight(ProductionOperationTask::getWorkOrderNo, taskPrefix)
                        .orderByDesc(ProductionOperationTask::getWorkOrderNo)
                        .last("limit 1"));
        int sequence = 1;
        if (latestTask != null && latestTask.getWorkOrderNo() != null && latestTask.getWorkOrderNo().startsWith(taskPrefix)) {
            try {
                sequence = Integer.parseInt(latestTask.getWorkOrderNo().substring(taskPrefix.length())) + 1;
            } catch (NumberFormatException ignored) {
                sequence = 1;
            }
        }
        return taskPrefix + String.format("%03d", sequence);
    }
    private BigDecimal defaultDecimal(BigDecimal value) {
        return value == null ? BigDecimal.ZERO : value;
    }
}
src/main/java/com/ruoyi/safe/controller/SafeCertificationController.java
@@ -1,19 +1,14 @@
package com.ruoyi.safe.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.production.dto.ProcessRouteDto;
import com.ruoyi.production.pojo.ProcessRoute;
import com.ruoyi.safe.pojo.SafeCertification;
import com.ruoyi.safe.service.SafeCertificationService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import java.util.Arrays;
import java.util.List;
/**
src/main/java/com/ruoyi/safe/controller/SafeCertificationFileController.java
@@ -2,18 +2,15 @@
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.production.pojo.ProductWorkOrderFile;
import com.ruoyi.production.service.ProductWorkOrderFileService;
import com.ruoyi.safe.pojo.SafeCertificationFile;
import com.ruoyi.safe.service.SafeCertificationFileService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import jakarta.annotation.Resource;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import jakarta.annotation.Resource;
import java.util.List;
/**
src/main/java/com/ruoyi/safe/service/impl/SafeTrainingServiceImpl.java
@@ -8,9 +8,6 @@
import com.deepoove.poi.XWPFTemplate;
import com.deepoove.poi.config.Configure;
import com.ruoyi.common.utils.HackLoopTableRenderPolicy;
import com.ruoyi.production.pojo.ProductOrder;
import com.ruoyi.production.pojo.ProductWorkOrder;
import com.ruoyi.project.system.domain.SysNotice;
import com.ruoyi.safe.dto.SafeTrainingDetailsDto;
import com.ruoyi.safe.dto.SafeTrainingDto;
import com.ruoyi.safe.mapper.SafeTrainingDetailsMapper;
@@ -22,20 +19,15 @@
import com.ruoyi.safe.service.SafeTrainingService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import jakarta.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URLEncoder;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java
@@ -10,10 +10,9 @@
import com.ruoyi.common.enums.StockInUnQualifiedRecordTypeEnum;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.procurementrecord.utils.StockUtils;
import com.ruoyi.production.dto.ProductStructureDto;
import com.ruoyi.production.mapper.*;
import com.ruoyi.production.pojo.*;
import com.ruoyi.production.service.impl.ProductOrderServiceImpl;
import com.ruoyi.production.service.ProductionOrderService;
import com.ruoyi.purchase.mapper.PurchaseLedgerMapper;
import com.ruoyi.purchase.pojo.PurchaseLedger;
import com.ruoyi.quality.mapper.QualityInspectMapper;
@@ -30,6 +29,10 @@
import com.ruoyi.sales.service.ISalesLedgerProductService;
import com.ruoyi.stock.mapper.StockInventoryMapper;
import com.ruoyi.stock.pojo.StockInventory;
import com.ruoyi.technology.bean.vo.TechnologyBomStructureVo;
import com.ruoyi.technology.mapper.TechnologyBomStructureMapper;
import com.ruoyi.technology.mapper.TechnologyRoutingMapper;
import com.ruoyi.technology.pojo.TechnologyRouting;
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -57,24 +60,19 @@
public class SalesLedgerProductServiceImpl extends ServiceImpl<SalesLedgerProductMapper, SalesLedgerProduct> implements ISalesLedgerProductService {
    private SalesLedgerProductMapper salesLedgerProductMapper;
    private SalesLedgerProductionAccountingMapper salesLedgerProductionAccountingMapper;
    private ProductionAccountMapper productionAccountMapper;
    private SalesLedgerMapper salesLedgerMapper;
    private PurchaseLedgerMapper purchaseLedgerMapper;
    private ProductOrderMapper productOrderMapper;
    private ProcessRouteItemMapper processRouteItemMapper;
    private ProductProcessRouteItemMapper productProcessRouteItemMapper;
    private ProductionOrderMapper productionOrderMapper;
    private ProductionOperationTaskMapper productionOperationTaskMapper;
    private ProductionOrderService productionOrderService;
    private TechnologyRoutingMapper technologyRoutingMapper;
    private TechnologyBomStructureMapper technologyBomStructureMapper;
    private InvoiceRegistrationProductMapper invoiceRegistrationProductMapper;
    private ProcessRouteMapper processRouteMapper;
    private ProductProcessRouteMapper productProcessRouteMapper;
    private ProductWorkOrderMapper productWorkOrderMapper;
    private ProductionProductMainMapper productionProductMainMapper;
    private ProductionProductOutputMapper productionProductOutputMapper;
    private ProductionProductInputMapper productionProductInputMapper;
@@ -87,12 +85,7 @@
    @Autowired
    private ProductStructureMapper productStructureMapper;
    @Autowired
    private StockInventoryMapper stockInventoryMapper;
    @Autowired
    private ProductOrderServiceImpl productOrderServiceImpl;
    @Override
    public SalesLedgerProduct selectSalesLedgerProductById(Long id) {
        return salesLedgerProductMapper.selectById(id);
@@ -266,70 +259,25 @@
     * æ–°å¢žç”Ÿäº§æ•°æ®
     */
    public void addProductionData(SalesLedgerProduct salesLedgerProduct) {
        ProductOrder productOrder = new ProductOrder();
        productOrder.setSalesLedgerId(salesLedgerProduct.getSalesLedgerId());
        productOrder.setProductModelId(salesLedgerProduct.getProductModelId());
        productOrder.setSaleLedgerProductId(salesLedgerProduct.getId());
        String string = productOrderServiceImpl.generateNextOrderNo(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd")));
        productOrder.setNpsNo(string);
        productOrder.setQuantity(salesLedgerProduct.getQuantity());//需求数量
        productOrder.setCompleteQuantity(BigDecimal.ZERO);//完成数量
        productOrderMapper.insert(productOrder);
        ProductionOrder productionOrder = new ProductionOrder();
        productionOrder.setSalesLedgerId(salesLedgerProduct.getSalesLedgerId());
        productionOrder.setProductModelId(salesLedgerProduct.getProductModelId());
        productionOrder.setSaleLedgerProductId(salesLedgerProduct.getId().intValue());
        productionOrder.setNpsNo(generateNextOrderNo(LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"))));
        productionOrder.setQuantity(salesLedgerProduct.getQuantity());
        productionOrder.setCompleteQuantity(BigDecimal.ZERO);
        List<ProcessRoute> processRoutes = processRouteMapper.selectList(new QueryWrapper<ProcessRoute>().lambda()
                .eq(ProcessRoute::getProductModelId, salesLedgerProduct.getProductModelId())
                .orderByDesc(ProcessRoute::getCreateTime));
        if (processRoutes.size()>0){
            ProcessRoute processRoute = processRoutes.get(0);
            //新增生产订单工艺路线主表
            ProductProcessRoute productProcessRoute = new ProductProcessRoute();
            productProcessRoute.setProductModelId(processRoute.getProductModelId());
            productProcessRoute.setProcessRouteCode(processRoute.getProcessRouteCode());
            productProcessRoute.setProductOrderId(productOrder.getId());
            productProcessRoute.setBomId(processRoute.getBomId());
            productProcessRouteMapper.insert(productProcessRoute);
            //新增生产订单工艺路线子表
            List<ProcessRouteItem> processRouteItems = processRouteItemMapper.selectList(new QueryWrapper<ProcessRouteItem>().lambda().eq(ProcessRouteItem::getRouteId, processRoute.getId()));
            // ç”Ÿæˆå½“前日期的前缀:年月日
            String datePrefix = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
            for (ProcessRouteItem processRouteItem : processRouteItems) {
                ProductProcessRouteItem productProcessRouteItem = new ProductProcessRouteItem();
                productProcessRouteItem.setProductModelId(processRouteItem.getProductModelId());
                productProcessRouteItem.setProcessId(processRouteItem.getProcessId());
                productProcessRouteItem.setProductOrderId(productOrder.getId());
                productProcessRouteItem.setProductRouteId(productProcessRoute.getId());
                productProcessRouteItem.setDragSort(processRouteItem.getDragSort());
                int insert = productProcessRouteItemMapper.insert(productProcessRouteItem);
                if (insert > 0) {
                    // æŸ¥è¯¢ä»Šæ—¥å·²å­˜åœ¨çš„æœ€å¤§å·¥å•号
                    ProductWorkOrder lastWorkOrder = productWorkOrderMapper.selectMax(datePrefix);
                    int sequenceNumber = 1; // é»˜è®¤åºå·
                    if (lastWorkOrder != null && lastWorkOrder.getWorkOrderNo() != null) {
                        String lastNo = lastWorkOrder.getWorkOrderNo().toString();
                        if (lastNo.startsWith(datePrefix)) {
                            String seqStr = lastNo.substring(datePrefix.length());
                            try {
                                sequenceNumber = Integer.parseInt(seqStr) + 1;
                            } catch (NumberFormatException e) {
                                sequenceNumber = 1;
                            }
                        }
                    }
                    // ç”Ÿæˆå®Œæ•´çš„工单号
                    String workOrderNoStr ="GD"+ String.format("%s%03d", datePrefix, sequenceNumber);
                    ProductWorkOrder productWorkOrder = new ProductWorkOrder();
                    productWorkOrder.setProductProcessRouteItemId(productProcessRouteItem.getId());
                    productWorkOrder.setProductOrderId(productOrder.getId());
                    productWorkOrder.setPlanQuantity(salesLedgerProduct.getQuantity());
                    productWorkOrder.setWorkOrderNo(workOrderNoStr);
                    productWorkOrder.setStatus(1);
                    productWorkOrderMapper.insert(productWorkOrder);
                }
            }
            productOrder.setRouteId(processRoute.getId());
            productOrderMapper.updateById(productOrder);
        TechnologyRouting routing = technologyRoutingMapper.selectOne(
                new QueryWrapper<TechnologyRouting>().lambda()
                        .eq(TechnologyRouting::getProductModelId, salesLedgerProduct.getProductModelId())
                        .orderByDesc(TechnologyRouting::getCreateTime)
                        .last("LIMIT 1"));
        if (routing != null) {
            productionOrder.setTechnologyRoutingId(routing.getId());
        }
        productionOrderMapper.insert(productionOrder);
        if (productionOrder.getTechnologyRoutingId() != null) {
            productionOrderService.syncProductionOrderSnapshot(productionOrder.getId());
        }
    }
@@ -337,93 +285,44 @@
     * åˆ é™¤ç”Ÿäº§æ•°æ®
     */
    public void deleteProductionData(List<Long> productIds) {
        //批量查询productOrder
        List<ProductOrder> productOrders = productOrderMapper.selectList(
                new LambdaQueryWrapper<ProductOrder>()
                        .in(ProductOrder::getSaleLedgerProductId, productIds)
        );
        if (!org.springframework.util.CollectionUtils.isEmpty(productOrders)) {
            List<Long> orderIds = productOrders.stream()
                    .map(ProductOrder::getId)
                    .collect(Collectors.toList());
            // æ‰¹é‡æŸ¥è¯¢processRouteItems
            List<ProductProcessRouteItem> allRouteItems = productProcessRouteItemMapper.selectList(
                    new LambdaQueryWrapper<ProductProcessRouteItem>()
                            .in(ProductProcessRouteItem::getProductOrderId, orderIds)
            );
            if (!com.baomidou.mybatisplus.core.toolkit.CollectionUtils.isEmpty(allRouteItems)) {
                // èŽ·å–è¦åˆ é™¤çš„å·¥åºé¡¹ID
                List<Long> routeItemIds = allRouteItems.stream()
                        .map(ProductProcessRouteItem::getId)
                        .collect(Collectors.toList());
                // æŸ¥è¯¢å…³è”的工单ID
                List<ProductWorkOrder> workOrders = productWorkOrderMapper.selectList(
                        new LambdaQueryWrapper<ProductWorkOrder>()
                                .in(ProductWorkOrder::getProductProcessRouteItemId, routeItemIds)
                );
                if (!com.baomidou.mybatisplus.core.toolkit.CollectionUtils.isEmpty(workOrders)) {
                    List<Long> workOrderIds = workOrders.stream()
                            .map(ProductWorkOrder::getId)
                            .collect(Collectors.toList());
                    // æŸ¥è¯¢å…³è”的生产主表ID
                    List<ProductionProductMain> productMains = productionProductMainMapper.selectList(
                            new LambdaQueryWrapper<ProductionProductMain>()
                                    .in(ProductionProductMain::getWorkOrderId, workOrderIds)
                    );
                    List<Long> productMainIds = productMains.stream()
                            .map(ProductionProductMain::getId)
                            .collect(Collectors.toList());
                    // åˆ é™¤äº§å‡ºè¡¨ã€æŠ•入表数据
                    if (!com.baomidou.mybatisplus.core.toolkit.CollectionUtils.isEmpty(productMainIds)) {
                        productionProductOutputMapper.deleteByProductMainIds(productMainIds);
                        productionProductInputMapper.deleteByProductMainIds(productMainIds);
                        List<QualityInspect> qualityInspects = qualityInspectMapper.selectList(
                                new LambdaQueryWrapper<QualityInspect>()
                                        .in(QualityInspect::getProductMainId, productMainIds)
                        );
                        //删除出库记录
                        for (Long productMainId : productMainIds) {
                            //删除生产出库记录
                            stockUtils.deleteStockOutRecord(productMainId, StockOutQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_OUT.getCode());
                            //删除报废的入库记录
                            stockUtils.deleteStockInRecord(productMainId, StockInUnQualifiedRecordTypeEnum.PRODUCTION_SCRAP.getCode());
                        }
                        qualityInspects.forEach(qualityInspect -> {
                            //inspectState=1 å·²æäº¤ ä¸èƒ½åˆ é™¤
                            if (qualityInspect.getInspectState() == 1) {
                                throw new RuntimeException("已提交的检验单不能删除");
                            }
                        });
                        qualityInspectMapper.deleteByProductMainIds(productMainIds);
                        salesLedgerProductionAccountingMapper.delete(new LambdaQueryWrapper<SalesLedgerProductionAccounting>()
                                .in(SalesLedgerProductionAccounting::getProductMainId, productMainIds));
        List<ProductionOrder> productionOrders = productionOrderMapper.selectList(
                new LambdaQueryWrapper<ProductionOrder>()
                        .in(ProductionOrder::getSaleLedgerProductId, productIds.stream().map(Long::intValue).collect(Collectors.toList())));
        if (org.springframework.util.CollectionUtils.isEmpty(productionOrders)) {
            return;
        }
        List<Long> orderIds = productionOrders.stream().map(ProductionOrder::getId).collect(Collectors.toList());
        List<Long> taskIds = productionOperationTaskMapper.selectList(
                        new LambdaQueryWrapper<ProductionOperationTask>()
                                .in(ProductionOperationTask::getProductionOrderId, orderIds))
                .stream().map(ProductionOperationTask::getId).collect(Collectors.toList());
        if (!taskIds.isEmpty()) {
            List<ProductionProductMain> productMains = productionProductMainMapper.selectList(
                    new LambdaQueryWrapper<ProductionProductMain>()
                            .in(ProductionProductMain::getProductionOperationTaskId, taskIds));
            List<Long> productMainIds = productMains.stream().map(ProductionProductMain::getId).collect(Collectors.toList());
            if (!productMainIds.isEmpty()) {
                List<QualityInspect> qualityInspects = qualityInspectMapper.selectList(
                        new LambdaQueryWrapper<QualityInspect>().in(QualityInspect::getProductMainId, productMainIds));
                qualityInspects.forEach(qualityInspect -> {
                    if (qualityInspect.getInspectState() == 1) {
                        throw new RuntimeException("已提交的检验单不能删除");
                    }
                    // åˆ é™¤ç”Ÿäº§ä¸»è¡¨æ•°æ®
                    productionProductMainMapper.deleteByWorkOrderIds(workOrderIds);
                    // åˆ é™¤å·¥å•数据
                    productWorkOrderMapper.delete(new LambdaQueryWrapper<ProductWorkOrder>()
                            .in(ProductWorkOrder::getProductProcessRouteItemId, routeItemIds));
                });
                productionProductOutputMapper.deleteByProductMainIds(productMainIds);
                productionProductInputMapper.deleteByProductMainIds(productMainIds);
                qualityInspectMapper.deleteByProductMainIds(productMainIds);
                productionAccountMapper.delete(new LambdaQueryWrapper<ProductionAccount>()
                        .in(ProductionAccount::getProductionProductMainId, productMainIds));
                for (Long productMainId : productMainIds) {
                    stockUtils.deleteStockOutRecord(productMainId, StockOutQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_OUT.getCode());
                    stockUtils.deleteStockInRecord(productMainId, StockInUnQualifiedRecordTypeEnum.PRODUCTION_SCRAP.getCode());
                }
            }
            // æ‰¹é‡åˆ é™¤processRouteItem
            productProcessRouteItemMapper.delete(new LambdaQueryWrapper<ProductProcessRouteItem>()
                    .in(ProductProcessRouteItem::getProductOrderId, orderIds));
            // æ‰¹é‡åˆ é™¤productProcessRoute
            productProcessRouteMapper.delete(new LambdaQueryWrapper<ProductProcessRoute>()
                    .in(ProductProcessRoute::getProductOrderId, orderIds));
            // æ‰¹é‡åˆ é™¤productOrder
            productOrderMapper.delete(new LambdaQueryWrapper<ProductOrder>()
                    .in(ProductOrder::getSaleLedgerProductId, productIds));
            productionProductMainMapper.delete(new LambdaQueryWrapper<ProductionProductMain>()
                    .in(ProductionProductMain::getProductionOperationTaskId, taskIds));
        }
        productionOrderService.removeProductionOrder(orderIds);
    }
    @Override
@@ -490,37 +389,67 @@
    }
    @Override
    public R judgmentInventory(SalesLedgerProduct salesLedgerProduct) {
        //获取产品最新的工艺路线
        ProcessRoute processRoute = processRouteMapper.selectOne(new QueryWrapper<ProcessRoute>().lambda().eq(ProcessRoute::getProductModelId, salesLedgerProduct.getProductModelId()).orderByDesc(ProcessRoute::getCreateTime).last("LIMIT 1"));
        if (processRoute == null) {
        TechnologyRouting routing = technologyRoutingMapper.selectOne(
                new QueryWrapper<TechnologyRouting>().lambda()
                        .eq(TechnologyRouting::getProductModelId, salesLedgerProduct.getProductModelId())
                        .orderByDesc(TechnologyRouting::getCreateTime)
                        .last("LIMIT 1"));
        if (routing == null) {
            return R.fail("请先设置工艺路线");
        }
        List<ProductStructureDto> productStructureDtos = productStructureMapper.listBybomId(processRoute.getBomId());
        if (productStructureDtos.isEmpty()) {
        List<TechnologyBomStructureVo> structureList = technologyBomStructureMapper.listByBomId(routing.getBomId().longValue());
        if (structureList == null || structureList.isEmpty()) {
            return R.fail("请先设置产品结构");
        }
        int count = 0;
        StringBuilder stringBuffer = new StringBuilder();
        for (ProductStructureDto productStructureDto : productStructureDtos) {
            StockInventory stockInventory = stockInventoryMapper.selectOne(new QueryWrapper<StockInventory>().lambda().eq(StockInventory::getProductModelId, productStructureDto.getProductModelId()));
            //所需数量
            BigDecimal multiply = salesLedgerProduct.getQuantity().multiply(productStructureDto.getUnitQuantity());
            BigDecimal subtract =stockInventory.getQualitity().subtract(stockInventory.getLockedQuantity()).subtract(multiply).divide(BigDecimal.ONE, 2, RoundingMode.CEILING);
            if (subtract.compareTo(BigDecimal.ZERO) <= 0) {
        for (TechnologyBomStructureVo structure : structureList) {
            if (structure.getParentId() == null) {
                continue;
            }
            StockInventory stockInventory = stockInventoryMapper.selectOne(
                    new QueryWrapper<StockInventory>().lambda().eq(StockInventory::getProductModelId, structure.getProductModelId()));
            if (stockInventory == null) {
                count++;
                stringBuffer.append(productStructureDto.getProductName())
                stringBuffer.append(structure.getProductName()).append("-").append(structure.getModel()).append("库存不足").append(System.lineSeparator());
                continue;
            }
            BigDecimal required = salesLedgerProduct.getQuantity().multiply(structure.getUnitQuantity() == null ? BigDecimal.ZERO : structure.getUnitQuantity());
            BigDecimal remain = stockInventory.getQualitity()
                    .subtract(stockInventory.getLockedQuantity())
                    .subtract(required)
                    .divide(BigDecimal.ONE, 2, RoundingMode.CEILING);
            if (remain.compareTo(BigDecimal.ZERO) < 0) {
                count++;
                stringBuffer.append(structure.getProductName())
                        .append("-")
                        .append(productStructureDto.getModel())
                        .append(structure.getModel())
                        .append("库存不足,少")
                        .append(subtract)
                        .append(remain.abs())
                        .append(System.lineSeparator());
            }
        }
        if (count>0) {
        if (count > 0) {
            return R.fail(stringBuffer.toString());
        }else {
            return R.ok();
        }
        return R.ok();
    }
    private String generateNextOrderNo(String datePrefix) {
        QueryWrapper<ProductionOrder> queryWrapper = new QueryWrapper<>();
        queryWrapper.likeRight("nps_no", "SC" + datePrefix);
        queryWrapper.orderByDesc("nps_no");
        queryWrapper.last("LIMIT 1");
        ProductionOrder latestOrder = productionOrderMapper.selectOne(queryWrapper);
        int sequence = 1;
        if (latestOrder != null && latestOrder.getNpsNo() != null && !latestOrder.getNpsNo().isEmpty()) {
            String sequenceStr = latestOrder.getNpsNo().substring(("SC" + datePrefix).length());
            try {
                sequence = Integer.parseInt(sequenceStr) + 1;
            } catch (NumberFormatException e) {
                sequence = 1;
            }
        }
        return "SC" + datePrefix + String.format("%04d", sequence);
    }
}
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
@@ -15,7 +15,6 @@
import com.ruoyi.basic.mapper.ProductMapper;
import com.ruoyi.basic.mapper.ProductModelMapper;
import com.ruoyi.basic.pojo.Customer;
import com.ruoyi.basic.pojo.CustomerPrivatePool;
import com.ruoyi.common.enums.FileNameType;
import com.ruoyi.common.enums.SaleEnum;
import com.ruoyi.common.exception.base.BaseException;
@@ -97,17 +96,8 @@
    private final CommonFileServiceImpl commonFileService;
    private final ShippingInfoMapper shippingInfoMapper;
    private final InvoiceLedgerMapper invoiceLedgerMapper;
    private final SalesLedgerSchedulingMapper salesLedgerSchedulingMapper;
    private final SalesLedgerWorkMapper salesLedgerWorkMapper;
    private final SalesLedgerProductionAccountingMapper salesLedgerProductionAccountingMapper;
    private final InvoiceRegistrationProductMapper invoiceRegistrationProductMapper;
    private final InvoiceRegistrationMapper invoiceRegistrationMapper;
    private final ProductOrderMapper productOrderMapper;
    private final ProcessRouteMapper processRouteMapper;
    private final ProductProcessRouteMapper productProcessRouteMapper;
    private final ProcessRouteItemMapper processRouteItemMapper;
    private final ProductProcessRouteItemMapper productProcessRouteItemMapper;
    private final ProductWorkOrderMapper productWorkOrderMapper;
    private final ProductionProductMainMapper productionProductMainMapper;
    private final ProductionProductOutputMapper productionProductOutputMapper;
    private final ProductionProductInputMapper productionProductInputMapper;
@@ -123,12 +113,9 @@
    @Autowired
    private ProductMapper productMapper;
    @Autowired
    private ProductStructureMapper productStructureMapper;
    @Autowired
    private ProductionProductMainService productionProductMainService;
    @Autowired
    private PurchaseReturnOrderProductsMapper purchaseReturnOrderProductsMapper;
    ;
    @Autowired
    private SysUserMapper sysUserMapper;
    @Autowired
src/main/java/com/ruoyi/staff/service/impl/SchemeApplicableStaffServiceImpl.java
@@ -2,35 +2,34 @@
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.production.dto.UserAccountDto;
import com.ruoyi.production.dto.UserProductionAccountingDto;
import com.ruoyi.production.bean.dto.UserAccountDto;
import com.ruoyi.production.bean.dto.UserProductionAccountingDto;
import com.ruoyi.production.service.SalesLedgerProductionAccountingService;
import com.ruoyi.project.system.domain.SysDept;
import com.ruoyi.project.system.domain.SysUser;
import com.ruoyi.project.system.domain.SysUserDept;
import com.ruoyi.project.system.mapper.SysDeptMapper;
import com.ruoyi.project.system.mapper.SysUserDeptMapper;
import com.ruoyi.project.system.mapper.SysUserMapper;
import com.ruoyi.staff.controller.TaxCalculator;
import com.ruoyi.staff.dto.StaffOnJobDto;
import com.ruoyi.staff.mapper.SchemeApplicableStaffMapper;
import com.ruoyi.staff.mapper.SchemeInsuranceDetailMapper;
import com.ruoyi.staff.mapper.StaffOnJobMapper;
import com.ruoyi.staff.pojo.SchemeApplicableStaff;
import com.ruoyi.staff.mapper.SchemeApplicableStaffMapper;
import com.ruoyi.staff.pojo.SchemeInsuranceDetail;
import com.ruoyi.staff.pojo.StaffOnJob;
import com.ruoyi.staff.service.IStaffOnJobService;
import com.ruoyi.staff.service.SchemeApplicableStaffService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import jakarta.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;
/**
src/main/java/com/ruoyi/technology/bean/dto/BomImportDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,37 @@
package com.ruoyi.technology.bean.dto;
import com.ruoyi.framework.aspectj.lang.annotation.Excel;
import lombok.Data;
import java.math.BigDecimal;
@Data
public class BomImportDto {
    @Excel(name = "父项产品编号")
    private String parentCode;
    @Excel(name = "父项产品名称")
    private String parentName;
    @Excel(name = "父项产品规格")
    private String parentSpec;
    @Excel(name = "子项产品编号")
    private String childCode;
    @Excel(name = "子项产品名称")
    private String childName;
    @Excel(name = "子项产品规格")
    private String childSpec;
    @Excel(name = "单位用量")
    private BigDecimal unitQty;
    @Excel(name = "投料工序")
    private String process;
    @Excel(name = "备注")
    private String remark;
}
src/main/java/com/ruoyi/technology/bean/dto/TechnologyRoutingOperationParamDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,12 @@
package com.ruoyi.technology.bean.dto;
import com.ruoyi.technology.pojo.TechnologyRoutingOperationParam;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "TechnologyRoutingOperationParamDto对象", description = "工艺路线工序参数查询参数")
public class TechnologyRoutingOperationParamDto extends TechnologyRoutingOperationParam {
}
src/main/java/com/ruoyi/technology/bean/dto/TechnologyRoutingOperationParamSyncDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,16 @@
package com.ruoyi.technology.bean.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@Data
@ApiModel(value = "TechnologyRoutingOperationParamSyncDto对象", description = "工艺路线工序参数同步参数")
public class TechnologyRoutingOperationParamSyncDto {
    @ApiModelProperty("工艺路线工序id")
    private Long technologyRoutingOperationId;
    @ApiModelProperty("是否覆盖当前工序已存在参数,默认true")
    private Boolean replaceExisting;
}
src/main/java/com/ruoyi/technology/bean/vo/TechnologyRoutingOperationParamVo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,12 @@
package com.ruoyi.technology.bean.vo;
import com.ruoyi.technology.pojo.TechnologyRoutingOperationParam;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = true)
@ApiModel(value = "TechnologyRoutingOperationParamVo对象", description = "工艺路线工序参数返回对象")
public class TechnologyRoutingOperationParamVo extends TechnologyRoutingOperationParam {
}
src/main/java/com/ruoyi/technology/controller/TechnologyBomController.java
@@ -6,19 +6,19 @@
import com.ruoyi.framework.aspectj.lang.annotation.Log;
import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.production.dto.BomImportDto;
import com.ruoyi.technology.bean.dto.BomImportDto;
import com.ruoyi.technology.bean.dto.TechnologyBomDto;
import com.ruoyi.technology.bean.vo.TechnologyBomVo;
import com.ruoyi.technology.pojo.TechnologyBom;
import com.ruoyi.technology.service.TechnologyBomService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import jakarta.servlet.http.HttpServletResponse;
import java.util.List;
@RestController
@@ -53,7 +53,7 @@
    @DeleteMapping("/batchDelete")
    @Log(title = "Delete technology BOM", businessType = BusinessType.DELETE)
    @ApiOperation("批量删除BOM")
    public R batchDelete(@RequestBody List<Integer> ids) {
    public R batchDelete(@RequestBody List<Long> ids) {
        return R.ok(technologyBomService.batchDelete(ids));
    }
src/main/java/com/ruoyi/technology/service/TechnologyBomService.java
@@ -7,9 +7,9 @@
import com.ruoyi.technology.bean.dto.TechnologyBomDto;
import com.ruoyi.technology.bean.vo.TechnologyBomVo;
import com.ruoyi.technology.pojo.TechnologyBom;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.web.multipart.MultipartFile;
import jakarta.servlet.http.HttpServletResponse;
import java.util.List;
public interface TechnologyBomService extends IService<TechnologyBom> {
@@ -22,7 +22,7 @@
    R update(TechnologyBom technologyBom);
    boolean batchDelete(List<Integer> ids);
    boolean batchDelete(List<Long> ids);
    R uploadBom(MultipartFile file);
src/main/java/com/ruoyi/technology/service/impl/TechnologyBomServiceImpl.java
@@ -13,9 +13,8 @@
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.production.dto.BomImportDto;
import com.ruoyi.production.dto.ProductStructureDto;
import com.ruoyi.production.pojo.ProductStructure;
import com.ruoyi.production.bean.dto.BomImportDto;
import com.ruoyi.production.bean.dto.ProductStructureDto;
import com.ruoyi.technology.bean.dto.TechnologyBomDto;
import com.ruoyi.technology.bean.vo.TechnologyBomVo;
import com.ruoyi.technology.mapper.TechnologyBomMapper;
@@ -25,12 +24,12 @@
import com.ruoyi.technology.pojo.TechnologyRouting;
import com.ruoyi.technology.service.TechnologyBomService;
import com.ruoyi.technology.service.TechnologyBomStructureService;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;
import jakarta.servlet.http.HttpServletResponse;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
@@ -127,7 +126,7 @@
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean batchDelete(List<Integer> ids) {
    public boolean batchDelete(List<Long> ids) {
        if (ids == null || ids.isEmpty()) {
            throw new ServiceException("Select at least one BOM");
        }
@@ -212,13 +211,13 @@
            //处理根节点,第一行且子项为空
            if (i == 0 && StringUtils.isBlank(dto.getChildName())) {
                ProductStructure rootNode = new ProductStructure();
                rootNode.setBomId(bom.getId());
                TechnologyBomStructure rootNode = new TechnologyBomStructure();
                rootNode.setBomId(bom.getId().longValue());
                rootNode.setParentId(null); // é¡¶å±‚没有父节点
                rootNode.setProductModelId(rootModel.getId());
                rootNode.setUnitQuantity(BigDecimal.ONE);
                rootNode.setUnit(rootModel.getUnit());
//                productStructureService.save(rootNode);
                technologyBomStructureService.save(rootNode);
                treePathMap.put(parentKey, rootNode.getId());
                continue;
@@ -236,8 +235,8 @@
            ProductModel childModel = findModel(dto.getChildName(), dto.getChildSpec());
            //  æ’入结构表
            ProductStructure node = new ProductStructure();
            node.setBomId(bom.getId());
            TechnologyBomStructure node = new TechnologyBomStructure();
            node.setBomId(bom.getId().longValue());
            node.setParentId(parentStructureId); // çˆ¶èŠ‚ç‚¹ID
            node.setProductModelId(childModel.getId());
            node.setUnitQuantity(dto.getUnitQty());
@@ -245,7 +244,7 @@
//            if (processMap.containsKey(dto.getProcess())) {
//                node.setProcessId(processMap.get(dto.getProcess()));
//            }
//            productStructureService.save(node);
            technologyBomStructureService.save(node);
            //  æŠŠå½“前子项记录到 Map,作为以后更深层级的父项查找依据
            //  åŒä¸€çˆ¶é¡¹ä¸‹çš„同名子项不需要重复记录
src/main/resources/application.yml
@@ -1,4 +1,6 @@
# Spring配置
spring:
  main:
    allow-circular-references: true
  profiles:
    active: dev
src/main/resources/mapper/production/ProcessRouteItemMapper.xml
ÎļþÒÑɾ³ý
src/main/resources/mapper/production/ProcessRouteMapper.xml
ÎļþÒÑɾ³ý
src/main/resources/mapper/production/ProductBomMapper.xml
ÎļþÒÑɾ³ý
src/main/resources/mapper/production/ProductOrderMapper.xml
ÎļþÒÑɾ³ý
src/main/resources/mapper/production/ProductOrderMaterialMapper.xml
ÎļþÒÑɾ³ý
src/main/resources/mapper/production/ProductProcessMapper.xml
ÎļþÒÑɾ³ý
src/main/resources/mapper/production/ProductProcessRouteItemMapper.xml
ÎļþÒÑɾ³ý
src/main/resources/mapper/production/ProductProcessRouteMapper.xml
ÎļþÒÑɾ³ý
src/main/resources/mapper/production/ProductStructureMapper.xml
ÎļþÒÑɾ³ý
src/main/resources/mapper/production/ProductWorkOrderFileMapper.xml
ÎļþÒÑɾ³ý
src/main/resources/mapper/production/ProductWorkOrderMapper.xml
ÎļþÒÑɾ³ý
src/main/resources/mapper/production/ProductionAccountMapper.xml
@@ -21,4 +21,24 @@
        <result column="dept_id" property="deptId" />
    </resultMap>
    <select id="selectUserAccount" resultType="com.ruoyi.production.bean.dto.UserAccountDto">
        select ifnull(sum(finished_num), 0) as accountBalance,
               ifnull(sum(work_hours), 0) as account
        from production_account
        where scheduling_user_id = #{userId}
          and date_format(scheduling_date, '%Y-%m') = #{date}
    </select>
    <select id="selectDailyWagesStats" resultType="java.util.Map">
        select date_format(scheduling_date, '%m-%d') as dateStr,
               cast(ifnull(sum(finished_num), 0) as decimal(18,2)) as numberOfCompleted,
               cast(ifnull(sum(work_hours), 0) as decimal(18,2)) as amount,
               cast(0 as decimal(18,2)) as passRate
        from production_account
        where scheduling_date &gt;= #{startDate}
          and scheduling_date &lt;= #{endDate}
        group by date_format(scheduling_date, '%m-%d')
        order by date_format(scheduling_date, '%m-%d')
    </select>
</mapper>
src/main/resources/mapper/production/ProductionOperationTaskMapper.xml
@@ -21,4 +21,68 @@
        <result column="dept_id" property="deptId" />
    </resultMap>
    <select id="selectTaskStatisticsByDate" resultType="com.ruoyi.home.dto.ProductionTaskStatisticsDto">
        select pot.id,
               pot.work_order_no,
               pot.plan_start_time as planStartTime,
               pot.plan_end_time as planEndTime,
               pot.actual_start_time as actualStartTime,
               pot.actual_end_time as actualEndTime,
               pot.plan_quantity as planQuantity,
               ifnull(pot.complete_quantity, 0) as completeQuantity,
               top2.name as processName,
               p.product_name as productName,
               pm.model,
               pm.unit,
               po.nps_no as productOrderNpsNo
        from production_operation_task pot
                 left join production_order po on pot.production_order_id = po.id
                 left join product_model pm on po.product_model_id = pm.id
                 left join product p on pm.product_id = p.id
                 left join technology_routing_operation tro on pot.technology_routing_operation_id = tro.id
                 left join technology_operation top2 on tro.technology_operation_id = top2.id
        where date(pot.create_time) between #{startDate} and #{endDate}
        order by pot.create_time desc
    </select>
    <select id="selectTaskStartStats" resultType="com.ruoyi.home.dto.ProductionTaskStatisticsDto">
        select id,
               actual_start_time as actualStartTime,
               plan_quantity as planQuantity
        from production_operation_task
        where actual_start_time &gt;= #{startDateTime}
          and actual_start_time &lt;= #{endDateTime}
    </select>
    <select id="calculateProductionStatistics" resultType="com.ruoyi.home.dto.processDataProductionStatisticsDto">
        select top2.name as processName,
               sum(ifnull(ppi.input_quantity, 0)) as totalInput,
               sum(ifnull(ppo.scrap_qty, 0)) as totalScrap,
               sum(ifnull(ppo.quantity, 0) - ifnull(ppo.scrap_qty, 0)) as totalOutput
        from production_product_output ppo
                 inner join production_product_main ppm on ppo.production_product_main_id = ppm.id
                 inner join production_operation_task pot on ppm.production_operation_task_id = pot.id
                 inner join technology_routing_operation tro on pot.technology_routing_operation_id = tro.id
                 inner join technology_operation top2 on tro.technology_operation_id = top2.id
                 left join production_product_input ppi on ppi.production_product_main_id = ppm.id
        <where>
            <if test="startDateTime != null">
                and ppo.create_time &gt;= #{startDateTime}
            </if>
            <if test="endDateTime != null">
                and ppo.create_time &lt;= #{endDateTime}
            </if>
            <if test="userId != null">
                and ppm.create_user = #{userId}
            </if>
            <if test="processIds != null and processIds.size() > 0">
                and top2.id in
                <foreach collection="processIds" item="id" open="(" separator="," close=")">
                    #{id}
                </foreach>
            </if>
        </where>
        group by top2.id, top2.name
    </select>
</mapper>
src/main/resources/mapper/production/ProductionOrderMapper.xml
@@ -21,4 +21,52 @@
        <result column="dept_id" property="deptId" />
    </resultMap>
    <select id="selectProgressOrders" resultType="com.ruoyi.home.dto.ProductionProgressOrderDto">
        select po.nps_no,
               sl.sales_contract_no,
               sl.project_name,
               sl.customer_name,
               p.product_name as productCategory,
               pm.model as specificationModel,
               tr.process_route_code as processRouteCode,
               po.quantity,
               ifnull(po.complete_quantity, 0) as completeQuantity,
               round(ifnull(po.complete_quantity, 0) / nullif(po.quantity, 0) * 100, 2) as completionStatus,
               tb.bom_no,
               datediff(sl.delivery_date, curdate()) as deliveryDaysDiff,
               sl.delivery_date,
               false as isFh
        from production_order po
                 left join sales_ledger sl on po.sales_ledger_id = sl.id
                 left join product_model pm on po.product_model_id = pm.id
                 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 tr.bom_id = tb.id
        where po.create_time between #{startTime} and #{endTime}
        order by po.create_time desc
    </select>
    <select id="countCreated" resultType="java.lang.Integer">
        select count(1)
        from production_order
        where create_time &gt;= #{startDate}
          and create_time &lt;= #{endDate}
    </select>
    <select id="countCompleted" resultType="java.lang.Integer">
        select count(1)
        from production_order
        where end_time &gt;= #{startDate}
          and end_time &lt;= #{endDate}
          and ifnull(complete_quantity, 0) &gt;= quantity
    </select>
    <select id="countPending" resultType="java.lang.Integer">
        select count(1)
        from production_order
        where create_time &gt;= #{startDate}
          and create_time &lt;= #{endDate}
          and ifnull(complete_quantity, 0) &lt; quantity
    </select>
</mapper>
src/main/resources/mapper/production/ProductionPlanMapper.xml
@@ -4,21 +4,89 @@
    <!-- é€šç”¨æŸ¥è¯¢æ˜ å°„结果 -->
    <resultMap id="BaseResultMap" type="com.ruoyi.production.pojo.ProductionPlan">
        <id column="id" property="id" />
        <result column="mps_no" property="mpsNo" />
        <result column="required_date" property="requiredDate" />
        <result column="remark" property="remark" />
        <result column="create_time" property="createTime" />
        <result column="update_time" property="updateTime" />
        <result column="create_user" property="createUser" />
        <result column="update_user" property="updateUser" />
        <result column="product_model_id" property="productModelId" />
        <result column="qty_required" property="qtyRequired" />
        <result column="state" property="state" />
        <result column="issued" property="issued" />
        <result column="source" property="source" />
        <result column="is_audit" property="isAudit" />
        <result column="promised_delivery_date" property="promisedDeliveryDate" />
        <id column="id" property="id"/>
        <result column="mps_no" property="mpsNo"/>
        <result column="required_date" property="requiredDate"/>
        <result column="remark" property="remark"/>
        <result column="create_time" property="createTime"/>
        <result column="update_time" property="updateTime"/>
        <result column="create_user" property="createUser"/>
        <result column="update_user" property="updateUser"/>
        <result column="product_model_id" property="productModelId"/>
        <result column="qty_required" property="qtyRequired"/>
        <result column="state" property="state"/>
        <result column="issued" property="issued"/>
        <result column="source" property="source"/>
        <result column="is_audit" property="isAudit"/>
        <result column="promised_delivery_date" property="promisedDeliveryDate"/>
    </resultMap>
    <select id="listPage" resultType="com.ruoyi.production.bean.dto.ProductionPlanDto">
        SELECT
        pp.*,
        pms.material_code AS materialCode,
        pms.model,
        pms.product_id AS productMaterialId,
        pm.product_name AS productName,
        pm.unit
        FROM production_plan pp
        left join product_material_sku pms on pp.product_material_sku_id = pms.id
        left join product_material pm on pms.product_id = pm.id
        WHERE 1 = 1
        <if test="c.customerName != null and c.customerName != '' ">
            AND pp.customer_name LIKE CONCAT('%',#{c.customerName},'%')
        </if>
        <if test="c.productName != null and c.productName != '' ">
            AND pm.product_name LIKE CONCAT('%',#{c.productName},'%')
        </if>
        <if test="c.materialCode != null and c.materialCode != '' ">
            AND pms.material_code LIKE CONCAT('%',#{c.materialCode},'%')
        </if>
        <if test="c.model != null and c.model != '' ">
            AND pms.model LIKE CONCAT('%',#{c.model},'%')
        </if>
        <if test="c.status != null">
            AND pp.status =#{c.status}
        </if>
        <if test="c.applyNo != null and c.applyNo != '' ">
            AND pp.apply_no LIKE CONCAT('%',#{c.applyNo},'%')
        </if>
        <if test="c.startDate != null">
            AND pp.start_date &gt;= DATE_FORMAT(#{c.startDate},'%Y-%m-%d')
        </if>
        <if test="c.endDate != null">
            AND pp.end_date &lt;= DATE_FORMAT(#{c.endDate},'%Y-%m-%d')
        </if>
        ORDER BY COALESCE(pp.form_modified_time, pp.id) DESC
    </select>
    <select id="selectWithMaterialByIds" resultType="com.ruoyi.production.bean.dto.ProductionPlanDto">
        SELECT
        pp.*,
        pms.material_code AS materialCode,
        pms.model,
        pm.product_name AS productName,
        pm.unit
        FROM production_plan pp
        LEFT JOIN product_material_sku pms ON pp.product_material_sku_id = pms.id
        LEFT JOIN product_material pm ON pms.product_id = pm.id
        WHERE pp.id IN
        <foreach collection="ids" item="id" open="(" separator="," close=")">
            #{id}
        </foreach>
        ORDER BY pp.id ASC
    </select>
    <select id="selectProductionPlanDtoById" resultType="com.ruoyi.production.bean.dto.ProductionPlanDto">
        SELECT
        pp.*,
        pms.material_code AS materialCode,
        pms.model,
        pms.product_id AS productMaterialId,
        pm.product_name AS productName,
        pm.unit
        FROM production_plan pp
        left join product_material_sku pms on pp.product_material_sku_id = pms.id
        left join product_material pm on pms.product_id = pm.id
        WHERE pp.id = #{productionPlanId}
    </select>
</mapper>
src/main/resources/mapper/production/ProductionProductInputMapper.xml
@@ -14,4 +14,30 @@
        <result column="update_user" property="updateUser" />
    </resultMap>
    <select id="listPageProductionProductInputDto" resultType="com.ruoyi.production.bean.dto.ProductionProductInputDto">
        select ppi.*,
               ppm.product_no as productNo,
               pm.model,
               p.product_name as productName,
               pm.unit
        from production_product_input ppi
                 left join production_product_main ppm on ppi.production_product_main_id = ppm.id
                 left join production_operation_task pot on ppm.production_operation_task_id = pot.id
                 left join production_order po on pot.production_order_id = po.id
                 left join product_model pm on po.product_model_id = pm.id
                 left join product p on pm.product_id = p.id
        <where>
            <if test="c.productNo != null and c.productNo != ''">
                and ppm.product_no like concat('%', #{c.productNo}, '%')
            </if>
            <if test="c.model != null and c.model != ''">
                and pm.model like concat('%', #{c.model}, '%')
            </if>
            <if test="c.productName != null and c.productName != ''">
                and p.product_name like concat('%', #{c.productName}, '%')
            </if>
        </where>
        order by ppi.create_time desc
    </select>
</mapper>
src/main/resources/mapper/production/ProductionProductMainMapper.xml
@@ -14,4 +14,97 @@
        <result column="update_user" property="updateUser" />
    </resultMap>
    <select id="listPageProductionProductMainDto" resultType="com.ruoyi.production.bean.dto.ProductionProductMainDto">
        select ppm.*,
               pot.work_order_no as workOrderNo,
               case pot.status
                   when 1 then '待确认'
                   when 2 then '待生产'
                   when 3 then '生产中'
                   when 4 then '已生产'
                   else '未知'
                   end as workOrderStatus,
               su.nick_name as nickName,
               ifnull(ppo.quantity, 0) as quantity,
               ifnull(ppo.scrap_qty, 0) as scrapQty,
               p.product_name as productName,
               pm.model as productModelName,
               pm.unit,
               sl.sales_contract_no as salesContractNo,
               date(ppm.create_time) as schedulingDate,
               su.nick_name as schedulingUserName,
               sl.customer_name as customerName,
               top2.name as process
        from production_product_main ppm
                 left join production_operation_task pot on ppm.production_operation_task_id = pot.id
                 left join production_order po on pot.production_order_id = po.id
                 left join sales_ledger sl on po.sales_ledger_id = sl.id
                 left join product_model pm on po.product_model_id = pm.id
                 left join product p on pm.product_id = p.id
                 left join technology_routing_operation tro on pot.technology_routing_operation_id = tro.id
                 left join technology_operation top2 on tro.technology_operation_id = top2.id
                 left join sys_user su on ppm.create_user = su.user_id
                 left join production_product_output ppo on ppo.production_product_main_id = ppm.id
        <where>
            <if test="c.productNo != null and c.productNo != ''">
                and ppm.product_no like concat('%', #{c.productNo}, '%')
            </if>
            <if test="c.workOrderNo != null and c.workOrderNo != ''">
                and pot.work_order_no like concat('%', #{c.workOrderNo}, '%')
            </if>
            <if test="c.salesContractNo != null and c.salesContractNo != ''">
                and sl.sales_contract_no like concat('%', #{c.salesContractNo}, '%')
            </if>
            <if test="c.customerName != null and c.customerName != ''">
                and sl.customer_name like concat('%', #{c.customerName}, '%')
            </if>
            <if test="c.productName != null and c.productName != ''">
                and p.product_name like concat('%', #{c.productName}, '%')
            </if>
            <if test="c.productModelName != null and c.productModelName != ''">
                and pm.model like concat('%', #{c.productModelName}, '%')
            </if>
            <if test="c.process != null and c.process != ''">
                and top2.name like concat('%', #{c.process}, '%')
            </if>
            <if test="c.schedulingDate != null">
                and date(ppm.create_time) = #{c.schedulingDate}
            </if>
        </where>
        order by ppm.create_time desc
    </select>
    <select id="getOrderByMainId" resultType="com.ruoyi.production.pojo.ProductionOrder">
        select null
    </select>
    <select id="listProductionDetails" resultType="com.ruoyi.production.bean.dto.ProductionProductMainDto">
        select ppm.*,
               pot.work_order_no as workOrderNo,
               p.product_name as productName,
               pm.model as productModelName,
               pm.unit,
               top2.name as process,
               ifnull(ppo.quantity, 0) as quantity,
               ifnull(ppo.scrap_qty, 0) as scrapQty
        from production_product_main ppm
                 left join production_operation_task pot on ppm.production_operation_task_id = pot.id
                 left join production_order po on pot.production_order_id = po.id
                 left join product_model pm on po.product_model_id = pm.id
                 left join product p on pm.product_id = p.id
                 left join technology_routing_operation tro on pot.technology_routing_operation_id = tro.id
                 left join technology_operation top2 on tro.technology_operation_id = top2.id
                 left join production_product_output ppo on ppo.production_product_main_id = ppm.id
        order by ppm.create_time desc
    </select>
    <select id="listMain" resultType="java.lang.Long">
        select id
        from production_product_main
        where production_operation_task_id in
        <foreach collection="list" item="id" open="(" separator="," close=")">
            #{id}
        </foreach>
    </select>
</mapper>
src/main/resources/mapper/production/ProductionProductOutputMapper.xml
@@ -15,4 +15,47 @@
        <result column="update_user" property="updateUser" />
    </resultMap>
    <select id="listPageProductionProductOutputDto" resultType="com.ruoyi.production.bean.dto.ProductionProductOutputDto">
        select ppo.*,
               ppm.product_no as productNo,
               pm.model
        from production_product_output ppo
                 left join production_product_main ppm on ppo.production_product_main_id = ppm.id
                 left join production_operation_task pot on ppm.production_operation_task_id = pot.id
                 left join production_order po on pot.production_order_id = po.id
                 left join product_model pm on po.product_model_id = pm.id
        <where>
            <if test="c.productNo != null and c.productNo != ''">
                and ppm.product_no like concat('%', #{c.productNo}, '%')
            </if>
            <if test="c.model != null and c.model != ''">
                and pm.model like concat('%', #{c.model}, '%')
            </if>
        </where>
        order by ppo.create_time desc
    </select>
    <select id="selectOutputStats" resultType="com.ruoyi.production.bean.dto.ProductionProductOutputDto">
        select id,
               production_product_main_id as productionProductMainId,
               product_model_id as productModelId,
               quantity,
               scrap_qty as scrapQty,
               create_time as createTime
        from production_product_output
        where create_time &gt;= #{startDate}
          and create_time &lt;= #{endDate}
    </select>
    <select id="selectDailyOutputStats" resultType="java.util.Map">
        select date(create_time) as statDate,
               sum(ifnull(quantity, 0)) as quantity,
               sum(ifnull(scrap_qty, 0)) as scrapQty
        from production_product_output
        where create_time &gt;= #{startDate}
          and create_time &lt;= #{endDate}
        group by date(create_time)
        order by statDate asc
    </select>
</mapper>
src/main/resources/mapper/production/SalesLedgerProductionAccountingMapper.xml
ÎļþÒÑɾ³ý
src/main/resources/mapper/production/SalesLedgerSchedulingMapper.xml
ÎļþÒÑɾ³ý
src/main/resources/mapper/production/SalesLedgerWorkMapper.xml
ÎļþÒÑɾ³ý