zss
12 小时以前 1493f69da9d12415085c9be7937d4f394c5fb154
Merge branch 'jtwy' into dev_New

# Conflicts:
# src/main/java/com/ruoyi/CodeGenerator.java
# src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java
# src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java
# src/main/java/com/ruoyi/sales/controller/SalesLedgerProductController.java
# src/main/java/com/ruoyi/sales/pojo/SalesLedgerProduct.java
已添加13个文件
已修改80个文件
2669 ■■■■ 文件已修改
src/main/java/com/ruoyi/basic/pojo/ProductModel.java 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/service/impl/ProductModelServiceImpl.java 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/common/config/MybatisHandler.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/procurementrecord/controller/ProcurementRecordController.java 16 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/procurementrecord/controller/ProcurementRecordOutController.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/procurementrecord/dto/ProcurementRecordOutAdd.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/procurementrecord/mapper/ProcurementRecordMapper.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/procurementrecord/mapper/ProcurementRecordOutMapper.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/procurementrecord/pojo/ProcurementRecordOut.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/procurementrecord/service/ProcurementRecordOutService.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/procurementrecord/service/ProcurementRecordService.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/procurementrecord/service/impl/ProcurementRecordOutServiceImpl.java 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/procurementrecord/service/impl/ProcurementRecordServiceImpl.java 36 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/procurementrecord/utils/StockUtils.java 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/controller/ProcessRouteController.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/controller/ProcessRouteItemController.java 25 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/controller/ProductBomController.java 87 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/controller/ProductOrderController.java 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/controller/ProductProcessController.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/controller/ProductProcessRouteController.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/controller/ProductProcessRouteItemController.java 188 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/controller/ProductStructureController.java 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/dto/ProcessRouteDto.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/dto/ProcessRouteItemDto.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/dto/ProductBomDto.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/dto/ProductOrderDto.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/dto/ProductProcessRouteItemDto.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/dto/ProductWorkOrderDto.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/dto/ProductionProductInputDto.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/dto/ProductionProductMainDto.java 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/mapper/ProductBomMapper.java 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/mapper/ProductOrderMapper.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/mapper/ProductProcessMapper.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/mapper/ProductProcessRouteMapper.java 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/mapper/ProductStructureMapper.java 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/mapper/ProductWorkOrderMapper.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/pojo/ProcessRoute.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/pojo/ProcessRouteItem.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/pojo/ProductBom.java 72 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/pojo/ProductOrder.java 43 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/pojo/ProductProcess.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/pojo/ProductProcessRoute.java 61 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/pojo/ProductProcessRouteItem.java 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/pojo/ProductStructure.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/pojo/ProductWorkOrder.java 46 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/pojo/ProductionProductMain.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/ProcessRouteItemService.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/ProductBomService.java 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/ProductOrderService.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/ProductProcessRouteItemService.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/ProductProcessRouteService.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/ProductProcessService.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/ProductStructureService.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/ProcessRouteItemServiceImpl.java 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/ProcessRouteServiceImpl.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/ProductBomServiceImpl.java 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/ProductOrderServiceImpl.java 93 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/ProductProcessRouteItemServiceImpl.java 189 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/ProductProcessRouteServiceImpl.java 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/ProductProcessServiceImpl.java 25 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/ProductStructureServiceImpl.java 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java 260 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/controller/PurchaseLedgerController.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/controller/TicketRegistrationController.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/dto/ProductRecordDto.java 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/mapper/ProductRecordMapper.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/service/IProductRecordService.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/service/impl/ProductRecordServiceImpl.java 18 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/quality/service/impl/QualityInspectServiceImpl.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/controller/SalesLedgerProductController.java 27 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/controller/ShipmentApprovalController.java 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/pojo/SalesLedgerProduct.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/InvoiceLedgerServiceImpl.java 155 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java 24 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java 43 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/procurementrecord/ProcurementRecordMapper.xml 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/procurementrecord/ProcurementRecordOutMapper.xml 166 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProcessRouteItemMapper.xml 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProcessRouteMapper.xml 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProductBomMapper.xml 48 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProductOrderMapper.xml 55 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProductProcessMapper.xml 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProductProcessRouteItemMapper.xml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProductProcessRouteMapper.xml 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProductStructureMapper.xml 21 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProductWorkOrderMapper.xml 29 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProductionProductInputMapper.xml 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/production/ProductionProductMainMapper.xml 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/purchase/ProductRecordMapper.xml 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/purchase/PurchaseLedgerMapper.xml 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/sales/InvoiceRegistrationProductMapper.xml 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/pojo/ProductModel.java
@@ -5,6 +5,8 @@
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.math.BigDecimal;
@Data
@TableName("product_model")
public class ProductModel {
@@ -27,9 +29,6 @@
    @Excel(name = "产品名称")
    private String productName;
    @Excel(name = "产品编码")
    private String productCode;
    /**
     * è§„格型号
     */
@@ -51,4 +50,13 @@
    @ApiModelProperty(value = "租户ID")
    @TableField(fill = FieldFill.INSERT)
    private Long tenantId;
    @TableField(exist = false)
    @Excel(name = "入库数量")
    private BigDecimal inboundNum;
    @TableField(exist = false)
    @Excel(name = "出库数量")
    private BigDecimal outboundNum;
    @TableField(exist = false)
    @Excel(name = "剩余库存")
    private BigDecimal stockQuantity;
}
src/main/java/com/ruoyi/basic/service/impl/ProductModelServiceImpl.java
@@ -48,14 +48,7 @@
        if (productModelDto.getId() == null) {
            ProductModel productModel = new ProductModel();
            BeanUtils.copyProperties(productModelDto,productModel);
            productModelMapper.insert(productModel);
            String dateStr = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
            String idStr = String.format("%06d", productModel.getId()); // å…­ä½è¡¥0
            String newProductCode = "BM" + dateStr + idStr;
            // æ›´æ–°æ•°æ®åº“中的productCode
            productModel.setProductCode(newProductCode);
            return productModelMapper.updateById(productModel);
            return productModelMapper.insert(productModel);
        } else {
            return productModelMapper.updateById(productModelDto);
        }
src/main/java/com/ruoyi/common/config/MybatisHandler.java
@@ -18,7 +18,6 @@
            tenantId = SecurityUtils.getLoginUser().getTenantId();
        } catch (Exception ignored) {
        }
        System.out.println("执行插入填充...");
        this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
        this.strictInsertFill(metaObject, "updateTime",  LocalDateTime.class, LocalDateTime.now());
        this.strictInsertFill(metaObject, "createUser", Integer.class, userId);
@@ -36,4 +35,4 @@
        this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now()); // èµ·å§‹ç‰ˆæœ¬ 3.3.0(推荐)
        this.strictUpdateFill(metaObject, "updateUser", Integer.class, userId);
    }
}
}
src/main/java/com/ruoyi/home/service/impl/HomeServiceImpl.java
@@ -514,9 +514,9 @@
        List<ProductOrderDto> productOrderDtoList = new ArrayList<>();
        productOrderList.forEach(productOrder -> {
            ProductOrderDto productOrderDto = productOrderMapper.productMainByOrderId(productOrder);
            if (productOrderDto != null && productOrderDto.getPlanQuantity() != null && productOrderDto.getQuantity() != null) {
                productOrderDto.setCompletionStatus(BigDecimal.valueOf(productOrderDto.getPlanQuantity()-productOrderDto.getQuantity()).divide(BigDecimal.valueOf(productOrderDto.getPlanQuantity()), 2, RoundingMode.HALF_UP));
            }
//            if (productOrderDto != null && productOrderDto.getPlanQuantity() != null && productOrderDto.getQuantity() != null) {
//                productOrderDto.setCompletionStatus((productOrderDto.getPlanQuantity().subtract(productOrderDto.getQuantity())).divide(productOrderDto.getPlanQuantity(), 2, RoundingMode.HALF_UP));
//            }
            productOrderDtoList.add(productOrderDto);
        });
        productionProgressDto.setCompletedOrderDetails(productOrderDtoList);
@@ -525,7 +525,7 @@
        // 2. åˆå§‹åŒ–汇总数据
        int totalCount = productOrderDtoIPage.getRecords().size();
        int completedCount = (int) productOrderDtoIPage.getRecords().stream().map(productOrderDto -> productOrderMapper.productMainByOrderId(productOrderDto)).filter(productOrderDto1 -> productOrderDto1.getQuantity() != null && productOrderDto1.getQuantity() == 0).count();
        int completedCount = (int) productOrderDtoIPage.getRecords().stream().map(productOrderDto -> productOrderMapper.productMainByOrderId(productOrderDto)).filter(productOrderDto1 -> productOrderDto1.getQuantity() != null && productOrderDto1.getQuantity().compareTo(BigDecimal.ZERO) == 0).count();
        // 6. èµ‹å€¼æ±‡æ€»æ•°æ®
        productionProgressDto.setTotalOrderCount(totalCount);
src/main/java/com/ruoyi/procurementrecord/controller/ProcurementRecordController.java
@@ -2,6 +2,7 @@
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.basic.pojo.ProductModel;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.aspectj.lang.annotation.Log;
import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
@@ -132,6 +133,14 @@
        return AjaxResult.success(result);
    }
    @GetMapping("/listPageByProductProduction")
    @Log(title = "生产入库-入库管理-生产入库查询", businessType = BusinessType.OTHER)
    @ApiOperation(value = "入库查询")
    public AjaxResult listPageByProductProduction(Page page, ProcurementPageDto procurementDto) {
        IPage<ProcurementPageDto> result = procurementRecordService.listPageByProductProduction(page, procurementDto);
        return AjaxResult.success(result);
    }
    @GetMapping("/listPageByCustom")
    @Log(title = "自定义入库-入库管理-入库查询", businessType = BusinessType.OTHER)
    @ApiOperation(value = "入库查询")
@@ -226,5 +235,10 @@
        util.exportExcel(response, customStorages, "入库台账");
    }
    @GetMapping("/listPageProductionStock")
    @Log(title = "库存管理-成品库存", businessType = BusinessType.OTHER)
    public AjaxResult listPageProductionStock(Page page) {
        IPage<ProductModel> result = procurementRecordService.listPageProductionStock(page);
        return AjaxResult.success(result);
    }
}
src/main/java/com/ruoyi/procurementrecord/controller/ProcurementRecordOutController.java
@@ -52,6 +52,13 @@
        return AjaxResult.success(result);
    }
    @GetMapping("/listPageBySemiProduct")
    @Log(title = "生产出库-出库台账-出库查询", businessType = BusinessType.OTHER)
    public AjaxResult listPageBySemiProduct(Page page, ProcurementRecordOutPageDto procurementDto) {
        IPage<ProcurementRecordOutPageDto> result = procurementRecordOutService.listPageBySemiProduct(page, procurementDto);
        return AjaxResult.success(result);
    }
    @GetMapping("/listPageByCustom")
    @Log(title = "自定义出库-出库台账-出库查询", businessType = BusinessType.OTHER)
    public AjaxResult listPageByCustom(Page page, ProcurementRecordOutPageDto procurementDto) {
src/main/java/com/ruoyi/procurementrecord/dto/ProcurementRecordOutAdd.java
@@ -17,7 +17,7 @@
    private Integer userId;
    private Integer salesLedgerProductId;
    private Long salesLedgerProductId;
    /**
     * å‡ºåº“类型 1-采购出库 2-销售出库 3-自定义
src/main/java/com/ruoyi/procurementrecord/mapper/ProcurementRecordMapper.java
@@ -44,4 +44,6 @@
    IPage<ProcurementPageDtoCopy> listPagePRS(Page page, @Param("req") ProcurementPageDto procurementDto);
    BigDecimal getSumQuantity(@Param("productModelId") Long productModelId);
    IPage<ProcurementPageDto> listPageByProductProduction(Page page, @Param("req") ProcurementPageDto procurementDto);
}
src/main/java/com/ruoyi/procurementrecord/mapper/ProcurementRecordOutMapper.java
@@ -29,4 +29,8 @@
    IPage<ProcurementRecordOutPageDto> listPageByCustom(Page page,@Param("req") ProcurementRecordOutPageDto procurementDto);
    BigDecimal getSumQuantity(@Param("productModelId") Long productModelId);
    ProcurementRecordOut selectCode(@Param("format") String format);
    IPage<ProcurementRecordOutPageDto> listPageBySemiProduct(Page page,@Param("req") ProcurementRecordOutPageDto procurementDto);
}
src/main/java/com/ruoyi/procurementrecord/pojo/ProcurementRecordOut.java
@@ -22,9 +22,9 @@
    private Integer id;
    /**
     * äº§å“ä¿¡æ¯è¡¨id(自定义入库时为0)
     * äº§å“ä¿¡æ¯è¡¨id(生产扣库存的时候使用)
     */
    private Integer salesLedgerProductId;
    private Long salesLedgerProductId;
    /**
     * å…¥åº“id
src/main/java/com/ruoyi/procurementrecord/service/ProcurementRecordOutService.java
@@ -27,4 +27,6 @@
    IPage<ProcurementRecordOutPageDto> listPageByProduct(Page page, ProcurementRecordOutPageDto procurementDto);
    IPage<ProcurementRecordOutPageDto> listPageByCustom(Page page, ProcurementRecordOutPageDto procurementDto);
    IPage<ProcurementRecordOutPageDto> listPageBySemiProduct(Page page, ProcurementRecordOutPageDto procurementDto);
}
src/main/java/com/ruoyi/procurementrecord/service/ProcurementRecordService.java
@@ -3,6 +3,7 @@
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.basic.pojo.ProductModel;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.procurementrecord.dto.*;
import com.ruoyi.procurementrecord.pojo.CustomStorage;
@@ -58,4 +59,8 @@
    BigDecimal getProcurementAmount(Long salesProductId);
    InventoryInformationDto getReportList();
    IPage<ProductModel> listPageProductionStock(Page page);
    IPage<ProcurementPageDto> listPageByProductProduction(Page page, ProcurementPageDto procurementDto);
}
src/main/java/com/ruoyi/procurementrecord/service/impl/ProcurementRecordOutServiceImpl.java
@@ -69,7 +69,7 @@
        Long aLong = procurementRecordOutMapper.selectCount(procurementRecordLambdaQueryWrapper);
        ProcurementRecordOut.ProcurementRecordOutBuilder procurementRecordOut = ProcurementRecordOut.builder()
                .procurementRecordStorageId(procurementRecordOutAdd.getId())
                .code("LS" + dateFormat.format(now) + String.format("%03d", aLong1 + 1))
                .code("SC" + dateFormat.format(now) + String.format("%03d", aLong1 + 1))
                .salesLedgerProductId(procurementRecordOutAdd.getSalesLedgerProductId())
                .inboundBatches(aLong.equals(0L) ? "第1批次" : "第"+ (aLong + 1) + "批次")
                .inboundNum(new BigDecimal(procurementRecordOutAdd.getQuantity()))
@@ -119,4 +119,9 @@
    public IPage<ProcurementRecordOutPageDto> listPageByCustom(Page page, ProcurementRecordOutPageDto procurementDto) {
        return procurementRecordOutMapper.listPageByCustom(page, procurementDto);
    }
    @Override
    public IPage<ProcurementRecordOutPageDto> listPageBySemiProduct(Page page, ProcurementRecordOutPageDto procurementDto) {
        return procurementRecordOutMapper.listPageBySemiProduct(page, procurementDto);
    }
}
src/main/java/com/ruoyi/procurementrecord/service/impl/ProcurementRecordServiceImpl.java
@@ -2,8 +2,11 @@
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.basic.mapper.ProductModelMapper;
import com.ruoyi.basic.pojo.ProductModel;
import com.ruoyi.common.utils.OrderUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
@@ -17,6 +20,7 @@
import com.ruoyi.procurementrecord.pojo.ProcurementRecordOut;
import com.ruoyi.procurementrecord.pojo.ProcurementRecordStorage;
import com.ruoyi.procurementrecord.service.ProcurementRecordService;
import com.ruoyi.procurementrecord.utils.StockUtils;
import com.ruoyi.project.system.domain.SysUser;
import com.ruoyi.project.system.mapper.SysUserMapper;
import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
@@ -48,6 +52,8 @@
    private final ProcurementRecordOutMapper procurementRecordOutMapper;
    private final SalesLedgerProductMapper salesLedgerProductMapper;
    private final StockUtils stockUtils;
    private final ProductModelMapper productModelMapper;
    @Override
    public List<ProcurementDto> listProcurementBySalesLedgerId(ProcurementDto procurementDto) {
@@ -69,18 +75,18 @@
            List<ProcurementRecordStorage> collect1 = procurementRecordStorages.stream()
                    .filter(procurementRecordStorage -> procurementRecordStorage.getSalesLedgerProductId().equals(dto.getId()))
                    .collect(Collectors.toList());
            // å¦‚果没有相关的入库记录,跳过该条数据
            if(CollectionUtils.isEmpty(collect1)){
                dto.setQuantity0(dto.getQuantity());
                continue;
            }
            // è®¡ç®—已入库数量总和,并设置待入库数量
            BigDecimal totalInboundNum = collect1.stream()
                    .map(ProcurementRecordStorage::getInboundNum)
                    .reduce(BigDecimal.ZERO, BigDecimal::add);
            // å¾…入库数量 = æ€»æ•°é‡ - å·²å…¥åº“数量
            dto.setQuantity0(dto.getQuantity().subtract(totalInboundNum));
        }
@@ -606,7 +612,7 @@
        List<ProcurementRecordOut> recordOutList = procurementRecordOutMapper.selectList(queryWrapper);
        // 2. æŒ‰SalesLedgerProductId分组,统计每个id对应的已出库数量总和-已出库数量
        Map<Integer, BigDecimal> storageIdToTotalOutNumMap = recordOutList.stream()
        Map<Long, BigDecimal> storageIdToTotalOutNumMap = recordOutList.stream()
                .collect(Collectors.groupingBy(
                        ProcurementRecordOut::getSalesLedgerProductId,
                        Collectors.reducing(
@@ -758,7 +764,10 @@
            procurementRecordLambdaQueryWrapper.eq(ProcurementRecordStorage::getSalesLedgerProductId, detail.getId())
                    .eq(ProcurementRecordStorage::getType, procurementDto.getType());
            Long aLong = procurementRecordMapper.selectCount(procurementRecordLambdaQueryWrapper);
            SalesLedgerProduct salesLedgerProduct = salesLedgerProductMapper.selectById(detail.getId());
            if (ObjectUtils.isNull(detail.getProductModelId())){
                detail.setProductModelId(salesLedgerProduct.getProductModelId());
            }
            ProcurementRecordStorage.ProcurementRecordStorageBuilder procurementRecordBuilder = ProcurementRecordStorage.builder()
                    .salesLedgerProductId(detail.getId())
                    .inboundBatches(aLong.equals(0L) ? "第1批次("+ procurementDto.getTypeName() +")" : "第"+ (aLong + 1) + "批次(" + procurementDto.getTypeName() + ")" )
@@ -872,5 +881,22 @@
        }
        return procurementPageDtoCopyIPage;
    }
    @Override
    public IPage<ProductModel> listPageProductionStock(Page page) {
        ProductModel productModel = new ProductModel();
        IPage<ProductModel> iPage = productModelMapper.listPageProductModel(page, productModel);
        iPage.getRecords().forEach(item -> {
            item.setInboundNum(stockUtils.getStockQuantity(item.getId()).get("inboundNum"));
            item.setOutboundNum(stockUtils.getStockQuantity(item.getId()).get("outboundNum"));
            item.setStockQuantity(stockUtils.getStockQuantity(item.getId()).get("stockQuantity"));
        });
        return iPage;
    }
    @Override
    public IPage<ProcurementPageDto> listPageByProductProduction(Page page, ProcurementPageDto procurementDto) {
        IPage<ProcurementPageDto> procurementPageDtoIPage = procurementRecordMapper.listPageByProductProduction(page, procurementDto);
        return procurementPageDtoIPage;
    }
}
src/main/java/com/ruoyi/procurementrecord/utils/StockUtils.java
@@ -6,6 +6,8 @@
import org.springframework.stereotype.Component;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
@Component
@RequiredArgsConstructor
@@ -13,12 +15,18 @@
    private final ProcurementRecordOutMapper procurementRecordOutMapper;
    private final ProcurementRecordMapper procurementRecordMapper;
    // èŽ·å–å•†å“å‰©ä½™åº“å­˜
    public  BigDecimal getStockQuantity(Long productModelId) {
    // èŽ·å–å•†å“å…¥åº“æ•°é‡,出库数量,剩余库存
    public Map<String, BigDecimal> getStockQuantity(Long productModelId) {
        // å…¥åº“数量
        BigDecimal sumQuantity = procurementRecordMapper.getSumQuantity(productModelId);
        // å‡ºåº“数量
        BigDecimal outQuantity = procurementRecordOutMapper.getSumQuantity(productModelId);
        return outQuantity.compareTo(sumQuantity) > 0 ? BigDecimal.ZERO : sumQuantity.subtract(outQuantity);
        // å‰©ä½™åº“å­˜
        BigDecimal stockQuantity = outQuantity.compareTo(sumQuantity) > 0 ? BigDecimal.ZERO : sumQuantity.subtract(outQuantity);
        Map<String, BigDecimal> stockMap = new HashMap<>();
        stockMap.put("inboundNum", sumQuantity);
        stockMap.put("outboundNum", outQuantity);
        stockMap.put("stockQuantity", stockQuantity);
        return stockMap;
    }
}
src/main/java/com/ruoyi/production/controller/ProcessRouteController.java
@@ -1,9 +1,12 @@
package com.ruoyi.production.controller;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.production.dto.ProcessRouteDto;
import com.ruoyi.production.pojo.ProcessRoute;
import com.ruoyi.production.pojo.ProcessRouteItem;
import com.ruoyi.production.service.ProcessRouteItemService;
import com.ruoyi.production.service.ProcessRouteService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
@@ -19,6 +22,9 @@
    @Autowired
    private ProcessRouteService processRouteService;
    @Autowired
    private ProcessRouteItemService processRouteItemService;
    @GetMapping("page")
    @ApiOperation("分页查询")
@@ -39,6 +45,8 @@
    @ApiOperation("删除工艺路线")
    @DeleteMapping("/{ids}")
    public R delete(@PathVariable("ids") Long[] ids) {
        //删除工艺路线详情
        processRouteItemService.remove(Wrappers.<ProcessRouteItem>lambdaQuery().in(ProcessRouteItem::getRouteId,Arrays.asList(ids)));
        return R.ok(processRouteService.removeBatchByIds(Arrays.asList(ids)));
    }
}
src/main/java/com/ruoyi/production/controller/ProcessRouteItemController.java
@@ -1,14 +1,20 @@
package com.ruoyi.production.controller;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.framework.aspectj.lang.annotation.Log;
import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.production.dto.ProcessRouteItemDto;
import com.ruoyi.production.pojo.ProcessRoute;
import com.ruoyi.production.pojo.ProcessRouteItem;
import com.ruoyi.production.service.ProcessRouteItemService;
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;
@@ -26,11 +32,22 @@
        return R.ok(processRouteItemService.listProcessRouteItemDto(processRouteItemDto));
    }
    @PostMapping ()
    @ApiOperation("新增修改")
    public R addOrUpdate(@RequestBody ProcessRouteItemDto processRouteItemDto) {
        processRouteItemService.remove(new QueryWrapper<ProcessRouteItem>().lambda().eq(ProcessRouteItem::getRouteId, processRouteItemDto.getRouteId()));
        return R.ok(processRouteItemService.saveBatch(processRouteItemDto.getProcessRouteItem()));
    public R addOrUpdate(@RequestBody ProcessRouteItem processRouteItem) {
        return R.ok(processRouteItemService.saveOrUpdate(processRouteItem));
    }
    @PostMapping ("/sort")
    @ApiOperation("排序")
    public R sort(@RequestBody ProcessRouteItem processRouteItem) {
        return R.ok(processRouteItemService.sort(processRouteItem));
    }
    @ApiOperation("删除工艺路线明细")
    @DeleteMapping("/batchDelete/{id}")
    @Log(title = "删除", businessType = BusinessType.DELETE)
    public AjaxResult batchDelete(@PathVariable("id") Long id) {
        return AjaxResult.success(processRouteItemService.batchDelete(id));
    }
}
src/main/java/com/ruoyi/production/controller/ProductBomController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,87 @@
package com.ruoyi.production.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.framework.aspectj.lang.annotation.Log;
import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.production.dto.ProductBomDto;
import com.ruoyi.production.dto.ProductProcessDto;
import com.ruoyi.production.pojo.ProcessRoute;
import com.ruoyi.production.pojo.ProductBom;
import com.ruoyi.production.pojo.ProductProcess;
import com.ruoyi.production.service.ProcessRouteService;
import com.ruoyi.production.service.ProductBomService;
import com.ruoyi.production.service.ProductProcessService;
import io.swagger.annotations.ApiModelProperty;
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.List;
/**
 * <p>
 * BOM主表 å‰ç«¯æŽ§åˆ¶å™¨
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-01-15 09:59:27
 */
@RestController
@RequestMapping("/productBom")
public class ProductBomController {
    @Autowired
    private ProductBomService productBomService;
    @Autowired
    private ProcessRouteService processRouteService;
    @GetMapping("/listPage")
    @Log(title = "BOM-分页查询", businessType = BusinessType.OTHER)
    @ApiOperation("BOM-分页查询")
    public AjaxResult listPage(Page page, ProductBomDto productBomDto) {
        IPage<ProductBomDto> listPage = productBomService.listPage(page, productBomDto);
        return AjaxResult.success(listPage);
    }
    @ApiModelProperty("新增BOM")
    @PostMapping("/add")
    @Log(title = "新增", businessType = BusinessType.INSERT)
    public AjaxResult add( @RequestBody ProductBom productBom) {
        return productBomService.add(productBom);
    }
    @ApiOperation("更新BOM")
    @Log(title = "修改", businessType = BusinessType.UPDATE)
    @PutMapping("/update")
    public AjaxResult update(@RequestBody ProductBom productBom) {
        return AjaxResult.success(productBomService.updateById(productBom));
    }
    @ApiOperation("删除BOM")
    @DeleteMapping("/batchDelete")
    @Log(title = "删除", businessType = BusinessType.DELETE)
    public AjaxResult batchDelete(@RequestBody List<Integer> ids) {
        List<ProcessRoute> list = processRouteService.list(Wrappers.<ProcessRoute>lambdaQuery().in(ProcessRoute::getBomId, ids));
        if (list.size()>0){
            return AjaxResult.error("该BOM已经存在对应的工艺路线,无法进行删除");
        }
        if(CollectionUtils.isEmpty(ids)){
            return AjaxResult.error("请选择至少一条数据");
        }
        return AjaxResult.success(productBomService.removeBatchByIds(ids));
    }
    @GetMapping("/getByModel")
    @Log(title = "BOM-根据选择的规格型号id查询存在的bom", businessType = BusinessType.OTHER)
    @ApiOperation("BOM-根据选择的规格型号id查询存在的bom")
    public AjaxResult getByModel(Long productModelId) {
        List<ProductBom> productBoms = productBomService.list(Wrappers.<ProductBom>lambdaQuery().eq(ProductBom::getProductModelId, productModelId));
        return AjaxResult.success(productBoms);
    }
}
src/main/java/com/ruoyi/production/controller/ProductOrderController.java
@@ -1,18 +1,26 @@
package com.ruoyi.production.controller;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.basic.pojo.Customer;
import com.ruoyi.common.utils.poi.ExcelUtil;
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.ProductOrderDto;
import com.ruoyi.production.pojo.ProcessRoute;
import com.ruoyi.production.pojo.ProductOrder;
import com.ruoyi.production.service.ProductOrderService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.*;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
@RequestMapping("productOrder")
@RestController
@Api(tags = "生产订单")
public class ProductOrderController {
    @Autowired
@@ -25,6 +33,35 @@
        return R.ok(productOrderService.pageProductOrder(page, productOrder));
    }
    @ApiOperation("绑定工艺路线")
    @PostMapping("/bindingRoute")
    public R bindingRoute(@RequestBody ProductOrder productOrder) {
        return R.ok(productOrderService.bindingRoute(productOrder));
    }
    @ApiOperation("查询规格型号对应的工艺路线")
    @GetMapping("/listProcessRoute")
    public R listProcessRoute(Long productModelId) {
        return R.ok(productOrderService.listProcessRoute(productModelId));
    }
    /**
     * å¯¼å‡ºç”Ÿäº§è®¢å•
     */
    @Log(title = "生产订单", businessType = BusinessType.EXPORT)
    @PostMapping("/export")
    public void export(HttpServletResponse response, ProductOrderDto productOrderDto) {
        List<ProductOrderDto> list;
        list = productOrderService.pageProductOrder(new Page<>(1, -1), productOrderDto).getRecords();
        ExcelUtil<ProductOrderDto> util = new ExcelUtil<ProductOrderDto>(ProductOrderDto.class);
        util.exportExcel(response, list, "生产订单数据");
    }
    @ApiOperation("查询生产订单对应的BOM")
    @GetMapping("/listProcessBom")
    public R listProcessBom(Long orderId) {
        return R.ok(productOrderService.listProcessBom(orderId));
    }
}
src/main/java/com/ruoyi/production/controller/ProductProcessController.java
@@ -2,6 +2,7 @@
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.basic.pojo.Customer;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.device.pojo.DeviceRepair;
import com.ruoyi.framework.aspectj.lang.annotation.Log;
@@ -18,7 +19,9 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.CollectionUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
@RestController
@@ -66,5 +69,21 @@
    @GetMapping("/list")
    public AjaxResult list() {
        return AjaxResult.success(productProcessService.list());
        }
    /**
     * å¯¼å…¥å·¥åº
     */
    @Log(title = "工序", businessType = BusinessType.IMPORT)
    @PostMapping("/importData")
    public AjaxResult importData(MultipartFile file) throws Exception {
        return productProcessService.importData(file);
    }
    @PostMapping("/downloadTemplate")
    @Log(title = "工序-下载模板", businessType = BusinessType.EXPORT)
    public void downloadTemplate(HttpServletResponse response) {
        ExcelUtil<ProductProcess> util = new ExcelUtil<ProductProcess>(ProductProcess.class);
        util.importTemplateExcel(response, "工序模板");
    }
}
src/main/java/com/ruoyi/production/controller/ProductProcessRouteController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,18 @@
package com.ruoyi.production.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
 * <p>
 *  å‰ç«¯æŽ§åˆ¶å™¨
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-01-15 02:51:09
 */
@RestController
@RequestMapping("/productProcessRoute")
public class ProductProcessRouteController {
}
src/main/java/com/ruoyi/production/controller/ProductProcessRouteItemController.java
@@ -2,11 +2,13 @@
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.production.dto.ProductProcessRouteItemDto;
import com.ruoyi.production.mapper.*;
import com.ruoyi.production.pojo.*;
import com.ruoyi.production.service.ProductProcessRouteItemService;
import com.ruoyi.production.service.ProductProcessRouteService;
import com.ruoyi.production.service.ProductWorkOrderService;
import com.ruoyi.quality.mapper.QualityInspectMapper;
import com.ruoyi.quality.pojo.QualityInspect;
@@ -34,175 +36,43 @@
@Api(tags = "生产工艺路线")
public class ProductProcessRouteItemController {
    private final ProductOrderMapper productOrderMapper;
    private ProductProcessRouteItemService productProcessRouteItemService;
    private ProductWorkOrderService productWorkOrderService;
    private ProductWorkOrderMapper productWorkOrderMapper;
    private SalesLedgerProductMapper salesLedgerProductMapper;
    private ProductionProductMainMapper productionProductMainMapper;
    private ProductionProductInputMapper productionProductInputMapper;
    private ProductionProductOutputMapper productionProductOutputMapper;
    private QualityInspectMapper qualityInspectMapper;
    private SalesLedgerProductionAccountingMapper salesLedgerProductionAccountingMapper;
    private ProductProcessRouteService productProcessRouteService;
    @GetMapping("list")
    @ApiOperation("根据Id查询工艺项目")
    @ApiOperation("根据Id查询工艺路线子表")
    public R list(Long orderId) {
        return R.ok(productProcessRouteItemService.listItem(orderId));
    }
    @PostMapping("/updateRouteItem")
    @ApiOperation("批量新增修改")
    @Transactional(rollbackFor = Exception.class)
    public R addOrUpdate(@RequestBody ProductProcessRouteItemDto processRouteItemDto) {
        ProductOrder productOrder = productOrderMapper.selectById(processRouteItemDto.getRouteId());
        if (productOrder == null) {
            return R.fail("未找到ID为[" + processRouteItemDto.getRouteId() + "]的产品订单");
        }
        SalesLedgerProduct salesLedgerProduct = salesLedgerProductMapper.selectOne(new LambdaQueryWrapper<SalesLedgerProduct>()
                .eq(SalesLedgerProduct::getSalesLedgerId, productOrder.getSalesLedgerId()));
        if (salesLedgerProduct == null) {
            return R.fail("未找到销售台账ID为[" + productOrder.getSalesLedgerId() + "]的台账产品");
        }
        List<ProductProcessRouteItem> items = processRouteItemDto.getProcessRouteItem();
        if (CollectionUtils.isEmpty(items)) {
            return R.ok();
        }
        Map<Boolean, List<ProductProcessRouteItem>> partitioned = items.stream()
                .collect(Collectors.partitioningBy(
                        item -> item.getId() != null && item.getId() > 0
                ));
        List<ProductProcessRouteItem> toUpdate = partitioned.get(true);
        List<ProductProcessRouteItem> toInsert = partitioned.get(false);
        // æ‰¹é‡å¤„理
        boolean result = true;
        if (!toInsert.isEmpty()) {
            result = productProcessRouteItemService.saveBatch(toInsert);
            if (result) {
                // ç”Ÿæˆå·¥å•号
                String datePrefix = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
                // æŸ¥è¯¢ä»Šæ—¥æœ€å¤§å·¥å•号
                QueryWrapper<ProductWorkOrder> queryWrapper = new QueryWrapper<>();
                queryWrapper.likeRight("work_order_no", datePrefix)
                        .select("MAX(work_order_no) as maxNo");
                List<Map<String, Object>> maxNoList = productWorkOrderMapper.selectMaps(queryWrapper);
                String maxWorkOrderNo = null;
                if (!maxNoList.isEmpty() && maxNoList.get(0) != null && maxNoList.get(0).get("maxNo") != null) {
                    maxWorkOrderNo = maxNoList.get(0).get("maxNo").toString();
                }
                int startSequence = 1;
                if (maxWorkOrderNo != null && maxWorkOrderNo.startsWith(datePrefix)) {
                    try {
                        String seqStr = maxWorkOrderNo.substring(datePrefix.length());
                        startSequence = Integer.parseInt(seqStr) + 1;
                    } catch (NumberFormatException e) {
                        startSequence = 1;
                    }
                }
                // æ‰¹é‡ç”Ÿæˆå·¥å•
                List<ProductWorkOrder> workOrders = new ArrayList<>();
                for (int i = 0; i < toInsert.size(); i++) {
                    ProductProcessRouteItem item = toInsert.get(i);
                    String workOrderNoStr = String.format("%s%03d", datePrefix, startSequence + i);
                    ProductWorkOrder workOrder = new ProductWorkOrder();
                    workOrder.setProductProcessRouteItemId(item.getId());
                    workOrder.setProductOrderId(item.getRouteId());
                    workOrder.setWorkOrderNo(workOrderNoStr);
                    workOrder.setPlanQuantity(salesLedgerProduct.getQuantity());
                    workOrder.setStatus(1);
                    workOrders.add(workOrder);
                }
                result = productWorkOrderService.saveBatch(workOrders);
            }
        }
        if (!toUpdate.isEmpty()) {
            result = productProcessRouteItemService.updateBatchById(toUpdate) && result;
        }
        return R.ok(result);
    @GetMapping("listMain")
    @ApiOperation("根据Id查询工艺路线主表")
    public R listMain(Long orderId) {
        return R.ok(productProcessRouteService.listMain(orderId));
    }
    @DeleteMapping("/deleteRouteItem")
    @PostMapping("/addRouteItem")
    @ApiOperation("新增生产订单的工艺路线详情")
    public R addRouteItem(@RequestBody ProductProcessRouteItem productProcessRouteItem) {
        return productProcessRouteItemService.addRouteItem(productProcessRouteItem);
    }
    @PostMapping("/updateRouteItem")
    @ApiOperation("修改生产订单的工艺路线详情")
    public R updateRouteItem(@RequestBody ProductProcessRouteItem productProcessRouteItem) {
        return R.ok(productProcessRouteItemService.updateById(productProcessRouteItem));
    }
    @DeleteMapping("/deleteRouteItem/{id}")
    @ApiOperation("删除生产工艺路线")
    @Transactional(rollbackFor = Exception.class)
    public R deleteRouteItem(@RequestBody ProductProcessRouteItemDto processRouteItemDto) {
    public R deleteRouteItem(@PathVariable("id") Long id) {
        return productProcessRouteItemService.deleteRouteItem(id);
    }
        if (processRouteItemDto == null || processRouteItemDto.getId() == null) {
            return R.fail("删除失败:工艺路线项ID不能为空");
        }
        Long routeItemId = processRouteItemDto.getId();
        try {
            // æŸ¥è¯¢å·¥å•
            ProductWorkOrder productWorkOrder = productWorkOrderMapper.selectOne(
                    new LambdaQueryWrapper<ProductWorkOrder>()
                            .eq(ProductWorkOrder::getProductProcessRouteItemId, routeItemId)
                            .last("LIMIT 1")
            );
            if (productWorkOrder == null) {
                return R.fail("删除失败:未找到关联的生产工单");
            }
            Long workOrderId = productWorkOrder.getId();
            Long productOrderId = productWorkOrder.getProductOrderId();
            // æŸ¥è¯¢ç”Ÿäº§ä¸»è¡¨
            List<ProductionProductMain> productionProductMains = productionProductMainMapper.selectList(
                    new LambdaQueryWrapper<ProductionProductMain>()
                            .eq(ProductionProductMain::getWorkOrderId, workOrderId)
            );
            if (!productionProductMains.isEmpty()) {
                // æ‰¹é‡åˆ é™¤å­è¡¨
                for (ProductionProductMain main : productionProductMains) {
                    Long mainId = main.getId();
                    // åˆ é™¤æŠ•å…¥
                    productionProductInputMapper.delete(new LambdaQueryWrapper<ProductionProductInput>()
                            .eq(ProductionProductInput::getProductMainId, mainId));
                    // åˆ é™¤äº§å‡º
                    productionProductOutputMapper.delete(new LambdaQueryWrapper<ProductionProductOutput>()
                            .eq(ProductionProductOutput::getProductMainId, mainId));
                    // åˆ é™¤è´¨æ£€
                    qualityInspectMapper.delete(new LambdaQueryWrapper<QualityInspect>()
                            .eq(QualityInspect::getProductMainId, mainId));
                }
            }
            //  åˆ é™¤æŠ¥å·¥ï¼ˆç”Ÿäº§ä¸»è¡¨ï¼‰
            productionProductMainMapper.delete(new LambdaQueryWrapper<ProductionProductMain>()
                    .eq(ProductionProductMain::getWorkOrderId, workOrderId));
            // æŸ¥è¯¢è®¢å• + åˆ é™¤æ ¸ç®—
            ProductOrder productOrder = productOrderMapper.selectById(productOrderId);
            if (productOrder != null && productOrder.getSalesLedgerId() != null) {
                salesLedgerProductionAccountingMapper.delete(new LambdaQueryWrapper<SalesLedgerProductionAccounting>()
                        .eq(SalesLedgerProductionAccounting::getSalesLedgerId, productOrder.getSalesLedgerId()));
            }
            // åˆ é™¤å…³è”工单
            productWorkOrderMapper.delete(new LambdaQueryWrapper<ProductWorkOrder>()
                    .eq(ProductWorkOrder::getProductProcessRouteItemId, routeItemId));
            // åˆ é™¤ä¸»è¡¨æ•°æ®
            boolean removeFlag = productProcessRouteItemService.removeById(routeItemId);
            if (!removeFlag) {
                return R.fail("删除失败:工艺路线项主表数据不存在");
            }
            return R.ok();
        } catch (Exception e) {
            return R.fail("删除生产工艺路线失败:" + e.getMessage());
        }
    @PostMapping ("/sortRouteItem")
    @ApiOperation("排序")
    public R sortRouteItem(@RequestBody ProductProcessRouteItem productProcessRouteItem) {
        return R.ok(productProcessRouteItemService.sortRouteItem(productProcessRouteItem));
    }
}
src/main/java/com/ruoyi/production/controller/ProductStructureController.java
@@ -1,7 +1,12 @@
package com.ruoyi.production.controller;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.framework.aspectj.lang.annotation.Log;
import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.production.dto.ProductProcessDto;
import com.ruoyi.production.dto.ProductStructureDto;
import com.ruoyi.production.pojo.ProductStructure;
import com.ruoyi.production.service.ProductStructureService;
@@ -15,21 +20,21 @@
@RequestMapping("productStructure")
@RestController
@Api(tags = "产品结构")
@Api(tags = "BOM")
public class ProductStructureController {
    @Autowired
    private ProductStructureService productStructureService;
    @ApiOperation("根据productId查询")
    @GetMapping("/listByproductModelId/{productModelId}")
    public R listByproductModelId( @PathVariable("productModelId") Long productModelId){
        return R.ok(productStructureService.listByproductModelId( productModelId));
    }
    @ApiOperation("新增产品结构")
    @ApiOperation("新增BOM")
    @PostMapping()
    public R addOrUpdate(@RequestBody ProductStructureDto productStructureDto){
        return R.ok(productStructureService.addProductStructureDto(productStructureDto));
    }
    @ApiOperation("BOM查看详情")
    @GetMapping("/listBybomId/{bomId}")
    public R listBybomId( @PathVariable("bomId") Long bomId){
        return R.ok(productStructureService.listBybomId(bomId));
    }
}
src/main/java/com/ruoyi/production/dto/ProcessRouteDto.java
@@ -13,4 +13,6 @@
    @ApiModelProperty("规格")
    private String model;
    private String bomNo;
}
src/main/java/com/ruoyi/production/dto/ProcessRouteItemDto.java
@@ -27,6 +27,5 @@
    private Long productId;
    private List<ProcessRouteItem> processRouteItem;
    private String model;
}
src/main/java/com/ruoyi/production/dto/ProductBomDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,18 @@
package com.ruoyi.production.dto;
import com.ruoyi.production.pojo.ProductBom;
import lombok.Data;
import java.util.List;
//分页查询回显数据
@Data
public class ProductBomDto extends ProductBom {
    //产品名称
    private String productName;
    //产品规格型号
    private String productModelName;
}
src/main/java/com/ruoyi/production/dto/ProductOrderDto.java
@@ -1,5 +1,7 @@
package com.ruoyi.production.dto;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.ruoyi.framework.aspectj.lang.annotation.Excel;
import com.ruoyi.production.pojo.ProductOrder;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@@ -7,32 +9,38 @@
import java.math.BigDecimal;
@Data
@ExcelIgnoreUnannotated
public class ProductOrderDto extends ProductOrder {
    @ApiModelProperty(value = "销售合同号")
    @Excel(name = "销售合同号")
    private String salesContractNo;
    @ApiModelProperty(value = "项目名")
    @Excel(name = "项目名")
    private String projectName;
    @ApiModelProperty(value = "客户名")
    @ApiModelProperty(value = "客户名称")
    @Excel(name = "客户名称")
    private String customerName;
    @ApiModelProperty(value = "产品名称")
    @Excel(name = "产品名称")
    private String productCategory;
    @ApiModelProperty(value = "规格")
    @Excel(name = "规格")
    private String specificationModel;
    @ApiModelProperty(value = "计划数量")
    private Integer planQuantity;
    @ApiModelProperty(value = "数量")
    private Integer Quantity;
    @ApiModelProperty(value = "工单号")
    private String workOrderNo;
    @ApiModelProperty(value = "是否报工")
    private Integer reportWork;
    @ApiModelProperty(value = "工单状态")
    private Integer status;
    @ApiModelProperty(value = "订单完成度")
    @ApiModelProperty(value = "工艺路线编号")
    @Excel(name = "工艺路线编号")
    private String processRouteCode;
    @ApiModelProperty(value = "完成状态")
    @Excel(name = "完成状态")
    private BigDecimal completionStatus;
    @ApiModelProperty(value = "BOM编号")
    @Excel(name = "BOM编号")
    private String bomNo;
}
src/main/java/com/ruoyi/production/dto/ProductProcessRouteItemDto.java
@@ -23,7 +23,5 @@
    private String productName;
    private List<ProductProcessRouteItem> processRouteItem;
    private String model;
}
src/main/java/com/ruoyi/production/dto/ProductWorkOrderDto.java
@@ -1,9 +1,12 @@
package com.ruoyi.production.dto;
import com.ruoyi.framework.aspectj.lang.annotation.Excel;
import com.ruoyi.production.pojo.ProductWorkOrder;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.math.BigDecimal;
@EqualsAndHashCode(callSuper = true)
@Data
@@ -29,4 +32,7 @@
    //生产订单号
    @ApiModelProperty(value = "生产订单号")
    private String productOrderNpsNo;
    @ApiModelProperty(value = "完成进度")
    private BigDecimal completionStatus;
}
src/main/java/com/ruoyi/production/dto/ProductionProductInputDto.java
@@ -11,4 +11,10 @@
    @ApiModelProperty(value = "产品型号")
    private String model;
    @ApiModelProperty(value = "产品名称")
    private String productName;
    @ApiModelProperty(value = "单位")
    private String unit;
}
src/main/java/com/ruoyi/production/dto/ProductionProductMainDto.java
@@ -21,9 +21,15 @@
    @ApiModelProperty(value = "报工数量")
    private BigDecimal quantity;
    @ApiModelProperty(value = "是否报工")
    private boolean reportWork;
    //产品名称
    private String productName;
    @ApiModelProperty(value = "报工id")
    private Long productMainId;
    //产品规格型号
    private String productModelName;
    //单位
    private String unit;
    //销售合同号
    private String salesContractNo;
}
src/main/java/com/ruoyi/production/mapper/ProductBomMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,26 @@
package com.ruoyi.production.mapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.production.dto.ProductBomDto;
import com.ruoyi.production.dto.ProductProcessDto;
import com.ruoyi.production.pojo.ProductBom;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
/**
 * <p>
 * BOM主表 Mapper æŽ¥å£
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-01-15 09:59:27
 */
@Mapper
public interface ProductBomMapper extends BaseMapper<ProductBom> {
    IPage<ProductBomDto> listPage(Page page, @Param("c") ProductBomDto productBomDto);
    ProductBomDto getById(@Param("bomId") Long bomId);
}
src/main/java/com/ruoyi/production/mapper/ProductOrderMapper.java
@@ -3,10 +3,15 @@
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.dto.ProductBomDto;
import com.ruoyi.production.dto.ProductOrderDto;
import com.ruoyi.production.dto.ProductStructureDto;
import com.ruoyi.production.pojo.ProcessRoute;
import com.ruoyi.production.pojo.ProductOrder;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@Mapper
public interface ProductOrderMapper extends BaseMapper<ProductOrder> {
@@ -16,4 +21,8 @@
     * æ ¹æ®è®¢å•ID查询工单报工
     */
     ProductOrderDto productMainByOrderId(@Param("c") ProductOrder productOrder);
    List<ProcessRoute> listProcessRoute(@Param("productModelId") Long productModelId);
    List<ProductStructureDto> listProcessBom(@Param("orderId") Long orderId);
}
src/main/java/com/ruoyi/production/mapper/ProductProcessMapper.java
@@ -5,8 +5,10 @@
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.production.dto.ProductProcessDto;
import com.ruoyi.production.pojo.ProductProcess;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
@Mapper
public interface ProductProcessMapper extends BaseMapper<ProductProcess> {
    IPage<ProductProcessDto> listPage(Page page,@Param("productProcessDto") ProductProcessDto productProcessDto);
}
src/main/java/com/ruoyi/production/mapper/ProductProcessRouteMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,21 @@
package com.ruoyi.production.mapper;
import com.ruoyi.production.dto.ProcessRouteDto;
import com.ruoyi.production.pojo.ProductProcessRoute;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
/**
 * <p>
 *  Mapper æŽ¥å£
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-01-15 02:51:09
 */
@Mapper
public interface ProductProcessRouteMapper extends BaseMapper<ProductProcessRoute> {
    ProcessRouteDto listMain(@Param("orderId") Long orderId);
}
src/main/java/com/ruoyi/production/mapper/ProductStructureMapper.java
@@ -12,5 +12,8 @@
@Mapper
public interface ProductStructureMapper  extends BaseMapper<ProductStructure> {
    List<ProductStructureDto> listByproductModelId(@Param("productModelId") Long productModelId);
    List<ProductStructureDto> listBybomId(@Param("bomId") Long bomId);
    List<ProductStructureDto> listBybomAndProcess(@Param("bomId") Long bomId, @Param("processId") Long processId);
}
src/main/java/com/ruoyi/production/mapper/ProductWorkOrderMapper.java
@@ -17,14 +17,5 @@
    IPage<ProductWorkOrderDto> pageProductWorkOrder(Page<ProductWorkOrderDto> page, @Param("c") ProductWorkOrderDto productWorkOrder);
    int updatePlanQuantity(Map<String, Object> params);
    /**
     * å›žæ»šå·¥å•计划数量:从production_product_output取quantity加回plan_quantity
     * @param productMainId
     * @return
     */
    int rollbackPlanQuantity(@Param("productMainId") Long productMainId);
    List<ProductWorkOrderDto> selectProductWorkOrderDtoList();
}
src/main/java/com/ruoyi/production/pojo/ProcessRoute.java
@@ -3,6 +3,7 @@
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@@ -10,12 +11,14 @@
@TableName("process_route")
@Data
@ApiModel(value = "processRoute", description = "工艺路线主表")
public class ProcessRoute {
    @ApiModelProperty(value = "序号")
    private Long id;
    @ApiModelProperty(value = "产品ID")
    //product_model
    private Long productModelId;
    @ApiModelProperty(value = "描述")
@@ -30,9 +33,12 @@
    private LocalDateTime createTime;
    @ApiModelProperty(value = "更新时间")
    @TableField(fill = FieldFill.UPDATE)
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;
    @ApiModelProperty(value = "工艺路线编码")
    private String processRouteCode;
    @ApiModelProperty(value = "BOM的ID")
    private Long bomId;
}
src/main/java/com/ruoyi/production/pojo/ProcessRouteItem.java
@@ -1,6 +1,7 @@
package com.ruoyi.production.pojo;
import com.baomidou.mybatisplus.annotation.*;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@@ -8,6 +9,7 @@
@Data
@TableName("process_route_item")
@ApiModel(value = "processRouteItem", description = "工艺路线子表")
public class ProcessRouteItem {
    @TableId(type = IdType.AUTO)
@@ -32,5 +34,8 @@
    @TableField(fill = FieldFill.UPDATE)
    private LocalDateTime updateTime;
    @ApiModelProperty(value ="拖动排序")
    private Integer dragSort;
}
src/main/java/com/ruoyi/production/pojo/ProductBom.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,72 @@
package com.ruoyi.production.pojo;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.time.LocalDateTime;
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;
/**
 * <p>
 * BOM主表
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-01-15 09:59:27
 */
@Getter
@Setter
@TableName("product_bom")
@ApiModel(value = "ProductBom对象", description = "BOM主表")
public class ProductBom implements Serializable {
    private static final long serialVersionUID = 1L;
    @TableId(value = "id", type = IdType.AUTO)
    private Integer id;
    @ApiModelProperty("bom编号")
    private String bomNo;
    @ApiModelProperty("产品规格id")
    private Long productModelId;
    @ApiModelProperty("备注")
    private String remark;
    @ApiModelProperty("版本号")
    private String version;
    @ApiModelProperty("创建时间")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;
    @ApiModelProperty("更新时间")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;
    @ApiModelProperty("创建者")
    @TableField(fill = FieldFill.INSERT)
    private Long createUser;
    @ApiModelProperty("更新者")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Long updateUser;
    @ApiModelProperty("租户ID")
    @TableField(fill = FieldFill.INSERT)
    private Long tenantId;
}
src/main/java/com/ruoyi/production/pojo/ProductOrder.java
@@ -1,11 +1,15 @@
package com.ruoyi.production.pojo;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.framework.aspectj.lang.annotation.Excel;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serializable;
import java.math.BigDecimal;
import java.time.LocalDateTime;
@Data
@@ -24,7 +28,7 @@
    private Long salesLedgerId;
    /**
     * é”€å”®å°è´¦äº§å“id
     * é”€å”®å°è´¦äº§å“id(sales_ledger_product)
     */
    @ApiModelProperty(value = "销售台账产品id")
    private Long productModelId;
@@ -39,6 +43,7 @@
     * ç”Ÿäº§è®¢å•号
     */
    @ApiModelProperty(value = "生产订单号")
    @Excel(name = "生产订单号")
    private String npsNo;
    /**
@@ -51,11 +56,45 @@
    //创建时间
    @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.UPDATE)
    @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 = "需求数量")
    @Excel(name = "需求数量")
    private BigDecimal quantity;
    /**
     * å®Œæˆæ•°é‡
     */
    @ApiModelProperty(value = "完成数量")
    @Excel(name = "完成数量")
    private BigDecimal completeQuantity;
    @Excel(name = "开始时间")
    @ApiModelProperty(value = "开始时间")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime startTime;
    @ApiModelProperty(value = "结束时间")
    @Excel(name = "结束时间")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime endTime;
}
src/main/java/com/ruoyi/production/pojo/ProductProcess.java
@@ -1,7 +1,12 @@
package com.ruoyi.production.pojo;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.framework.aspectj.lang.annotation.Excel;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serializable;
import java.math.BigDecimal;
@@ -9,6 +14,8 @@
@TableName("product_process")
@Data
@ExcelIgnoreUnannotated
@ApiModel(value = "productProcess", description = "工序表")
public class ProductProcess implements Serializable {
    private static final long serialVersionUID = 1L;
@@ -19,34 +26,42 @@
    /**
     * å·¥åºåç§°
     */
    @Excel(name = "工序名称")
    private String name;
    /**
     * å·¥åºç¼–号
     */
    @Excel(name = "工序编号")
    private String no;
    /**
     * å¤‡æ³¨
     */
    @Excel(name = "备注")
    private String remark;
    /**
     * å·¥èµ„定额
     */
    @Excel(name = "工资定额")
    private BigDecimal salaryQuota;
    /**
     * åˆ›å»ºæ—¶é—´
     */
    @TableField(fill = FieldFill.INSERT)
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime createTime;
    /**
     * ä¿®æ”¹æ—¶é—´
     */
    @TableField(fill = FieldFill.UPDATE)
    @TableField(fill = FieldFill.INSERT_UPDATE)
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime updateTime;
    /**
src/main/java/com/ruoyi/production/pojo/ProductProcessRoute.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,61 @@
package com.ruoyi.production.pojo;
import com.baomidou.mybatisplus.annotation.FieldFill;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.time.LocalDateTime;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
import lombok.Setter;
/**
 * <p>
 *
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-01-15 02:51:09
 */
@Getter
@Setter
@TableName("product_process_route")
@ApiModel(value = "ProductProcessRoute对象", description = "")
public class ProductProcessRoute implements Serializable {
    private static final long serialVersionUID = 1L;
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    @ApiModelProperty("产品id")
    //product_model
    private Long productModelId;
    @ApiModelProperty("描述")
    private String description;
    @ApiModelProperty("租户id")
    @TableField(fill = FieldFill.INSERT)
    private Long tenantId;
    @ApiModelProperty("录入时间")
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;
    @ApiModelProperty("更新时间")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;
    @ApiModelProperty("关联bom的id")
    private Long bomId;
    @ApiModelProperty("工艺路线编码")
    private String processRouteCode;
    @ApiModelProperty("生产订单的id")
    private Long productOrderId;
}
src/main/java/com/ruoyi/production/pojo/ProductProcessRouteItem.java
@@ -14,7 +14,10 @@
    private Long id;
    @ApiModelProperty(value = "生产订单id(product_order_id)")
    private Long routeId;
    private Long productOrderId;
    @ApiModelProperty(value = "生产订单的工艺路线id(product_process_route)")
    private Long productRouteId;
    @ApiModelProperty(value = "工序id")
    private Long processId;
src/main/java/com/ruoyi/production/pojo/ProductStructure.java
@@ -1,12 +1,14 @@
package com.ruoyi.production.pojo;
import com.baomidou.mybatisplus.annotation.*;
import io.swagger.annotations.ApiModel;
import lombok.Data;
import java.math.BigDecimal;
@TableName("product_structure")
@Data
@ApiModel(value = "ProductStructure", description = "BOM子表")
public class ProductStructure {
    private static final long serialVersionUID = 1L;
@@ -40,20 +42,15 @@
    private String unit;
    /**
     * çˆ¶çº§id
     */
    private Long parentId;
    /**
     * ç›˜æ•°é‡
     */
    private BigDecimal diskQuantity;
    /**
     * ç§Ÿæˆ·ID
     */
    @TableField(fill = FieldFill.INSERT)
    private Long tenantId;
    /**
     * å…³è”BOMid
     */
    private Long bomId;
}
src/main/java/com/ruoyi/production/pojo/ProductWorkOrder.java
@@ -1,8 +1,11 @@
package com.ruoyi.production.pojo;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.ruoyi.framework.aspectj.lang.annotation.Excel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serializable;
import java.math.BigDecimal;
@@ -42,13 +45,17 @@
     */
    @ApiModelProperty(value = "创建时间")
    @TableField(fill = FieldFill.INSERT)
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime createTime;
    /**
     * ä¿®æ”¹æ—¶é—´
     */
    @ApiModelProperty(value = "修改时间")
    @TableField(fill = FieldFill.UPDATE)
    @TableField(fill = FieldFill.INSERT_UPDATE)
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime updateTime;
    /**
@@ -58,9 +65,9 @@
    private String workOrderNo;
    /**
     * çŠ¶æ€  1 å¾…确认  2 å¾…生产 3生产中 4已生产
     * çŠ¶æ€  1 å¾…确认  2 å¾…生产 3生产中 4已完成
     */
    @ApiModelProperty(value = "状态  1 å¾…确认  2 å¾…生产 3生产中 4已生产")
    @ApiModelProperty(value = "状态  1 å¾…确认  2 å¾…生产 3生产中 4已完成")
    private Integer status;
    /**
@@ -74,48 +81,45 @@
     * è®¡åˆ’开始时间
     */
    @ApiModelProperty(value = "计划开始时间")
    @JsonFormat(pattern = "yyyy-MM-dd")
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private LocalDate planStartTime;
    /**
     * è®¡åˆ’结束时间
     */
    @ApiModelProperty(value = "计划结束时间")
    @JsonFormat(pattern = "yyyy-MM-dd")
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private LocalDate planEndTime;
    /**
     * å®žé™…开始时间
     */
    @ApiModelProperty(value = "实际开始时间")
    @JsonFormat(pattern = "yyyy-MM-dd")
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private LocalDate actualStartTime;
    /**
     * å®žé™…结束时间
     */
    @ApiModelProperty(value = "实际结束时间")
    @JsonFormat(pattern = "yyyy-MM-dd")
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private LocalDate actualEndTime;
    /**
     * æ˜¯å¦æŠ¥å·¥
     * éœ€æ±‚量
     */
    @ApiModelProperty(value = "是否报工")
    private boolean reportWork;
    /**
     * è®¡åˆ’数量
     */
    @ApiModelProperty(value = "计划数量")
    @ApiModelProperty(value = "需求数量")
    private BigDecimal planQuantity;
    /**
     * å®žé™…数量
     * å®Œæˆæ•°é‡
     */
    @ApiModelProperty(value = "数量")
    private BigDecimal quantity;
    @ApiModelProperty(value = "完成数量")
    private BigDecimal completeQuantity;
    /**
     * æŠ¥å·¥id
     */
    @ApiModelProperty(value = "报工id")
    private Long productMainId;
}
}
src/main/java/com/ruoyi/production/pojo/ProductionProductMain.java
@@ -1,8 +1,10 @@
package com.ruoyi.production.pojo;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
@@ -33,10 +35,14 @@
    @ApiModelProperty(value = "创建时间")
    @TableField(fill = FieldFill.INSERT)
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime createTime;
    @ApiModelProperty(value = "更新时间")
    @TableField(fill = FieldFill.UPDATE)
    @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")
src/main/java/com/ruoyi/production/service/ProcessRouteItemService.java
@@ -11,4 +11,8 @@
public interface ProcessRouteItemService extends IService<ProcessRouteItem> {
    List<ProcessRouteItemDto> listProcessRouteItemDto( ProcessRouteItemDto processRouteItemDto);
    int sort(ProcessRouteItem processRouteItem);
    String batchDelete(Long id);
}
src/main/java/com/ruoyi/production/service/ProductBomService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,24 @@
package com.ruoyi.production.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.production.dto.ProductBomDto;
import com.ruoyi.production.dto.ProductProcessDto;
import com.ruoyi.production.pojo.ProductBom;
import com.baomidou.mybatisplus.extension.service.IService;
/**
 * <p>
 * BOM主表 æœåŠ¡ç±»
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-01-15 09:59:27
 */
public interface ProductBomService extends IService<ProductBom> {
    IPage<ProductBomDto> listPage(Page page, ProductBomDto productBomDto);
    AjaxResult add(ProductBom productBom);
}
src/main/java/com/ruoyi/production/service/ProductOrderService.java
@@ -3,11 +3,22 @@
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.dto.ProductBomDto;
import com.ruoyi.production.dto.ProductOrderDto;
import com.ruoyi.production.dto.ProductStructureDto;
import com.ruoyi.production.pojo.ProcessRoute;
import com.ruoyi.production.pojo.ProductOrder;
import java.util.List;
public interface ProductOrderService extends IService<ProductOrder> {
    IPage<ProductOrderDto> pageProductOrder(Page page, ProductOrderDto productOrder);
    int bindingRoute(ProductOrder productOrder);
    List<ProcessRoute> listProcessRoute(Long productModelId);
    List<ProductStructureDto> listProcessBom(Long orderId);
}
src/main/java/com/ruoyi/production/service/ProductProcessRouteItemService.java
@@ -1,6 +1,7 @@
package com.ruoyi.production.service;
import com.baomidou.mybatisplus.extension.service.IService;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.production.dto.ProductProcessRouteItemDto;
import com.ruoyi.production.pojo.ProductProcessRouteItem;
@@ -8,4 +9,10 @@
public interface ProductProcessRouteItemService extends IService<ProductProcessRouteItem> {
    List<ProductProcessRouteItemDto> listItem(Long orderId);
    R deleteRouteItem(Long id);
    R addRouteItem(ProductProcessRouteItem productProcessRouteItem);
    int sortRouteItem(ProductProcessRouteItem productProcessRouteItem);
}
src/main/java/com/ruoyi/production/service/ProductProcessRouteService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,18 @@
package com.ruoyi.production.service;
import com.ruoyi.production.dto.ProcessRouteDto;
import com.ruoyi.production.pojo.ProductProcessRoute;
import com.baomidou.mybatisplus.extension.service.IService;
/**
 * <p>
 *  æœåŠ¡ç±»
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-01-15 02:51:09
 */
public interface ProductProcessRouteService extends IService<ProductProcessRoute> {
    ProcessRouteDto listMain(Long orderId);
}
src/main/java/com/ruoyi/production/service/ProductProcessService.java
@@ -8,6 +8,7 @@
import com.ruoyi.production.dto.*;
import com.ruoyi.production.pojo.ProductProcess;
import com.ruoyi.production.pojo.SalesLedgerScheduling;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
@@ -20,4 +21,6 @@
    IPage<ProductProcessDto> listPage(Page page, ProductProcessDto productProcessDto);
    AjaxResult add(ProductProcessDto productProcessDto);
    AjaxResult importData(MultipartFile file);
}
src/main/java/com/ruoyi/production/service/ProductStructureService.java
@@ -10,8 +10,8 @@
public interface ProductStructureService extends IService<ProductStructure> {
    ProductModelDto listByproductModelId(Long productId);
    Boolean addProductStructureDto(ProductStructureDto productStructureDto);
    List<ProductStructureDto> listBybomId(Long bomId);
}
src/main/java/com/ruoyi/production/service/impl/ProcessRouteItemServiceImpl.java
@@ -1,6 +1,7 @@
package com.ruoyi.production.service.impl;
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.dto.ProcessRouteItemDto;
@@ -10,11 +11,13 @@
import lombok.AllArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
@AllArgsConstructor
@Transactional(rollbackFor = Exception.class)
public class ProcessRouteItemServiceImpl extends ServiceImpl<ProcessRouteItemMapper, ProcessRouteItem> implements ProcessRouteItemService {
    @Autowired
@@ -24,4 +27,64 @@
    public List<ProcessRouteItemDto> listProcessRouteItemDto(ProcessRouteItemDto processRouteItemDto) {
        return processRouteItemMapper.listProcessRouteItemDto( processRouteItemDto);
    }
    //排序
    @Override
    public int sort(ProcessRouteItem processRouteItem) {
        //查询被改动的这条数据
        ProcessRouteItem oldProcessRouteItem = processRouteItemMapper.selectById(processRouteItem.getId());
        //查询该工艺路线的所有工序并按照顺序排序
        List<ProcessRouteItem> processRouteItems = processRouteItemMapper.selectList(Wrappers.<ProcessRouteItem>lambdaQuery()
                .eq(ProcessRouteItem::getRouteId, oldProcessRouteItem.getRouteId())
                .orderByAsc(ProcessRouteItem::getDragSort));
        // èŽ·å–ç›®æ ‡ä½ç½®ï¼ˆç§»åŠ¨åˆ°ç¬¬å‡ ä¸ªä¹‹åŽï¼‰
        Integer targetPosition = processRouteItem.getDragSort();
        if (targetPosition != null && targetPosition >= 0) {
            // ç§»åŠ¨å…ƒç´ åˆ°æ–°çš„ä½ç½®
            processRouteItems.remove(oldProcessRouteItem);
            processRouteItems.add(targetPosition-1, oldProcessRouteItem);
            // æ›´æ–°æ‰€æœ‰å—影响的排序字段
            for (int i = 0; i < processRouteItems.size(); i++) {
                ProcessRouteItem item = processRouteItems.get(i);
                if (!item.getId().equals(oldProcessRouteItem.getId())) {
                    // æ£€æŸ¥æ˜¯å¦éœ€è¦æ›´æ–°æŽ’序值
                    if (item.getDragSort() != i+1) {
                        item.setDragSort(i+1);
                        processRouteItemMapper.updateById(item);
                    }
                } else {
                    // æ›´æ–°åŽŸè®°å½•çš„æ–°æŽ’åºä½ç½®
                    oldProcessRouteItem.setDragSort(targetPosition);
                    processRouteItemMapper.updateById(oldProcessRouteItem);
                }
            }
            return 1;
        }
        return 0;
    }
    @Override
    public String batchDelete(Long id) {
        // æŸ¥è¯¢è¦åˆ é™¤çš„æ•°æ®
        ProcessRouteItem deleteProcessRouteItem = processRouteItemMapper.selectById(id);
        if (deleteProcessRouteItem == null) {
            return "删除失败,未找到对应数据";
        }
        Long routeId = deleteProcessRouteItem.getRouteId();
        // åˆ é™¤æŒ‡å®šæ•°æ®
        processRouteItemMapper.deleteById(id);
        // æŸ¥è¯¢è¯¥å·¥è‰ºè·¯çº¿çš„æ‰€æœ‰å·¥åºå¹¶æŒ‰ç…§é¡ºåºæŽ’序
        List<ProcessRouteItem> processRouteItems = processRouteItemMapper.selectList(Wrappers.<ProcessRouteItem>lambdaQuery()
                .eq(ProcessRouteItem::getRouteId, routeId)
                .orderByAsc(ProcessRouteItem::getDragSort));
        // é‡æ–°è®¾ç½®æŽ’序值,使序号连续
        for (int i = 0; i < processRouteItems.size(); i++) {
            ProcessRouteItem item = processRouteItems.get(i);
            if (!item.getDragSort().equals(i+1)) {
                item.setDragSort(i+1);
                processRouteItemMapper.updateById(item);
            }
        }
        return "删除成功";
    }
}
src/main/java/com/ruoyi/production/service/impl/ProcessRouteServiceImpl.java
@@ -35,7 +35,7 @@
        this.save(processRoute);
        String dateStr = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        String idStr = String.format("%06d", processRoute.getId());
        String newProductCode = "GY" + dateStr + idStr;
        String newProductCode = "GYLX" + dateStr + idStr;
        // æ›´æ–°æ•°æ®åº“中的productCode
        processRoute.setProcessRouteCode(newProductCode);
        return processRouteMapper.updateById(processRoute);
src/main/java/com/ruoyi/production/service/impl/ProductBomServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,49 @@
package com.ruoyi.production.service.impl;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.production.dto.ProductBomDto;
import com.ruoyi.production.dto.ProductProcessDto;
import com.ruoyi.production.pojo.ProductBom;
import com.ruoyi.production.mapper.ProductBomMapper;
import com.ruoyi.production.pojo.ProductProcess;
import com.ruoyi.production.service.ProductBomService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
 * <p>
 * BOM主表 æœåŠ¡å®žçŽ°ç±»
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-01-15 09:59:27
 */
@Service
public class ProductBomServiceImpl extends ServiceImpl<ProductBomMapper, ProductBom> implements ProductBomService {
    @Autowired
    private ProductBomMapper productBomMapper;
    @Override
    public IPage<ProductBomDto> listPage(Page page, ProductBomDto productBomDto) {
        return productBomMapper.listPage(page,productBomDto);
    }
    @Override
    public AjaxResult add(ProductBom productBom) {
        boolean save = productBomMapper.insert(productBom) > 0;
        if (save) {
            // æ ¹æ®id生成no字段:GX + 8位数字(不足8位前面补0)
            String no = "BM." + String.format("%05d", productBom.getId());
            productBom.setBomNo(no);
            productBomMapper.updateById(productBom);
            return AjaxResult.success();
        }
        return AjaxResult.error();
    }
}
src/main/java/com/ruoyi/production/service/impl/ProductOrderServiceImpl.java
@@ -1,22 +1,111 @@
package com.ruoyi.production.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
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.dto.ProductBomDto;
import com.ruoyi.production.dto.ProductOrderDto;
import com.ruoyi.production.mapper.ProductOrderMapper;
import com.ruoyi.production.pojo.ProductOrder;
import com.ruoyi.production.dto.ProductStructureDto;
import com.ruoyi.production.mapper.*;
import com.ruoyi.production.pojo.*;
import com.ruoyi.production.service.ProcessRouteService;
import com.ruoyi.production.service.ProductOrderService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.List;
@Service
public class ProductOrderServiceImpl extends ServiceImpl<ProductOrderMapper, ProductOrder> implements ProductOrderService {
    @Autowired
    private ProductOrderMapper productOrderMapper;
    @Autowired
    private ProcessRouteMapper processRouteMapper;
    @Autowired
    private ProductProcessRouteMapper productProcessRouteMapper;
    @Autowired
    private ProcessRouteItemMapper processRouteItemMapper;
    @Autowired
    private ProductProcessRouteItemMapper productProcessRouteItemMapper;
    @Autowired
    private ProductWorkOrderMapper productWorkOrderMapper;
    @Override
    public IPage<ProductOrderDto> pageProductOrder(Page page, ProductOrderDto productOrder) {
        return productOrderMapper.pageProductOrder(page, productOrder);
    }
    @Override
    public int bindingRoute(ProductOrder productOrder) {
        //新增生产订单下的工艺路线主表
        ProcessRoute processRoute = processRouteMapper.selectById(productOrder.getRouteId());
        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());
            int insert = productProcessRouteItemMapper.insert(productProcessRouteItem);
            if (insert > 0) {
                // æŸ¥è¯¢ä»Šæ—¥å·²å­˜åœ¨çš„æœ€å¤§å·¥å•号
                QueryWrapper<ProductWorkOrder> queryWrapper = new QueryWrapper<>();
                queryWrapper.likeRight("work_order_no", datePrefix)
                        .orderByDesc("work_order_no")
                        .last("LIMIT 1");
                ProductWorkOrder lastWorkOrder = productWorkOrderMapper.selectOne(queryWrapper);
                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 = String.format("%s%03d", datePrefix, sequenceNumber);
                ProductWorkOrder productWorkOrder = new ProductWorkOrder();
                productWorkOrder.setProductProcessRouteItemId(productProcessRouteItem.getId());
                productWorkOrder.setProductOrderId(productOrder.getId());
                productWorkOrder.setPlanQuantity(productOrder.getQuantity());
                productWorkOrder.setWorkOrderNo(workOrderNoStr);
                productWorkOrder.setStatus(1);
                productWorkOrderMapper.insert(productWorkOrder);
            }
        }
        return productOrderMapper.updateById(productOrder);
    }
    @Override
    public List<ProcessRoute> listProcessRoute(Long productModelId) {
        return productOrderMapper.listProcessRoute(productModelId);
    }
    @Override
    public List<ProductStructureDto> listProcessBom(Long orderId) {
        return productOrderMapper.listProcessBom(orderId);
    }
}
src/main/java/com/ruoyi/production/service/impl/ProductProcessRouteItemServiceImpl.java
@@ -1,23 +1,206 @@
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.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.production.dto.ProductProcessRouteItemDto;
import com.ruoyi.production.mapper.ProductProcessRouteItemMapper;
import com.ruoyi.production.pojo.ProductProcessRouteItem;
import com.ruoyi.production.mapper.*;
import com.ruoyi.production.pojo.*;
import com.ruoyi.production.service.ProductProcessRouteItemService;
import com.ruoyi.quality.mapper.QualityInspectMapper;
import com.ruoyi.quality.pojo.QualityInspect;
import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
import com.ruoyi.sales.pojo.SalesLedgerProduct;
import lombok.AllArgsConstructor;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
@Service
@Transactional(rollbackFor = Exception.class)
@AllArgsConstructor
public class ProductProcessRouteItemServiceImpl extends ServiceImpl<ProductProcessRouteItemMapper, ProductProcessRouteItem> implements ProductProcessRouteItemService {
    @Autowired
    private ProductProcessRouteItemMapper productProcessRouteItemMapper;
    private ProductionProductMainMapper productionProductMainMapper;
    private ProductionProductInputMapper productionProductInputMapper;
    private ProductionProductOutputMapper productionProductOutputMapper;
    private QualityInspectMapper qualityInspectMapper;
    private SalesLedgerProductionAccountingMapper salesLedgerProductionAccountingMapper;
    private ProductWorkOrderMapper productWorkOrderMapper;
    private ProductOrderMapper productOrderMapper;
    private ProductProcessRouteMapper productProcessRouteMapper;
    private SalesLedgerProductMapper salesLedgerProductMapper;
    @Override
    public List<ProductProcessRouteItemDto> listItem(Long orderId) {
        return productProcessRouteItemMapper.listItem(orderId);
    }
    @Override
    public R deleteRouteItem(Long id) {
        Long routeItemId = id;
        try {
            // æŸ¥è¯¢å·¥å•
            ProductWorkOrder productWorkOrder = productWorkOrderMapper.selectOne(
                    new LambdaQueryWrapper<ProductWorkOrder>()
                            .eq(ProductWorkOrder::getProductProcessRouteItemId, routeItemId)
                            .last("LIMIT 1")
            );
            if (productWorkOrder == null) {
                throw new RuntimeException("删除失败:未找到关联的生产工单");
            }
            Long workOrderId = productWorkOrder.getId();
            Long productOrderId = productWorkOrder.getProductOrderId();
            // æŸ¥è¯¢ç”Ÿäº§ä¸»è¡¨
            List<ProductionProductMain> productionProductMains = productionProductMainMapper.selectList(
                    new LambdaQueryWrapper<ProductionProductMain>()
                            .eq(ProductionProductMain::getWorkOrderId, workOrderId)
            );
            if (!productionProductMains.isEmpty()) {
                // æ‰¹é‡åˆ é™¤å­è¡¨
                for (ProductionProductMain main : productionProductMains) {
                    Long mainId = main.getId();
                    // åˆ é™¤æŠ•å…¥
                    productionProductInputMapper.delete(new LambdaQueryWrapper<ProductionProductInput>()
                            .eq(ProductionProductInput::getProductMainId, mainId));
                    // åˆ é™¤äº§å‡º
                    productionProductOutputMapper.delete(new LambdaQueryWrapper<ProductionProductOutput>()
                            .eq(ProductionProductOutput::getProductMainId, mainId));
                    // åˆ é™¤è´¨æ£€
                    qualityInspectMapper.delete(new LambdaQueryWrapper<QualityInspect>()
                            .eq(QualityInspect::getProductMainId, mainId));
                }
            }
            //  åˆ é™¤æŠ¥å·¥ï¼ˆç”Ÿäº§ä¸»è¡¨ï¼‰
            productionProductMainMapper.delete(new LambdaQueryWrapper<ProductionProductMain>()
                    .eq(ProductionProductMain::getWorkOrderId, workOrderId));
            // æŸ¥è¯¢è®¢å• + åˆ é™¤æ ¸ç®—
            ProductOrder productOrder = productOrderMapper.selectById(productOrderId);
            if (productOrder != null && productOrder.getSalesLedgerId() != null) {
                salesLedgerProductionAccountingMapper.delete(new LambdaQueryWrapper<SalesLedgerProductionAccounting>()
                        .eq(SalesLedgerProductionAccounting::getSalesLedgerId, productOrder.getSalesLedgerId()));
            }
            // åˆ é™¤å…³è”工单
            productWorkOrderMapper.delete(new LambdaQueryWrapper<ProductWorkOrder>()
                    .eq(ProductWorkOrder::getProductProcessRouteItemId, routeItemId));
            // åˆ é™¤ä¸»è¡¨æ•°æ®
            ProductProcessRouteItem deleteProductProcessRouteItem = productProcessRouteItemMapper.selectById(routeItemId);
            Long productRouteId = deleteProductProcessRouteItem.getProductRouteId();
            // åˆ é™¤æŒ‡å®šæ•°æ®
            productProcessRouteItemMapper.deleteById(id);
            // æŸ¥è¯¢è¯¥å·¥è‰ºè·¯çº¿çš„æ‰€æœ‰å·¥åºå¹¶æŒ‰ç…§é¡ºåºæŽ’序
            List<ProductProcessRouteItem> productProcessRouteItems = productProcessRouteItemMapper.selectList(Wrappers.<ProductProcessRouteItem>lambdaQuery()
                    .eq(ProductProcessRouteItem::getProductRouteId, productRouteId)
                    .orderByAsc(ProductProcessRouteItem::getDragSort));
            // é‡æ–°è®¾ç½®æŽ’序值,使序号连续
            for (int i = 0; i < productProcessRouteItems.size(); i++) {
                ProductProcessRouteItem item = productProcessRouteItems.get(i);
                if (!item.getDragSort().equals(i + 1)) {
                    item.setDragSort(i + 1);
                    productProcessRouteItemMapper.updateById(item);
                }
            }
            return R.ok();
        } catch (Exception e) {
            throw new RuntimeException("删除生产工艺路线失败:" + e.getMessage());
        }
    }
    @Override
    public R addRouteItem(ProductProcessRouteItem productProcessRouteItem) {
        ProductOrder productOrder = productOrderMapper.selectById(productProcessRouteItem.getProductOrderId());
        int insert = productProcessRouteItemMapper.insert(productProcessRouteItem);
        // ç”Ÿæˆå½“前日期的前缀:年月日
        String datePrefix = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        if (insert > 0) {
            // æŸ¥è¯¢ä»Šæ—¥å·²å­˜åœ¨çš„æœ€å¤§å·¥å•号
            QueryWrapper<ProductWorkOrder> queryWrapper = new QueryWrapper<>();
            queryWrapper.likeRight("work_order_no", datePrefix)
                    .orderByDesc("work_order_no")
                    .last("LIMIT 1");
            ProductWorkOrder lastWorkOrder = productWorkOrderMapper.selectOne(queryWrapper);
            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 = String.format("%s%03d", datePrefix, sequenceNumber);
            ProductWorkOrder productWorkOrder = new ProductWorkOrder();
            productWorkOrder.setProductProcessRouteItemId(productProcessRouteItem.getId());
            productWorkOrder.setProductOrderId(productProcessRouteItem.getProductOrderId());
            productWorkOrder.setPlanQuantity(productOrder.getQuantity());
            productWorkOrder.setWorkOrderNo(workOrderNoStr);
            productWorkOrder.setStatus(1);
            productWorkOrderMapper.insert(productWorkOrder);
        }
        return R.ok();
    }
    @Override
    public int sortRouteItem(ProductProcessRouteItem productProcessRouteItem) {
        //查询被改动的这条数据
        ProductProcessRouteItem oldProductProcessRouteItem = productProcessRouteItemMapper.selectById(productProcessRouteItem.getId());
        //查询该工艺路线的所有工序并按照顺序排序
        List<ProductProcessRouteItem> productProcessRouteItems = productProcessRouteItemMapper.selectList(Wrappers.<ProductProcessRouteItem>lambdaQuery()
                .eq(ProductProcessRouteItem::getProductRouteId, oldProductProcessRouteItem.getProductRouteId())
                .orderByAsc(ProductProcessRouteItem::getDragSort));
        // èŽ·å–ç›®æ ‡ä½ç½®ï¼ˆç§»åŠ¨åˆ°ç¬¬å‡ ä¸ªä¹‹åŽï¼‰
        Integer targetPosition = productProcessRouteItem.getDragSort();
        if (targetPosition != null && targetPosition >= 0) {
            // ç§»åŠ¨å…ƒç´ åˆ°æ–°çš„ä½ç½®
            productProcessRouteItems.remove(oldProductProcessRouteItem);
            productProcessRouteItems.add(targetPosition-1, oldProductProcessRouteItem);
            // æ›´æ–°æ‰€æœ‰å—影响的排序字段
            for (int i = 0; i < productProcessRouteItems.size(); i++) {
                ProductProcessRouteItem item = productProcessRouteItems.get(i);
                if (!item.getId().equals(oldProductProcessRouteItem.getId())) {
                    // æ£€æŸ¥æ˜¯å¦éœ€è¦æ›´æ–°æŽ’序值
                    if (item.getDragSort() != i+1) {
                        item.setDragSort(i+1);
                        productProcessRouteItemMapper.updateById(item);
                    }
                } else {
                    // æ›´æ–°åŽŸè®°å½•çš„æ–°æŽ’åºä½ç½®
                    oldProductProcessRouteItem.setDragSort(targetPosition);
                    productProcessRouteItemMapper.updateById(oldProductProcessRouteItem);
                }
            }
            return 1;
        }
        return 0;
    }
}
src/main/java/com/ruoyi/production/service/impl/ProductProcessRouteServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,29 @@
package com.ruoyi.production.service.impl;
import com.ruoyi.production.dto.ProcessRouteDto;
import com.ruoyi.production.pojo.ProductProcessRoute;
import com.ruoyi.production.mapper.ProductProcessRouteMapper;
import com.ruoyi.production.service.ProductProcessRouteService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
/**
 * <p>
 *  æœåŠ¡å®žçŽ°ç±»
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-01-15 02:51:09
 */
@Service
public class ProductProcessRouteServiceImpl extends ServiceImpl<ProductProcessRouteMapper, ProductProcessRoute> implements ProductProcessRouteService {
    @Autowired
    private ProductProcessRouteMapper productProcessRouteMapper;
    @Override
    public ProcessRouteDto listMain(Long orderId) {
        return productProcessRouteMapper.listMain(orderId);
    }
}
src/main/java/com/ruoyi/production/service/impl/ProductProcessServiceImpl.java
@@ -1,8 +1,11 @@
package com.ruoyi.production.service.impl;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.basic.pojo.Customer;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.production.dto.ProductProcessDto;
import com.ruoyi.production.mapper.ProductProcessMapper;
@@ -11,6 +14,10 @@
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;
import java.util.List;
@Service
public class ProductProcessServiceImpl extends ServiceImpl<ProductProcessMapper, ProductProcess> implements ProductProcessService {
@@ -27,7 +34,7 @@
        ProductProcess productProcess = new ProductProcess();
        BeanUtils.copyProperties(productProcessDto,productProcess);
        boolean save = productProcessMapper.insert(productProcess) > 0;
        if (save) {
        if (save && ObjectUtils.isNotNull(productProcessDto.getNo())) {
            // æ ¹æ®id生成no字段:GX + 8位数字(不足8位前面补0)
            String no = "GX" + String.format("%08d", productProcess.getId());
            productProcess.setNo(no);
@@ -37,4 +44,20 @@
        }
        return AjaxResult.error();
    }
    @Override
    public AjaxResult importData(MultipartFile file) {
        try {
            ExcelUtil<ProductProcess> util = new ExcelUtil<ProductProcess>(ProductProcess.class);
            List<ProductProcess> productProcessList = util.importExcel(file.getInputStream());
            if(CollectionUtils.isEmpty(productProcessList)){
                return AjaxResult.warn("模板错误或导入数据为空");
            }
            this.saveOrUpdateBatch(productProcessList);
            return AjaxResult.success(true);
        }catch (Exception e){
            e.printStackTrace();
            return AjaxResult.error("导入失败");
        }
    }
}
src/main/java/com/ruoyi/production/service/impl/ProductStructureServiceImpl.java
@@ -1,13 +1,16 @@
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.extension.service.impl.ServiceImpl;
import com.ruoyi.basic.dto.ProductModelDto;
import com.ruoyi.basic.dto.ProductTreeDto;
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.production.dto.ProductStructureDto;
import com.ruoyi.production.mapper.ProductBomMapper;
import com.ruoyi.production.mapper.ProductStructureMapper;
import com.ruoyi.production.pojo.ProductStructure;
import com.ruoyi.production.service.ProductStructureService;
@@ -17,7 +20,7 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.util.HashMap;
import java.util.ArrayList;
import java.util.List;
@Service
@@ -27,29 +30,22 @@
    @Autowired
    private  ProductStructureMapper productStructureMapper;
    @Autowired
    private ProductModelMapper productModelMapper;
    @Autowired
    private ProductMapper productMapper;
    @Override
    public ProductModelDto listByproductModelId(Long productModelId) {
        ProductModel productModel = productModelMapper.selectById(productModelId);
        Product product = productMapper.selectById(productModel.getProductId());
        ProductModelDto productModelDto = new ProductModelDto();
        BeanUtils.copyProperties(productModel,productModelDto);
        productModelDto.setProductName(product.getProductName());
        List<ProductStructureDto> productStructureDtos = productStructureMapper.listByproductModelId(productModelId);
        productModelDto.setProductStructureList(productStructureDtos);
        return productModelDto;
    }
    @Override
    public Boolean addProductStructureDto(ProductStructureDto productStructureDto) {
        this.remove(new QueryWrapper<ProductStructure>().lambda().eq(ProductStructure::getParentId, productStructureDto.getParentId()));
        this.remove(new QueryWrapper<ProductStructure>().lambda().eq(ProductStructure::getBomId, productStructureDto.getBomId()));
        productStructureDto.getProductStructureList().forEach(productStructure -> {
            productStructure.setParentId(productStructureDto.getParentId());
            productStructure.setBomId(productStructureDto.getBomId());
        });
        return this.saveBatch(productStructureDto.getProductStructureList());
    }
    @Override
    public List<ProductStructureDto> listBybomId(Long bomId) {
        List<ProductStructureDto> tree = productStructureMapper.listBybomId(bomId);
        return tree;
    }
}
src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java
@@ -5,6 +5,8 @@
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
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.basic.mapper.ProductMapper;
@@ -13,6 +15,8 @@
import com.ruoyi.basic.pojo.ProductModel;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.procurementrecord.mapper.ProcurementRecordOutMapper;
import com.ruoyi.procurementrecord.pojo.ProcurementRecordOut;
import com.ruoyi.procurementrecord.utils.StockUtils;
import com.ruoyi.production.controller.ProductWorkOrderController;
import com.ruoyi.production.dto.ProductStructureDto;
@@ -21,21 +25,24 @@
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.QualityInspectMapper;
import com.ruoyi.quality.mapper.QualityInspectParamMapper;
import com.ruoyi.quality.mapper.QualityTestStandardMapper;
import com.ruoyi.quality.mapper.QualityTestStandardParamMapper;
import com.ruoyi.quality.pojo.QualityInspect;
import com.ruoyi.quality.pojo.QualityInspectParam;
import com.ruoyi.quality.pojo.QualityTestStandard;
import com.ruoyi.quality.pojo.QualityTestStandardParam;
import io.swagger.models.auth.In;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.ruoyi.production.mapper.ProductionProductMainMapper;
import oshi.driver.mac.net.NetStat;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
@@ -43,8 +50,10 @@
@Service
@AllArgsConstructor
@Transactional(rollbackFor = Exception.class)
public class ProductionProductMainServiceImpl extends ServiceImpl<ProductionProductMainMapper, ProductionProductMain> implements ProductionProductMainService {
    private final ProcurementRecordOutMapper procurementRecordOutMapper;
    private ProductionProductMainMapper productionProductMainMapper;
    private ProductWorkOrderController productWorkOrderController;
@@ -52,6 +61,7 @@
    private ProductWorkOrderMapper productWorkOrderMapper;
    private ProductProcessRouteItemMapper productProcessRouteItemMapper;
    private SysUserMapper userMapper;
    private ProductionProductOutputMapper productionProductOutputMapper;
@@ -62,11 +72,12 @@
    private QualityInspectMapper qualityInspectMapper;
    private ProductProcessMapper productProcessMapper;
    private ProductProcessRouteMapper productProcessRouteMapper;
    private ProductMapper productMapper;
    private QualityTestStandardMapper qualityTestStandardMapper;
    private QualityTestStandardParamMapper qualityTestStandardParamMapper;
    private QualityInspectParamMapper qualityInspectParamMapper;
@@ -87,41 +98,35 @@
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean addProductMain(ProductionProductMainDto dto) {
        if (dto == null) {
            throw new RuntimeException("参数不能为空");
        }
        SysUser user = SecurityUtils.getLoginUser().getUser();
        // æ–°å¢žé€»è¾‘
        SysUser user = userMapper.selectUserById(dto.getUserId());
        ProductionProductMain productionProductMain = new ProductionProductMain();
        //当前工艺路线对应的工序详情
        ProductProcessRouteItem productProcessRouteItem = productProcessRouteItemMapper.selectById(dto.getProductProcessRouteItemId());
        if (productProcessRouteItem == null) {
            throw new RuntimeException("工艺路线项不存在");
        }
        String datePrefix = LocalDate.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
        //当前具体工序
        ProductProcess productProcess = productProcessMapper.selectById(productProcessRouteItem.getProcessId());
        //工艺路线中当前工序对应的产出规格型号
        ProductModel productModel = productModelMapper.selectById(productProcessRouteItem.getProductModelId());
        //查询该生产订单对应的bom
        ProductProcessRoute productProcessRoute = productProcessRouteMapper.selectById(productProcessRouteItem.getProductRouteId());
        /*新增报工主表*/
        //查询最大报工编号
        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) {
                Object maxNoObj = result.get("maxNo");
                if (maxNoObj != null) {
                    String lastNo = maxNoObj.toString();
                    System.out.println("lastNo: " + lastNo);
                    if (lastNo.startsWith(datePrefix)) {
                        try {
                            String seqStr = lastNo.substring(datePrefix.length());
@@ -133,91 +138,114 @@
                }
            }
        }
        String productNo = String.format("%s%03d", datePrefix, sequenceNumber);
        productionProductMain.setProductNo(productNo);
        productionProductMain.setUserId(user.getUserId());
        productionProductMain.setUserId(dto.getUserId());
        productionProductMain.setUserName(dto.getUserName());
        productionProductMain.setProductProcessRouteItemId(dto.getProductProcessRouteItemId());
        productionProductMain.setWorkOrderId(dto.getWorkOrderId());
        productionProductMain.setStatus(0);
        // æ·»åŠ æŠ¥å·¥ä¸»è¡¨
        int insert = productionProductMainMapper.insert(productionProductMain);
        //更新工单
        if (insert > 0) {
            Map<String, Object> params = new HashMap<>();
            params.put("quantity", dto.getQuantity());
            params.put("productMainId", productionProductMain.getId());
            params.put("workOrderId", dto.getWorkOrderId());
            params.put("deductQuantity", dto.getQuantity());
            productWorkOrderMapper.updatePlanQuantity(params);
        productionProductMainMapper.insert(productionProductMain);
        /*新增报工投入表*/
        List<ProductStructureDto> productStructureDtos = productStructureMapper.listBybomAndProcess(productProcessRoute.getBomId(), productProcess.getId());
        if (productStructureDtos.size() == 0) {
            //如果该工序没有产品结构的投入品,那这个投入品和产出品是同一个
            ProductStructureDto productStructureDto = new ProductStructureDto();
            productStructureDto.setProductModelId(productProcessRouteItem.getProductModelId());
            productStructureDto.setUnitQuantity(BigDecimal.ONE);
            productStructureDtos.add(productStructureDto);
        }
        ProductProcess productProcess = productProcessMapper.selectById(productProcessRouteItem.getProcessId());
        ProductModel productModel = productProcessRouteItem.getProductModelId() != null ?
                productModelMapper.selectById(productProcessRouteItem.getProductModelId()) : null;
        if (productModel != null) {
            Product product = productMapper.selectById(productModel.getProductId());
            int inspectType = "组装".equals(productProcess.getName()) ? 2 : 1;
            QualityInspect qualityInspect = new QualityInspect();
            qualityInspect.setProductId(product.getId());
            qualityInspect.setProductName(product.getProductName());
            qualityInspect.setModel(productModel.getModel());
            qualityInspect.setUnit(productModel.getUnit());
            qualityInspect.setQuantity(dto.getQuantity());
            qualityInspect.setProcess(productProcess.getName());
            qualityInspect.setInspectState(0);
            qualityInspect.setInspectType(inspectType);
            qualityInspect.setProductMainId(productionProductMain.getId());
            qualityInspect.setProductModelId(productModel.getId());
            qualityInspectMapper.insert(qualityInspect);
            List<QualityTestStandardParam> qualityTestStandardParams = qualityTestStandardParamMapper.selectListByProductId(product.getId());
            if (qualityTestStandardParams.size()>0) {
                qualityTestStandardParams.forEach(standard -> {
                    QualityInspectParam param = new QualityInspectParam();
                    BeanUtils.copyProperties(standard, param);
                    param.setId(null);
                    param.setInspectId(qualityInspect.getId());
                    qualityInspectParamMapper.insert(param);
                });
        for (ProductStructureDto productStructureDto : productStructureDtos) {
            ProductModel productModel1 = productModelMapper.selectById(productStructureDto.getProductModelId());
            Product product = productMapper.selectById(productModel1.getProductId());
            BigDecimal stockQuantity = stockUtils.getStockQuantity(productModel1.getId()).get("stockQuantity");
            if (!(stockQuantity.compareTo(BigDecimal.ZERO) > 0)) {
                throw new RuntimeException(product.getProductName() + "库存为0");
            }
        }
        // æ·»åŠ æŠ•å…¥
        if (productModel != null) {
            List<ProductStructureDto> productStructureDtos = productStructureMapper.listByproductModelId(productModel.getId());
            for (ProductStructureDto productStructureDto : productStructureDtos) {
                ProductModel productModel1 = productModelMapper.selectById(productStructureDto.getProductModelId());
                BigDecimal stockQuantity = stockUtils.getStockQuantity(productModel1.getId());
                if (!(stockQuantity.compareTo(BigDecimal.ZERO) > 0)) {
                    throw new RuntimeException("库存不足");
                }
                ProductionProductInput productionProductInput = new ProductionProductInput();
                productionProductInput.setProductModelId(productStructureDto.getProductModelId());
                productionProductInput.setQuantity(productStructureDto.getUnitQuantity().multiply(dto.getQuantity()));
                productionProductInput.setProductMainId(productionProductMain.getId());
                productionProductInputMapper.insert(productionProductInput);
            if (stockQuantity.compareTo(productStructureDto.getUnitQuantity().multiply(dto.getQuantity())) < 0) {
                throw new RuntimeException(product.getProductName() + "库存不足");
            }
            ProductionProductInput productionProductInput = new ProductionProductInput();
            productionProductInput.setProductModelId(productStructureDto.getProductModelId());
            productionProductInput.setQuantity(productStructureDto.getUnitQuantity().multiply(dto.getQuantity()));
            productionProductInput.setProductMainId(productionProductMain.getId());
            productionProductInputMapper.insert(productionProductInput);
            //对应的库存出库
            DateTimeFormatter dateFormat = DateTimeFormatter.ofPattern("yyyyMMdd");
            LocalDate now = LocalDate.now();
            ProcurementRecordOut procurementRecordOut1 = procurementRecordOutMapper.selectCode(dateFormat.format(now));
            Long aLong = procurementRecordOut1 == null ? 1L : Long.valueOf(procurementRecordOut1.getCode().split("LS" + dateFormat.format(now))[1]);
            ProcurementRecordOut.ProcurementRecordOutBuilder procurementRecordOut = ProcurementRecordOut.builder()
                    .procurementRecordStorageId(0)
                    .code("LS" + dateFormat.format(now) + String.format("%03d", aLong + 1))
                    .salesLedgerProductId(productionProductMain.getId())//关联报工产出
                    .inboundBatches(aLong.equals(0L) ? "第1批次" : "第" + (aLong + 1) + "批次")
                    .inboundNum(productionProductInput.getQuantity())
                    .type(4)
                    .createBy(user.getNickName())
                    .productModelId(productModel1.getId());
            procurementRecordOutMapper.insert(procurementRecordOut.build());
        }
        // æ·»åŠ äº§å‡º
        /*新增报工产出表*/
        ProductionProductOutput productionProductOutput = new ProductionProductOutput();
        productionProductOutput.setProductMainId(productionProductMain.getId());
        productionProductOutput.setProductModelId(productProcessRouteItem.getProductModelId());
        productionProductOutput.setQuantity(dto.getQuantity() != null ? dto.getQuantity() : BigDecimal.ZERO);
        productionProductOutputMapper.insert(productionProductOutput);
        // èŽ·å–ç”Ÿäº§è®¢å•
        ProductWorkOrder productWorkOrder = productWorkOrderMapper.selectById(dto.getWorkOrderId());
        ProductOrder productOrder = productOrderMapper.selectById(productWorkOrder.getProductOrderId());
        if (productOrder == null) {
            throw new RuntimeException("生产订单不存在");
        //对应的过程检或者出厂检
        List<ProductProcessRouteItem> productProcessRouteItems = productProcessRouteItemMapper.selectList(Wrappers.<ProductProcessRouteItem>lambdaQuery().eq(ProductProcessRouteItem::getProductRouteId, productProcessRouteItem.getProductRouteId()));
        int inspectType = 1;
        if (productProcessRouteItem.getDragSort()==productProcessRouteItems.size()){
            //最后一道工序生成出厂检
            inspectType = 2;
        }
        // æ·»åŠ ç”Ÿäº§æ ¸ç®—
        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(dto.getQuantity());
        qualityInspect.setProcess(productProcess.getName());
        qualityInspect.setInspectState(0);
        qualityInspect.setInspectType(inspectType);
        qualityInspect.setProductMainId(productionProductMain.getId());
        qualityInspect.setProductModelId(productModel.getId());
        qualityInspectMapper.insert(qualityInspect);
        qualityTestStandardMapper.selectList(
                new LambdaQueryWrapper<QualityTestStandard>()
                        .eq(QualityTestStandard::getProductId, product.getId())
        ).forEach(standard -> {
            QualityInspectParam param = new QualityInspectParam();
            BeanUtils.copyProperties(standard, param);
            param.setId(null);
            param.setInspectId(qualityInspect.getId());
            qualityInspectParamMapper.insert(param);
        });
        /*更新工单和生产订单*/
        ProductWorkOrder productWorkOrder = productWorkOrderMapper.selectById(dto.getWorkOrderId());
        productWorkOrder.setCompleteQuantity(productWorkOrder.getCompleteQuantity().add(dto.getQuantity()));
        if (ObjectUtils.isNull(productWorkOrder.getActualStartTime())){
            productWorkOrder.setActualStartTime(LocalDate.now());//实际开始时间
        }
        if (productWorkOrder.getCompleteQuantity().compareTo(productWorkOrder.getPlanQuantity()) == 0){
            productWorkOrder.setActualEndTime(LocalDate.now());//实际结束时间
        }
        productWorkOrderMapper.updateById(productWorkOrder);
        //生产订单
        ProductOrder productOrder = productOrderMapper.selectById(productWorkOrder.getProductOrderId());
        if (ObjectUtils.isNull(productOrder.getStartTime())){
            productOrder.setStartTime(LocalDateTime.now());//开始时间
        }
        if (productProcessRouteItem.getDragSort()==productProcessRouteItems.size()){
            //如果是最后一道工序报工之后生产订单完成数量+
            productOrder.setCompleteQuantity(productOrder.getCompleteQuantity().add(dto.getQuantity()));
            if (productOrder.getCompleteQuantity().compareTo(productOrder.getQuantity()) == 0){
                productOrder.setEndTime(LocalDateTime.now());//结束时间
            }
        }
        productOrderMapper.updateById(productOrder);
        /*添加生产核算*/
        SalesLedgerProductionAccounting salesLedgerProductionAccounting = SalesLedgerProductionAccounting.builder()
                .salesLedgerWorkId(productionProductMain.getId())
                .salesLedgerSchedulingId(0L)
@@ -232,40 +260,54 @@
                .tenantId(dto.getTenantId())
                .build();
        salesLedgerProductionAccountingMapper.insert(salesLedgerProductionAccounting);
        return true;
    }
    @Override
    @Transactional
    public Boolean removeProductMain(ProductionProductMainDto dto) {
        Long id = dto.getId();
        // æ›´æ–°å·¥å•
        productWorkOrderMapper.rollbackPlanQuantity(id);
        // åˆ é™¤è´¨æ£€å‚数和质检记录
        ProductionProductMain productionProductMain = productionProductMainMapper.selectById(dto.getId());
        //该报工对应的工艺路线详情
        ProductProcessRouteItem productProcessRouteItem = productProcessRouteItemMapper.selectById(productionProductMain.getProductProcessRouteItemId());
        ProductionProductOutput productionProductOutput = productionProductOutputMapper.selectList(Wrappers.<ProductionProductOutput>lambdaQuery().eq(ProductionProductOutput::getProductMainId, productionProductMain.getId())).get(0);
        /*删除核算*/
        salesLedgerProductionAccountingMapper.delete(
                new LambdaQueryWrapper<SalesLedgerProductionAccounting>()
                        .eq(SalesLedgerProductionAccounting::getSalesLedgerWorkId, productionProductMain.getId())
        );
        /*更新工单和生产订单*/
        ProductWorkOrder productWorkOrder = productWorkOrderMapper.selectById(productionProductMain.getWorkOrderId());
        productWorkOrder.setCompleteQuantity(productWorkOrder.getCompleteQuantity().subtract(productionProductOutput.getQuantity()));
        productWorkOrder.setActualEndTime(null);
        productWorkOrderMapper.updateById(productWorkOrder);
        //判断是否是最后一道工序
        List<ProductProcessRouteItem> productProcessRouteItems = productProcessRouteItemMapper.selectList(Wrappers.<ProductProcessRouteItem>lambdaQuery().eq(ProductProcessRouteItem::getProductRouteId, productProcessRouteItem.getProductRouteId()));
        if (productProcessRouteItem.getDragSort() == productProcessRouteItems.size()){
            ProductOrder productOrder = productOrderMapper.selectById(productWorkOrder.getProductOrderId());
            productOrder.setCompleteQuantity(productOrder.getCompleteQuantity().subtract(productionProductOutput.getQuantity()));
            productOrder.setEndTime(null);
            productOrderMapper.updateById(productOrder);
        }
        /*删除产出*/
        //删除质检
        qualityInspectMapper.selectList(
                new LambdaQueryWrapper<QualityInspect>()
                        .eq(QualityInspect::getProductMainId, id)
                        .eq(QualityInspect::getProductMainId, productionProductMain.getId())
        ).forEach(q -> {
            qualityInspectParamMapper.delete(
                    new LambdaQueryWrapper<QualityInspectParam>()
                            .eq(QualityInspectParam::getInspectId, q.getId()));
            qualityInspectMapper.deleteById(q.getId());
        });
        // åˆ é™¤äº§å‡ºè®°å½•
        productionProductOutputMapper.delete(new LambdaQueryWrapper<ProductionProductOutput>()
                .eq(ProductionProductOutput::getProductMainId, id)
        );
        // åˆ é™¤å…³è”的核算数据
        salesLedgerProductionAccountingMapper.delete(
                new LambdaQueryWrapper<SalesLedgerProductionAccounting>()
                        .eq(SalesLedgerProductionAccounting::getSalesLedgerWorkId, id)
        );
                .eq(ProductionProductOutput::getProductMainId, productionProductMain.getId()));
        /*删除投入*/
        procurementRecordOutMapper.delete(new LambdaQueryWrapper<ProcurementRecordOut>()
                .eq(ProcurementRecordOut::getSalesLedgerProductId, productionProductMain.getId()));
        productionProductInputMapper.delete(new LambdaQueryWrapper<ProductionProductInput>()
                .eq(ProductionProductInput::getProductMainId, productionProductMain.getId()));
        // åˆ é™¤ä¸»è¡¨
        return productionProductMainMapper.deleteById(id) > 0;
        productionProductMainMapper.deleteById(productionProductMain.getId());
        return true;
    }
}
src/main/java/com/ruoyi/purchase/controller/PurchaseLedgerController.java
@@ -22,6 +22,7 @@
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.List;
import java.util.stream.Collectors;
@@ -194,6 +195,11 @@
        IPage<PurchaseLedgerDto> purchaseLedgerDtoIPage = purchaseLedgerService.selectPurchaseLedgerListPage(page ,purchaseLedger);
        //过滤掉approvalStatus=3的记录
        purchaseLedgerDtoIPage.getRecords().removeIf(purchaseLedgerDto -> purchaseLedgerDto.getApprovalStatus() == 3);
        purchaseLedgerDtoIPage.getRecords().forEach(purchaseLedgerDto -> {
            if (purchaseLedgerDto.getUnReceiptPaymentAmount().compareTo(BigDecimal.ZERO) == 0) {
                purchaseLedgerDto.setUnReceiptPaymentAmount(purchaseLedgerDto.getContractAmount());
            }
        });
         return AjaxResult.success(purchaseLedgerDtoIPage);
    }
src/main/java/com/ruoyi/purchase/controller/TicketRegistrationController.java
@@ -138,12 +138,12 @@
    }
    @GetMapping("/getProductRecordById")
    public AjaxResult getProductRecordById(Long id) {
        if (id == null) {
    @PostMapping("/getProductRecordById")
    public AjaxResult getProductRecordById(@RequestBody ProductRecordDto productRecordDto) {
        if (productRecordDto.getId() == null) {
            return AjaxResult.error("参数错误");
        }
        return AjaxResult.success(productRecordService.getProductRecordById(id));
        return AjaxResult.success(productRecordService.getProductRecordById(productRecordDto));
    }
    @ApiModelProperty("修改来票登记")
src/main/java/com/ruoyi/purchase/dto/ProductRecordDto.java
@@ -5,6 +5,7 @@
import com.ruoyi.sales.pojo.CommonFile;
import lombok.Data;
import java.math.BigDecimal;
import java.util.List;
@Data
@@ -28,12 +29,21 @@
    private String projectName;
    private Long issUerId;
    private String issUer;
    /**
     * åˆåŒé‡‘额(产品含税总价)
     */
    private BigDecimal contractAmount = BigDecimal.ZERO;
    //增值税
    private String invoiceAmount = "0";
    /**
     * å·²æ¥ç¥¨é‡‘额(发票金额)
     */
    private BigDecimal invoiceTotal = BigDecimal.ZERO;
    private BigDecimal invoiceAmount = BigDecimal.ZERO;
    /**
     * å‘票号
     */
    private String invoiceNumber;
    private String unTicketsPrice = "0";
    private BigDecimal unTicketsPrice = BigDecimal.ZERO;
    private List<CommonFile> commonFiles;
src/main/java/com/ruoyi/purchase/mapper/ProductRecordMapper.java
@@ -8,6 +8,8 @@
import com.ruoyi.purchase.pojo.ProductRecord;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
 * é‡‡è´­å°è´¦äº§å“å¼€ç¥¨è®°å½•Mapper接口
 *
@@ -18,5 +20,5 @@
    IPage<ProductRecordDto> productRecordPage(Page page, @Param("c") TicketRegistrationDto ticketRegistrationDto);
    ProductRecordDto getProductRecordById(Long id);
    List<ProductRecordDto> getProductRecordById(@Param("c") ProductRecordDto productRecordDto);
}
src/main/java/com/ruoyi/purchase/service/IProductRecordService.java
@@ -24,5 +24,5 @@
    AjaxResult updateRecord(ProductRecordDto productRecordDto);
    ProductRecordDto getProductRecordById(Long id);
    ProductRecordDto getProductRecordById(ProductRecordDto productRecordDto);
}
src/main/java/com/ruoyi/purchase/service/impl/ProductRecordServiceImpl.java
@@ -101,9 +101,19 @@
        return AjaxResult.success("修改成功");
    }
    @Override
    public ProductRecordDto getProductRecordById(Long id) {
        ProductRecordDto productRecordDto = productRecordMapper.getProductRecordById(id);
        return productRecordDto;
     @Override
    public ProductRecordDto getProductRecordById(ProductRecordDto productRecordDto) {
        List<ProductRecordDto> productRecordDtoList = productRecordMapper.getProductRecordById(productRecordDto);
        if(productRecordDtoList != null && productRecordDtoList.size() > 0){
            ProductRecordDto productRecordDto1 = productRecordDtoList.get(productRecordDtoList.size() - 1);
            // è¿‡æ»¤å‡ºä¸Žä¼ å…¥çš„ productRecordDto ä¸»é”®ç›¸åŒçš„记录
            ProductRecordDto productRecordDto2 = productRecordDtoList.stream().filter(item ->
                            item.getId().equals(productRecordDto.getId()))
                    .findFirst().orElse(null);
            productRecordDto2.setFutureTickets(productRecordDto1.getFutureTickets());
            productRecordDto2.setFutureTicketsAmount(productRecordDto1.getFutureTicketsAmount());
            return productRecordDto2;
        }
        return null;
    }
}
src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java
@@ -205,29 +205,44 @@
        }
        //新增原材料检验
        for (SalesLedgerProduct saleProduct : productList) {
            QualityInspect qualityInspect = new QualityInspect();
            qualityInspect.setInspectType(0);
            qualityInspect.setSupplier(purchaseLedger.getSupplierName());
            qualityInspect.setPurchaseLedgerId(purchaseLedger.getId());
            qualityInspect.setProductId(saleProduct.getId());
            qualityInspect.setProductName(saleProduct.getProductCategory());
            qualityInspect.setModel(saleProduct.getSpecificationModel());
            qualityInspect.setProductModelId(saleProduct.getProductModelId());
            qualityInspect.setUnit(saleProduct.getUnit());
            qualityInspect.setQuantity(saleProduct.getQuantity());
            qualityInspectMapper.insert(qualityInspect);
            List<QualityTestStandardParam> qualityTestStandardParams = qualityTestStandardParamMapper.selectListByProductId(saleProduct.getProductId());
            if (qualityTestStandardParams.size()>0) {
                qualityTestStandardParams.forEach(standard -> {
                    QualityInspectParam param = new QualityInspectParam();
                    com.ruoyi.common.utils.bean.BeanUtils.copyProperties(standard, param);
                    param.setId(null);
                    param.setInspectId(qualityInspect.getId());
                    qualityInspectParamMapper.insert(param);
                });
            //是否推送质检,如果true就添加
            if (saleProduct.getIsChecked()) {
                addQualityInspect(purchaseLedger, saleProduct);
            }
        }
        // 5. è¿ç§»ä¸´æ—¶æ–‡ä»¶åˆ°æ­£å¼ç›®å½•
        if (purchaseLedgerDto.getTempFileIds() != null && !purchaseLedgerDto.getTempFileIds().isEmpty()) {
            migrateTempFilesToFormal(purchaseLedger.getId(), purchaseLedgerDto.getTempFileIds());
        }
        return 1;
    }
    private void addQualityInspect(PurchaseLedger purchaseLedger, SalesLedgerProduct saleProduct) {
        QualityInspect qualityInspect = new QualityInspect();
        qualityInspect.setInspectType(0);
        qualityInspect.setSupplier(purchaseLedger.getSupplierName());
        qualityInspect.setPurchaseLedgerId(purchaseLedger.getId());
        qualityInspect.setProductId(saleProduct.getId());
        qualityInspect.setProductName(saleProduct.getProductCategory());
        qualityInspect.setModel(saleProduct.getSpecificationModel());
        qualityInspect.setProductModelId(saleProduct.getProductModelId());
        qualityInspect.setUnit(saleProduct.getUnit());
        qualityInspect.setQuantity(saleProduct.getQuantity());
        qualityInspectMapper.insert(qualityInspect);
        QualityTestStandard qualityTestStandard = new QualityTestStandard();
        qualityTestStandard.setProductId(saleProduct.getProductId());
        List<QualityTestStandard> qualityTestStandards = qualityTestStandardMapper.qualityTestStandardList(qualityTestStandard);
        for (QualityTestStandard qualityTestStandardDB : qualityTestStandards) {
            QualityInspectParam qualityInspectParam = new QualityInspectParam();
            qualityInspectParam.setInspectId(qualityInspect.getId());
            qualityInspectParam.setParameterItem(qualityTestStandardDB.getParameterItem());
            qualityInspectParam.setUnit(qualityTestStandardDB.getUnit());
            qualityInspectParam.setStandardValue(qualityTestStandardDB.getStandardValue());
            qualityInspectParam.setControlValue(qualityTestStandardDB.getControlValue());
            qualityInspectParamMapper.insert(qualityInspectParam);
        }
    }
        // 5. è¿ç§»ä¸´æ—¶æ–‡ä»¶åˆ°æ­£å¼ç›®å½•
        if (purchaseLedgerDto.getTempFileIds() != null && !purchaseLedgerDto.getTempFileIds().isEmpty()) {
@@ -304,6 +319,8 @@
                LocalDateTime localDateTime = entryDate.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
                salesLedgerProduct.setRegisterDate(localDateTime);
                salesLedgerProduct.setFutureTickets(salesLedgerProduct.getQuantity());
                salesLedgerProduct.setFutureTicketsAmount(salesLedgerProduct.getTaxInclusiveTotalPrice());
                salesLedgerProduct.setPendingTicketsTotal(salesLedgerProduct.getTaxInclusiveTotalPrice());
                salesLedgerProductMapper.insert(salesLedgerProduct);
            }
@@ -397,6 +414,7 @@
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deletePurchaseLedgerByIds(Long[] ids) {
        if (ids == null || ids.length == 0) {
           throw new BaseException("请选中至少一条数据");
@@ -408,7 +426,7 @@
        salesLedgerProductMapper.delete(queryWrapper);
        // æ‰¹é‡åˆ é™¤å…³è”的采购台账的来票登记
        LambdaQueryWrapper<TicketRegistration> ticketRegistrationLambdaQueryWrapper = new LambdaQueryWrapper<>();
        ticketRegistrationLambdaQueryWrapper.in(TicketRegistration::getSalesLedgerId,ids);
        ticketRegistrationLambdaQueryWrapper.in(TicketRegistration::getPurchaseLedgerId,ids);
        ticketRegistrationMapper.delete(ticketRegistrationLambdaQueryWrapper);
        // æ‰¹é‡åˆ é™¤å…³è”的采购台账的来票登记记录
        LambdaQueryWrapper<ProductRecord> productRecordLambdaQueryWrapper = new LambdaQueryWrapper<>();
@@ -422,6 +440,11 @@
        LambdaQueryWrapper<QualityInspect> materialInspectLambdaQueryWrapper = new LambdaQueryWrapper<>();
        materialInspectLambdaQueryWrapper.in(QualityInspect::getPurchaseLedgerId, ids);
        List<QualityInspect> qualityInspects = qualityInspectMapper.selectList(materialInspectLambdaQueryWrapper);
        qualityInspects.stream().forEach(qualityInspect -> {
            if (ObjectUtils.isNotEmpty(qualityInspect.getInspectState())&&qualityInspect.getInspectState().equals(1)) {
                throw new BaseException("已提交的检验单不能删除");
            }
        });
        List<Long> inspectIds = qualityInspects.stream()
                .map(QualityInspect::getId)
                .collect(Collectors.toList());
src/main/java/com/ruoyi/quality/service/impl/QualityInspectServiceImpl.java
@@ -146,7 +146,7 @@
            procurementRecordOutAdd.setDetails(details);
            ProcurementRecordStorage.ProcurementRecordStorageBuilder procurementRecordBuilder = ProcurementRecordStorage.builder()
                    .salesLedgerProductId(details1.getId())
                    .salesLedgerProductId(0)
                    .inboundBatches( "生产半成品入库")
                    .inboundNum(details1.getInboundQuantity())
                    .type(2)
@@ -173,7 +173,7 @@
            List<Details> details = new ArrayList<>();
            Details details1 = new Details();
            details1.setInboundQuantity(qualityInspect.getQuantity());
            details1.setId(Math.toIntExact(salesLedgerProduct.getProductId()));
            details1.setId(Math.toIntExact(salesLedgerProduct.getId()));
            details1.setUnitPrice(salesLedgerProduct.getTaxInclusiveUnitPrice());
            details1.setTotalPrice(salesLedgerProduct.getTaxInclusiveTotalPrice());
            details1.setProductModelId(salesLedgerProduct.getProductModelId());
src/main/java/com/ruoyi/sales/controller/SalesLedgerProductController.java
@@ -8,6 +8,7 @@
import com.ruoyi.procurementrecord.dto.ProcurementPageDto;
import com.ruoyi.procurementrecord.dto.ProcurementPageDtoCopy;
import com.ruoyi.procurementrecord.service.ProcurementRecordService;
import com.ruoyi.procurementrecord.utils.StockUtils;
import com.ruoyi.sales.dto.SalesLedgerProductDto;
import com.ruoyi.sales.pojo.SalesLedgerProduct;
import com.ruoyi.sales.service.ISalesLedgerProductService;
@@ -25,11 +26,12 @@
import com.ruoyi.framework.web.domain.AjaxResult;
import com.ruoyi.framework.web.page.TableDataInfo;
import java.math.BigDecimal;
import java.util.List;
/**
 * äº§å“ä¿¡æ¯Controller
 *
 *
 * @author ruoyi
 * @date 2025-05-08
 */
@@ -41,6 +43,8 @@
    private ISalesLedgerProductService salesLedgerProductService;
    @Autowired
    private ProcurementRecordService procurementRecordService;
    @Autowired
    private StockUtils stockUtils;
    /**
@@ -71,13 +75,20 @@
    {
        List<SalesLedgerProduct> list = salesLedgerProductService.selectSalesLedgerProductList(salesLedgerProduct);
        list.forEach(item -> {
            ProcurementPageDto procurementDto = new ProcurementPageDto();
            procurementDto.setSalesLedgerProductId(item.getId());
            procurementDto.setProductCategory(item.getProductCategory());
            IPage<ProcurementPageDtoCopy> result = procurementRecordService.listPageCopyByProduction(new Page<>(1,-1), procurementDto);
            if(result.getRecords().size()>0) {
                ProcurementPageDtoCopy procurementDtoCopy = result.getRecords().get(0);
                if (item.getQuantity().compareTo(procurementDtoCopy.getInboundNum0()) >= 0 && item.getApproveStatus() == 0) {
                if (item.getFutureTickets().compareTo(BigDecimal.ZERO) == 0) {
                    item.setFutureTickets(item.getQuantity());
                }
            if (item.getFutureTicketsAmount().compareTo(BigDecimal.ZERO) == 0) {
                item.setFutureTicketsAmount(item.getTaxInclusiveTotalPrice());
            }
//            ProcurementPageDto procurementDto = new ProcurementPageDto();
//            procurementDto.setSalesLedgerProductId(item.getId());
//            procurementDto.setProductCategory(item.getProductCategory());
//            IPage<ProcurementPageDtoCopy> result = procurementRecordService.listPageCopyByProduction(new Page<>(1,-1), procurementDto);
            BigDecimal stockQuantity = stockUtils.getStockQuantity(item.getProductModelId()).get("stockQuantity");
            if(stockQuantity != null) {
//                ProcurementPageDtoCopy procurementDtoCopy = result.getRecords().get(0);
                if (item.getQuantity().compareTo(stockQuantity) >= 0 && item.getApproveStatus() == 0) {
                    item.setApproveStatus(1);
                    salesLedgerProductService.addOrUpdateSalesLedgerProduct(item);
                }
src/main/java/com/ruoyi/sales/controller/ShipmentApprovalController.java
@@ -3,6 +3,8 @@
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.math.LongMath;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.web.controller.BaseController;
import com.ruoyi.framework.web.domain.AjaxResult;
@@ -60,41 +62,60 @@
    @ApiOperation("发货审批,更新发货审批状态")
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult update(@RequestBody ShipmentApproval req) {
        //  æŸ¥è¯¢å‘货审批
        ShipmentApproval shipmentApproval = shipmentApprovalMapper.selectById(req.getId());
        if (shipmentApproval == null) {
            return AjaxResult.error("发货审批不存在");
        }
        //  æ›´æ–°å‘货审批状态
        shipmentApproval.setApproveStatus(req.getApproveStatus());
        boolean update = shipmentApprovalService.updateById(shipmentApproval);
        if(update){
            SalesLedgerProduct salesLedgerProduct = salesLedgerProductService.getById(shipmentApproval.getSalesLedgerProductId());
            salesLedgerProduct.setApproveStatus(req.getApproveStatus());
            salesLedgerProductService.updateById(salesLedgerProduct);
            if(req.getApproveStatus()==3){
                ProcurementRecordStorage procurementRecordStorage = procurementRecordStorageService.getOne(new LambdaQueryWrapper<ProcurementRecordStorage>()
                        .eq(ProcurementRecordStorage::getSalesLedgerProductId, req.getSalesLedgerProductId()));
                if(procurementRecordStorage==null){
                    return AjaxResult.error("采购记录不存在");
                }
                //发货审批通过,生产该订单出库记录
                ProcurementRecordOutAdd procurementRecordOutAdd = new ProcurementRecordOutAdd();
                procurementRecordOutAdd.setId(procurementRecordStorage.getId());
                procurementRecordOutAdd.setSalesLedgerProductId(Math.toIntExact(salesLedgerProduct.getId()));
                procurementRecordOutAdd.setType(2);
                procurementRecordOutAdd.setUserId(Math.toIntExact(getUserId()));
                procurementRecordOutAdd.setQuantity(String.valueOf(salesLedgerProduct.getQuantity()));
                //获取当前时间
                LocalDate now = LocalDate.now();
                procurementRecordOutAdd.setTime(now.toString());
                procurementRecordOutService.stockout(procurementRecordOutAdd);
            }
        if (!update) {
            //  äº‹åŠ¡å›žæ»š
            throw new ServiceException("发货审批更新失败");
        }
        return update ? AjaxResult.success() : AjaxResult.error();
        //  æŸ¥è¯¢å…³è”的销售台账产品
        SalesLedgerProduct salesLedgerProduct = salesLedgerProductService.getById(shipmentApproval.getSalesLedgerProductId());
        if (salesLedgerProduct == null) {
            //  æŠ›å¼‚常事务回滚
            throw new ServiceException("销售台账不存在,审批回滚");
        }
        //  åŒæ­¥æ›´æ–°é”€å”®å°è´¦äº§å“çš„审批状态
        salesLedgerProduct.setApproveStatus(req.getApproveStatus());
        salesLedgerProductService.updateById(salesLedgerProduct);
        //  å®¡æ‰¹é€šè¿‡
        if (req.getApproveStatus() == 3) {
            // æŸ¥è¯¢é‡‡è´­å…¥åº“记录
            LambdaQueryWrapper<ProcurementRecordStorage> lambdaQueryWrapper = new LambdaQueryWrapper<ProcurementRecordStorage>()
                    .eq(ProcurementRecordStorage::getSalesLedgerProductId, req.getSalesLedgerProductId());
            ProcurementRecordStorage procurementRecordStorage = procurementRecordStorageService.getOne(lambdaQueryWrapper);
            if (procurementRecordStorage == null) {
                // ä¿è¯å‰é¢çš„修改全部回滚
                throw new ServiceException("采购记录不存在,审批回滚");
            }
            //  ç”Ÿæˆå‡ºåº“记录
            ProcurementRecordOutAdd procurementRecordOutAdd = new ProcurementRecordOutAdd();
            procurementRecordOutAdd.setId(procurementRecordStorage.getId());
            procurementRecordOutAdd.setSalesLedgerProductId((long) Math.toIntExact(salesLedgerProduct.getId()));
            procurementRecordOutAdd.setType(2);
            procurementRecordOutAdd.setUserId(Math.toIntExact(getUserId()));
            procurementRecordOutAdd.setQuantity(salesLedgerProduct.getQuantity().toPlainString());
            procurementRecordOutAdd.setTime(LocalDate.now().toString());
            procurementRecordOutService.stockout(procurementRecordOutAdd);
        }
        return AjaxResult.success();
    }
    /**
     * å¯¼å‡ºå‘货信息管理
     */
src/main/java/com/ruoyi/sales/pojo/SalesLedgerProduct.java
@@ -111,22 +111,22 @@
    /**
     * æœ¬æ¬¡æ¥ç¥¨æ•°
     */
    private BigDecimal ticketsNum;
    private BigDecimal ticketsNum=BigDecimal.ZERO;
    /**
     * æœ¬æ¬¡æ¥ç¥¨é‡‘额(元)
     */
    private BigDecimal ticketsAmount;
    private BigDecimal ticketsAmount=BigDecimal.ZERO;
    /**
     * æœªæ¥ç¥¨æ•°
     */
    private BigDecimal futureTickets;
    private BigDecimal futureTickets=BigDecimal.ZERO;
    /**
     * æœªæ¥ç¥¨é‡‘额(元)
     */
    private BigDecimal futureTicketsAmount;
    private BigDecimal futureTicketsAmount=BigDecimal.ZERO;
    @ApiModelProperty(value = "开票数")
    private BigDecimal invoiceNum;
@@ -221,4 +221,7 @@
    @ApiModelProperty(value = "付款总金额")
    private BigDecimal ticketsTotal = BigDecimal.ZERO;
    @ApiModelProperty(value = "是否质检")
    private Boolean isChecked;
}
src/main/java/com/ruoyi/sales/service/impl/InvoiceLedgerServiceImpl.java
@@ -381,55 +381,71 @@
    /**
     * å¤„理当月开票台账删除
     *
     * @param invoiceRegistrationProductId
     * @param invoiceRegistrationProduct
     */
    private void dealCurrentMonthDel(Integer invoiceRegistrationProductId,InvoiceRegistrationProduct invoiceRegistrationProduct){
    private void dealCurrentMonthDel(Integer invoiceRegistrationProductId, InvoiceRegistrationProduct invoiceRegistrationProduct) {
        // åˆ é™¤å¼€ç¥¨å°è´¦
        QueryWrapper<InvoiceLedger> delMapper = new QueryWrapper<>();
        delMapper.eq("invoice_registration_product_id", invoiceRegistrationProductId);
        invoiceLedgerMapper.delete(delMapper);
        // åˆ é™¤å¼€ç¥¨ç™»è®°å¹¶å›žæ»š
        QueryWrapper<InvoiceLedger> delLedgerWrapper = new QueryWrapper<>();
        delLedgerWrapper.eq("invoice_registration_product_id", invoiceRegistrationProductId);
        invoiceLedgerMapper.delete(delLedgerWrapper);
        // æŸ¥è¯¢å½“前产品下的所有开票登记
        QueryWrapper<InvoiceRegistrationProduct> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("sales_ledger_id", invoiceRegistrationProduct.getSalesLedgerId());
        queryWrapper.eq("sales_ledger_product_id", invoiceRegistrationProduct.getSalesLedgerProductId());
        queryWrapper.orderByAsc("create_time");
        List<InvoiceRegistrationProduct> invoiceRegistrationProductList = invoiceRegistrationProductMapper.selectList(queryWrapper);
//        InvoiceRegistrationProduct invoiceRegistrationProduct = invoiceRegistrationProductMapper.selectById(invoiceRegistrationProductId);
        int index =  -1;
        for (int i = 0; i < invoiceRegistrationProductList.size(); i++) {
            InvoiceRegistrationProduct currentInvoiceRegProduct = invoiceRegistrationProductList.get(i);
            if(invoiceRegistrationProduct.getId().equals(currentInvoiceRegProduct.getId())){
        List<InvoiceRegistrationProduct> allList = invoiceRegistrationProductMapper.selectList(queryWrapper);
        int index = -1;
        for (int i = 0; i < allList.size(); i++) {
            if (invoiceRegistrationProductId.equals(allList.get(i).getId())) {
                index = i;
                break;
            }
        }
        if(index == -1){
        if (index == -1) {
            return;
        }
        for (int i = index + 1; i < invoiceRegistrationProductList.size(); i++) {
            InvoiceRegistrationProduct currentInvoiceRegProduct = invoiceRegistrationProductList.get(i);
            // å›žæ»šæœªå¼€ç¥¨æ•°/未开票金额
            BigDecimal noInvoiceAmount = currentInvoiceRegProduct.getNoInvoiceAmount().add(invoiceRegistrationProduct.getInvoiceAmount());
            BigDecimal noInvoiceNum = currentInvoiceRegProduct.getNoInvoiceNum().add(invoiceRegistrationProduct.getInvoiceNum());
            currentInvoiceRegProduct.setNoInvoiceAmount(noInvoiceAmount);
            currentInvoiceRegProduct.setNoInvoiceNum(noInvoiceNum);
            invoiceRegistrationProductMapper.updateById(currentInvoiceRegProduct);
        for (int i = index + 1; i < allList.size(); i++) {
            InvoiceRegistrationProduct current = allList.get(i);
            current.setNoInvoiceNum(current.getNoInvoiceNum().add(invoiceRegistrationProduct.getInvoiceNum()));
            current.setNoInvoiceAmount(current.getNoInvoiceAmount().add(invoiceRegistrationProduct.getInvoiceAmount()));
            invoiceRegistrationProductMapper.updateById(current);
        }
        // åˆ é™¤å½“前开票登记
        invoiceRegistrationProductMapper.deleteById(invoiceRegistrationProductId);
        // ä¿®æ”¹sale_product数据
        SalesLedgerProduct salesLedgerProduct = salesLedgerProductMapper.selectById(invoiceRegistrationProduct.getSalesLedgerProductId());
        // æŸ¥è¯¢åˆ é™¤åŽçš„剩余开票登记
        QueryWrapper<InvoiceRegistrationProduct> newQueryWrapper = new QueryWrapper<>();
        queryWrapper.eq("sales_ledger_id", invoiceRegistrationProduct.getSalesLedgerId());
        queryWrapper.eq("sales_ledger_product_id", invoiceRegistrationProduct.getSalesLedgerProductId());
        queryWrapper.orderByAsc("create_time");
        List<InvoiceRegistrationProduct> newInvoiceRegistrationProductList = invoiceRegistrationProductMapper.selectList(newQueryWrapper);
        if(CollectionUtils.isEmpty(newInvoiceRegistrationProductList)){
        newQueryWrapper.eq("sales_ledger_id", invoiceRegistrationProduct.getSalesLedgerId());
        newQueryWrapper.eq("sales_ledger_product_id", invoiceRegistrationProduct.getSalesLedgerProductId());
        newQueryWrapper.orderByAsc("create_time");
        List<InvoiceRegistrationProduct> remainList = invoiceRegistrationProductMapper.selectList(newQueryWrapper);
        // æŸ¥è¯¢é”€å”®å°è´¦äº§å“
        SalesLedgerProduct salesLedgerProduct = salesLedgerProductMapper.selectById(invoiceRegistrationProduct.getSalesLedgerProductId());
        if (CollectionUtils.isEmpty(remainList)) {
            // æ²¡æœ‰ä»»ä½•开票记录,恢复初始状态
            salesLedgerProduct.setInvoiceNum(BigDecimal.ZERO);
            salesLedgerProduct.setInvoiceAmount(BigDecimal.ZERO);
            salesLedgerProduct.setNoInvoiceNum(salesLedgerProduct.getQuantity());
            salesLedgerProduct.setNoInvoiceAmount(salesLedgerProduct.getTaxInclusiveTotalPrice());
        }else {
        } else {
            salesLedgerProduct.setInvoiceNum(salesLedgerProduct.getInvoiceNum().subtract(invoiceRegistrationProduct.getInvoiceNum()));
            salesLedgerProduct.setInvoiceAmount(salesLedgerProduct.getInvoiceAmount().subtract(invoiceRegistrationProduct.getInvoiceAmount()));
            salesLedgerProduct.setNoInvoiceNum(salesLedgerProduct.getNoInvoiceNum().add(invoiceRegistrationProduct.getInvoiceNum()));
            salesLedgerProduct.setNoInvoiceAmount(salesLedgerProduct.getNoInvoiceAmount().add(invoiceRegistrationProduct.getInvoiceAmount()));
        }
        salesLedgerProductMapper.updateById(salesLedgerProduct);
    }
@@ -438,46 +454,59 @@
     * @param invoiceRegistrationProduct
     * @param invoiceLedger
     */
    private void dealOtherMonthDel(InvoiceRegistrationProduct invoiceRegistrationProduct,InvoiceLedger invoiceLedger ){
        InvoiceRegistrationProduct copyRegProduct = new InvoiceRegistrationProduct();
        BeanUtils.copyProperties(invoiceRegistrationProduct, copyRegProduct);
        BigDecimal invoiceNum = copyRegProduct.getInvoiceNum().negate();
        BigDecimal invoiceAmount = copyRegProduct.getInvoiceAmount().negate();
        // invoice_registration_product
        // åˆ é™¤å¼€ç¥¨ç™»è®°å¹¶å›žæ»š
    private void dealOtherMonthDel(InvoiceRegistrationProduct invoiceRegistrationProduct, InvoiceLedger invoiceLedger) {
        //查询历史开票登记
        QueryWrapper<InvoiceRegistrationProduct> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("sales_ledger_id", invoiceRegistrationProduct.getSalesLedgerId());
        queryWrapper.eq("sales_ledger_product_id", invoiceRegistrationProduct.getSalesLedgerProductId());
        queryWrapper.orderByAsc("create_time");
        List<InvoiceRegistrationProduct> invoiceRegistrationProductList = invoiceRegistrationProductMapper.selectList(queryWrapper);
        InvoiceRegistrationProduct lastInvoiceRegistrationProduct = invoiceRegistrationProductList.get(invoiceRegistrationProductList.size() - 1);
        BigDecimal noInvoiceNum = lastInvoiceRegistrationProduct.getNoInvoiceNum().subtract(invoiceNum);
        BigDecimal noInvoiceAmount = lastInvoiceRegistrationProduct.getNoInvoiceAmount().subtract(invoiceAmount);
        copyRegProduct.setInvoiceNum(invoiceNum);
        copyRegProduct.setInvoiceAmount(invoiceAmount);
        copyRegProduct.setNoInvoiceNum(noInvoiceNum);
        copyRegProduct.setNoInvoiceAmount(noInvoiceAmount);
        copyRegProduct.setId(null);
        invoiceRegistrationProductMapper.insert(copyRegProduct);
        List<InvoiceRegistrationProduct> list = invoiceRegistrationProductMapper.selectList(queryWrapper);
        if (CollectionUtils.isEmpty(list)) {
            return;
        }
        InvoiceRegistrationProduct last = list.get(list.size() - 1);
        BigDecimal negateInvoiceNum = invoiceRegistrationProduct.getInvoiceNum().negate();
        BigDecimal negateInvoiceAmount = invoiceRegistrationProduct.getInvoiceAmount().negate();
        InvoiceRegistrationProduct copy = new InvoiceRegistrationProduct();
        BeanUtils.copyProperties(invoiceRegistrationProduct, copy);
        copy.setId(null);
        copy.setInvoiceNum(negateInvoiceNum);
        copy.setInvoiceAmount(negateInvoiceAmount);
        // æœªå¼€ç¥¨ = ä¸Šä¸€æ¡ + æœ¬æ¬¡å†²å›žçš„æ•°é‡
        copy.setNoInvoiceNum(last.getNoInvoiceNum().add(invoiceRegistrationProduct.getInvoiceNum()));
        copy.setNoInvoiceAmount(last.getNoInvoiceAmount().add(invoiceRegistrationProduct.getInvoiceAmount()));
        invoiceRegistrationProductMapper.insert(copy);
        // å¤åˆ¶å¼€ç¥¨å°è´¦
        InvoiceLedger invoiceLedgerCopy = new InvoiceLedger();
        BeanUtils.copyProperties(invoiceLedger, invoiceLedgerCopy);
        invoiceLedgerCopy.setInvoiceRegistrationProductId(copyRegProduct.getId());
        BigDecimal invoiceTotal = invoiceLedgerCopy.getInvoiceTotal().negate();
        invoiceLedgerCopy.setInvoiceTotal(invoiceTotal);
        invoiceLedgerCopy.setId(null);
        invoiceLedgerCopy.setInvoiceDate(LocalDate.now());
        invoiceLedgerMapper.insert(invoiceLedgerCopy);
        // æ›´æ–°sales_leger_product
        QueryWrapper<SalesLedgerProduct> salesLedgerProductQueryWrapper = new QueryWrapper<>();
        salesLedgerProductQueryWrapper.eq("id", invoiceRegistrationProduct.getSalesLedgerProductId());
        SalesLedgerProduct salesLedgerProduct = salesLedgerProductMapper.selectOne(salesLedgerProductQueryWrapper);
        salesLedgerProduct.setNoInvoiceNum(noInvoiceNum);
        salesLedgerProduct.setNoInvoiceAmount(noInvoiceAmount);
        BigDecimal newInvoiceNum = salesLedgerProduct.getInvoiceNum().add(invoiceNum);
        BigDecimal newInvocieAmount = salesLedgerProduct.getInvoiceAmount().add(invoiceAmount);
        salesLedgerProduct.setInvoiceNum(newInvoiceNum);
        salesLedgerProduct.setInvoiceAmount(newInvocieAmount);
        InvoiceLedger ledgerCopy = new InvoiceLedger();
        BeanUtils.copyProperties(invoiceLedger, ledgerCopy);
        ledgerCopy.setId(null);
        ledgerCopy.setInvoiceRegistrationProductId(copy.getId());
        ledgerCopy.setInvoiceTotal(invoiceLedger.getInvoiceTotal().negate());
        ledgerCopy.setInvoiceDate(LocalDate.now());
        invoiceLedgerMapper.insert(ledgerCopy);
        // å›žæ»š sales_ledger_product
        SalesLedgerProduct salesLedgerProduct = salesLedgerProductMapper.selectById(invoiceRegistrationProduct.getSalesLedgerProductId());
        // å·²å¼€ç¥¨
        salesLedgerProduct.setInvoiceNum(salesLedgerProduct.getInvoiceNum().add(negateInvoiceNum));
        salesLedgerProduct.setInvoiceAmount(salesLedgerProduct.getInvoiceAmount().add(negateInvoiceAmount));
        // æœªå¼€ç¥¨
        salesLedgerProduct.setNoInvoiceNum(salesLedgerProduct.getNoInvoiceNum().add(invoiceRegistrationProduct.getInvoiceNum()));
        salesLedgerProduct.setNoInvoiceAmount(salesLedgerProduct.getNoInvoiceAmount().add(invoiceRegistrationProduct.getInvoiceAmount()));
        salesLedgerProductMapper.updateById(salesLedgerProduct);
    }
}
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java
@@ -59,6 +59,7 @@
    private InvoiceRegistrationProductMapper invoiceRegistrationProductMapper;
    private ProcessRouteMapper processRouteMapper;
    private ProductProcessRouteMapper productProcessRouteMapper;
    private ProductWorkOrderMapper productWorkOrderMapper;
@@ -140,7 +141,7 @@
            // æ‰¹é‡æŸ¥è¯¢processRouteItems
            List<ProductProcessRouteItem> allRouteItems = productProcessRouteItemMapper.selectList(
                    new LambdaQueryWrapper<ProductProcessRouteItem>()
                            .in(ProductProcessRouteItem::getRouteId, orderIds)
                            .in(ProductProcessRouteItem::getProductOrderId, orderIds)
            );
            if (!CollectionUtils.isEmpty(allRouteItems)) {
@@ -153,9 +154,13 @@
                                .in(ProductWorkOrder::getProductProcessRouteItemId, routeItemIds));
            }
            // æ‰¹é‡åˆ é™¤processRouteItem
            // æ‰¹é‡åˆ é™¤productProcessRouteItem
            productProcessRouteItemMapper.delete(new LambdaQueryWrapper<ProductProcessRouteItem>()
                            .in(ProductProcessRouteItem::getRouteId, orderIds));
                            .in(ProductProcessRouteItem::getProductOrderId, orderIds));
            // æ‰¹é‡åˆ é™¤productProcessRoute
            productProcessRouteMapper.delete(new LambdaQueryWrapper<ProductProcessRoute>()
                    .in(ProductProcessRoute::getProductOrderId, orderIds));
            // æ‰¹é‡åˆ é™¤productOrder
            productOrderMapper.delete(new LambdaQueryWrapper<ProductOrder>()
@@ -204,10 +209,20 @@
            productOrder.setSalesLedgerId(salesLedgerProduct.getSalesLedgerId());
            productOrder.setProductModelId(salesLedgerProduct.getId());
            productOrder.setNpsNo("SC" + String.format("%08d", salesLedgerProduct.getId()));
            productOrder.setQuantity(salesLedgerProduct.getQuantity());//需求数量
            productOrder.setCompleteQuantity(BigDecimal.ZERO);//完成数量
            productOrderMapper.insert(productOrder);
            ProcessRoute processRoute = processRouteMapper.selectOne(new QueryWrapper<ProcessRoute>().lambda().eq(ProcessRoute::getProductModelId, salesLedgerProduct.getProductModelId()));
            if (processRoute != null) {
                //新增生产订单工艺路线主表
                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"));
@@ -215,7 +230,8 @@
                    ProductProcessRouteItem productProcessRouteItem = new ProductProcessRouteItem();
                    productProcessRouteItem.setProductModelId(processRouteItem.getProductModelId());
                    productProcessRouteItem.setProcessId(processRouteItem.getProcessId());
                    productProcessRouteItem.setRouteId(productOrder.getId());
                    productProcessRouteItem.setProductOrderId(productOrder.getId());
                    productProcessRouteItem.setProductRouteId(productProcessRoute.getId());
                    int insert = productProcessRouteItemMapper.insert(productProcessRouteItem);
                    if (insert > 0) {
                        // æŸ¥è¯¢ä»Šæ—¥å·²å­˜åœ¨çš„æœ€å¤§å·¥å•号
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
@@ -12,13 +12,16 @@
import com.ruoyi.account.pojo.AccountIncome;
import com.ruoyi.account.service.AccountIncomeService;
import com.ruoyi.basic.mapper.CustomerMapper;
import com.ruoyi.basic.mapper.ProductModelMapper;
import com.ruoyi.basic.pojo.Customer;
import com.ruoyi.basic.pojo.ProductModel;
import com.ruoyi.common.enums.FileNameType;
import com.ruoyi.common.exception.base.BaseException;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.other.mapper.TempFileMapper;
import com.ruoyi.other.pojo.TempFile;
import com.ruoyi.production.dto.ProductStructureDto;
import com.ruoyi.production.mapper.*;
import com.ruoyi.production.pojo.*;
import com.ruoyi.project.system.domain.SysDept;
@@ -96,6 +99,7 @@
    private final ProductOrderMapper productOrderMapper;
    private final ProcessRouteMapper processRouteMapper;
    private final ProductProcessRouteMapper productProcessRouteMapper;
    private final ProcessRouteItemMapper processRouteItemMapper;
@@ -122,6 +126,10 @@
    private static final long LOCK_EXPIRE_TIME = 30;  // é”è‡ªåŠ¨è¿‡æœŸæ—¶é—´ï¼ˆç§’ï¼‰
    private final RedisTemplate<String, String> redisTemplate;
    @Autowired
    private ProductModelMapper productModelMapper;
    @Autowired
    private ProductStructureMapper productStructureMapper;
    @Override
    public List<SalesLedger> selectSalesLedgerList(SalesLedgerDto salesLedgerDto) {
@@ -400,7 +408,7 @@
            // æ‰¹é‡æŸ¥è¯¢processRouteItems
            List<ProductProcessRouteItem> allRouteItems = productProcessRouteItemMapper.selectList(
                    new LambdaQueryWrapper<ProductProcessRouteItem>()
                            .in(ProductProcessRouteItem::getRouteId, orderIds)
                            .in(ProductProcessRouteItem::getProductOrderId, orderIds)
            );
            if (!CollectionUtils.isEmpty(allRouteItems)) {
@@ -455,7 +463,11 @@
            }
            // æ‰¹é‡åˆ é™¤processRouteItem
            productProcessRouteItemMapper.delete(new LambdaQueryWrapper<ProductProcessRouteItem>()
                    .in(ProductProcessRouteItem::getRouteId, orderIds));
                    .in(ProductProcessRouteItem::getProductOrderId, orderIds));
            // æ‰¹é‡åˆ é™¤productProcessRoute
            productProcessRouteMapper.delete(new LambdaQueryWrapper<ProductProcessRoute>()
                    .in(ProductProcessRoute::getProductOrderId, orderIds));
            // æ‰¹é‡åˆ é™¤productOrder
            productOrderMapper.delete(new LambdaQueryWrapper<ProductOrder>()
@@ -687,20 +699,31 @@
                productOrder.setSalesLedgerId(salesLedgerProduct.getSalesLedgerId());
                productOrder.setProductModelId(salesLedgerProduct.getId());
                productOrder.setNpsNo("SC" + String.format("%08d", salesLedgerProduct.getId()));
                productOrder.setQuantity(salesLedgerProduct.getQuantity());//需求数量
                productOrder.setCompleteQuantity(BigDecimal.ZERO);//完成数量
                productOrderMapper.insert(productOrder);
                ProcessRoute processRoute = processRouteMapper.selectOne(new QueryWrapper<ProcessRoute>().lambda().eq(ProcessRoute::getProductModelId, salesLedgerProduct.getProductModelId()));
                List<ProductStructureDto> productStructureDtos = productStructureMapper.listBybomId(processRoute.getBomId());
                if (processRoute != null) {
                    //新增生产订单工艺路线主表
                    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"));
                    int dragSort = 1;
                    for (ProcessRouteItem processRouteItem : processRouteItems) {
                        ProductProcessRouteItem productProcessRouteItem = new ProductProcessRouteItem();
                        productProcessRouteItem.setProductModelId(processRouteItem.getProductModelId());
                        productProcessRouteItem.setProcessId(processRouteItem.getProcessId());
                        productProcessRouteItem.setRouteId(productOrder.getId());
                        productProcessRouteItem.setDragSort(dragSort);
                        productProcessRouteItem.setProductOrderId(productOrder.getId());
                        productProcessRouteItem.setProductRouteId(productProcessRoute.getId());
                        productProcessRouteItem.setDragSort(processRouteItem.getDragSort());
                        int insert = productProcessRouteItemMapper.insert(productProcessRouteItem);
                        if (insert > 0) {
                            // æŸ¥è¯¢ä»Šæ—¥å·²å­˜åœ¨çš„æœ€å¤§å·¥å•号
@@ -726,14 +749,20 @@
                            // ç”Ÿæˆå®Œæ•´çš„工单号
                            String workOrderNoStr = String.format("%s%03d", datePrefix, sequenceNumber);
                            ProductWorkOrder productWorkOrder = new ProductWorkOrder();
                            productStructureDtos.stream().forEach(productStructureDto -> {
                                if (productStructureDto.getProductModelId().equals(productProcessRouteItem.getProductModelId())){
                                    productWorkOrder.setPlanQuantity(productWorkOrder.getPlanQuantity());
                                }
                            });
                            if (Objects.equals(productProcessRouteItem.getProductModelId(), salesLedgerProduct.getProductModelId())) {
                                productWorkOrder.setPlanQuantity(salesLedgerProduct.getQuantity());
                            }
                            productWorkOrder.setProductProcessRouteItemId(productProcessRouteItem.getId());
                            productWorkOrder.setProductOrderId(productOrder.getId());
                            productWorkOrder.setPlanQuantity(salesLedgerProduct.getQuantity());
                            productWorkOrder.setWorkOrderNo(workOrderNoStr);
                            productWorkOrder.setStatus(1);
                            productWorkOrderMapper.insert(productWorkOrder);
                        }
                        dragSort++;
                    }
                    productOrder.setRouteId(processRoute.getId());
                    productOrderMapper.updateById(productOrder);
src/main/resources/mapper/procurementrecord/ProcurementRecordMapper.xml
@@ -261,7 +261,7 @@
        left join sales_ledger_product t2 on t2.id = t1.sales_ledger_product_id and t2.type = 1
        left join sales_ledger t3 on t3.id = t2.sales_ledger_id
        <where>
            t1.type = 2
            t1.type = 2 and t1.sales_ledger_product_id != 0
            <if test="req.customerName != null and req.customerName != ''">
                and t3.customer_name like  concat('%',#{req.customerName},'%')
            </if>
@@ -358,4 +358,25 @@
        from procurement_record_storage
        where product_model_id = #{productModelId}
    </select>
    <select id="listPageByProductProduction" resultType="com.ruoyi.procurementrecord.dto.ProcurementPageDto">
        select
        t1.*,
        t2.model as specification_model  ,
        t2.unit,
        t3.product_name as product_category
        from  procurement_record_storage t1
        left  join product_model t2 on t1.product_model_id = t2.id
        left join product t3 on t2.product_id = t3.id
        <where>
            t1.type = 2 and t1.sales_ledger_product_id  = 0
            <if test="req.productCategory != null and req.productCategory != ''">
                and t3.product_name like  concat('%',#{req.productCategory},'%')
            </if>
            <if test="req.timeStr != null and req.timeStr != ''">
                and t1.create_time like  concat('%',#{req.timeStr},'%')
            </if>
        </where>
        order by t1.create_time desc
    </select>
</mapper>
src/main/resources/mapper/procurementrecord/ProcurementRecordOutMapper.xml
@@ -19,85 +19,82 @@
        t1.create_by,
        t2.warn_num,
        t4.unit_price,
        t4.unit_price *  t1.inbound_num as totalPrice
        from  procurement_record_out t1
        t4.unit_price * t1.inbound_num as totalPrice
        from procurement_record_out t1
        left join sales_ledger_product t2 on t2.id = t1.sales_ledger_product_id and t2.type = 2
        left join purchase_ledger t3 on t3.id = t2.sales_ledger_id
        left join procurement_record_storage t4 on t4.id = t1.procurement_record_storage_id
        <where>
            and t1.type = 1
            <if test="req.supplierName != null and req.supplierName != ''">
                and t3.supplier_name like  concat('%',#{req.supplierName},'%')
                and t3.supplier_name like concat('%',#{req.supplierName},'%')
            </if>
            <if test="req.productCategory != null and req.productCategory != ''">
                and t2.product_category like  concat('%',#{req.productCategory},'%')
                and t2.product_category like concat('%',#{req.productCategory},'%')
            </if>
            <if test="req.timeStr != null and req.timeStr != ''">
                and t1.create_time like  concat('%',#{req.timeStr},'%')
                and t1.create_time like concat('%',#{req.timeStr},'%')
            </if>
        </where>
        order by t1.create_time desc
    </select>
    <select id="list" resultType="com.ruoyi.procurementrecord.dto.ProcurementRecordOutPageDto">
        select
            t3.supplier_name,
            t2.product_category,
            t1.id,
            t2.specification_model,
            t2.unit,
            t2.tax_rate,
            t2.tax_inclusive_unit_price,
            t2.tax_inclusive_total_price,
            t2.tax_exclusive_total_price,
            t1.inbound_num,
            t1.create_time,
            t1.create_time as time,
            t1.create_by
        from  procurement_record_out t1
                  left join sales_ledger_product t2 on t2.id = t1.sales_ledger_product_id
                  left join purchase_ledger t3 on t3.id = t2.sales_ledger_id
            where t1.type = 1
        select t3.supplier_name,
               t2.product_category,
               t1.id,
               t2.specification_model,
               t2.unit,
               t2.tax_rate,
               t2.tax_inclusive_unit_price,
               t2.tax_inclusive_total_price,
               t2.tax_exclusive_total_price,
               t1.inbound_num,
               t1.create_time,
               t1.create_time as time,
               t1.create_by
        from procurement_record_out t1
                 left join sales_ledger_product t2 on t2.id = t1.sales_ledger_product_id
                 left join purchase_ledger t3 on t3.id = t2.sales_ledger_id
        where t1.type = 1
    </select>
    <select id="listOne" resultType="com.ruoyi.procurementrecord.dto.ProcurementRecordOutPageDto">
        select
            t3.customer_contract_no,
            t3.sales_contract_no,
            t3.customer_name,
            t2.product_category,
            t1.id,
            t2.specification_model,
            t2.unit,
            t2.tax_rate,
            t2.tax_inclusive_unit_price,
            t2.tax_inclusive_total_price,
            t2.tax_exclusive_total_price,
            t1.inbound_num,
            t1.create_time,
            t1.create_time as time,
            t1.create_by
        from  procurement_record_out t1
            left join sales_ledger_product t2 on t2.id = t1.sales_ledger_product_id
            left join sales_ledger t3 on t3.id = t2.sales_ledger_id
        select t3.customer_contract_no,
               t3.sales_contract_no,
               t3.customer_name,
               t2.product_category,
               t1.id,
               t2.specification_model,
               t2.unit,
               t2.tax_rate,
               t2.tax_inclusive_unit_price,
               t2.tax_inclusive_total_price,
               t2.tax_exclusive_total_price,
               t1.inbound_num,
               t1.create_time,
               t1.create_time as time,
               t1.create_by
        from procurement_record_out t1
                 left join sales_ledger_product t2 on t2.id = t1.sales_ledger_product_id
                 left join sales_ledger t3 on t3.id = t2.sales_ledger_id
        where t1.type = 2
    </select>
    <select id="listTwo" resultType="com.ruoyi.procurementrecord.dto.ProcurementRecordOutPageDto">
        select
            t1.supplier_name,
            t1.product_category,
            t1.id,
            t1.specification_model,
            t1.unit,
            t1.tax_rate,
            t1.tax_inclusive_unit_price,
            t1.tax_inclusive_total_price,
            t1.tax_exclusive_total_price,
            t1.inbound_num,
            t1.create_time,
            t1.create_time as time,
            t1.create_by
        from  procurement_record_out t1
        select t1.supplier_name,
               t1.product_category,
               t1.id,
               t1.specification_model,
               t1.unit,
               t1.tax_rate,
               t1.tax_inclusive_unit_price,
               t1.tax_inclusive_total_price,
               t1.tax_exclusive_total_price,
               t1.inbound_num,
               t1.create_time,
               t1.create_time as time,
               t1.create_by
        from procurement_record_out t1
        where t1.type = 3
    </select>
    <select id="listPageByProduct" resultType="com.ruoyi.procurementrecord.dto.ProcurementRecordOutPageDto">
@@ -118,21 +115,21 @@
        t1.create_time,
        t1.create_by,
        t4.unit_price,
        t4.unit_price *  t1.inbound_num as totalPrice
        from  procurement_record_out t1
        t4.unit_price * t1.inbound_num as totalPrice
        from procurement_record_out t1
        left join sales_ledger_product t2 on t2.id = t1.sales_ledger_product_id and t2.type = 1
        left join sales_ledger t3 on t3.id = t2.sales_ledger_id
        left join procurement_record_storage t4 on t4.id = t1.procurement_record_storage_id
        <where>
            and t1.type = 2
            <if test="req.customerName != null and req.customerName != ''">
                and t3.customer_name like  concat('%',#{req.customerName},'%')
                and t3.customer_name like concat('%',#{req.customerName},'%')
            </if>
            <if test="req.productCategory != null and req.productCategory != ''">
                and t2.product_category like  concat('%',#{req.productCategory},'%')
                and t2.product_category like concat('%',#{req.productCategory},'%')
            </if>
            <if test="req.timeStr != null and req.timeStr != ''">
                and t1.create_time like  concat('%',#{req.timeStr},'%')
                and t1.create_time like concat('%',#{req.timeStr},'%')
            </if>
        </where>
        order by t1.create_time desc
@@ -153,18 +150,18 @@
        t1.create_by,
        t2.item_type,
        t2.code
        from  procurement_record_out t1
        from procurement_record_out t1
        left join custom_storage t2 on t2.id = t1.procurement_record_storage_id
        <where>
            t1.type = 3
            <if test="req.supplierName != null and req.supplierName != ''">
                and t2.supplier_name like  concat('%',#{req.supplierName},'%')
                and t2.supplier_name like concat('%',#{req.supplierName},'%')
            </if>
            <if test="req.productCategory != null and req.productCategory != ''">
                and t2.product_category like  concat('%',#{req.productCategory},'%')
                and t2.product_category like concat('%',#{req.productCategory},'%')
            </if>
            <if test="req.timeStr != null and req.timeStr != ''">
                and t1.create_time like  concat('%',#{req.timeStr},'%')
                and t1.create_time like concat('%',#{req.timeStr},'%')
            </if>
        </where>
        order by t1.create_time desc
@@ -173,7 +170,40 @@
    <select id="getSumQuantity" resultType="BigDecimal">
        select COALESCE(sum(inbound_num), 0)
        from procurement_record_out
        where type = 1
          and product_model_id = #{productModelId}
        where
           product_model_id = #{productModelId}
    </select>
    <select id="selectCode" resultType="com.ruoyi.procurementrecord.pojo.ProcurementRecordOut">
        select *
        from procurement_record_out
        where code like concat('%', #{format})
        order by id desc
        limit 1
    </select>
    <select id="listPageBySemiProduct" resultType="com.ruoyi.procurementrecord.dto.ProcurementRecordOutPageDto">
        select
        t1.id,
        t1.code,
        t2.unit,
        t1.inbound_num,
        t1.create_time,
        t1.create_by,
        t2.model as specification_model,
        t2.product_code,
        t3.product_name as product_category
        from procurement_record_out t1
        left join product_model t2 on t2.id = t1.product_model_id
        left join product t3 on t3.id = t2.product_id
        <where>
            and t1.type = 4
            <if test="req.productCategory !=null and req.productCategory !=''">
                t3.product_name like concat('%',#{req.productCategory},'%')
            </if>
            <if test="req.timeStr != null and req.timeStr != ''">
                and t1.create_time like concat('%',#{req.timeStr},'%')
            </if>
        </where>
        order by t1.create_time desc
    </select>
</mapper>
src/main/resources/mapper/production/ProcessRouteItemMapper.xml
@@ -10,6 +10,7 @@
        <result property="tenantId" column="tenant_id"/>
        <result property="createTime" column="create_time"/>
        <result property="updateTime" column="update_time"/>
        <result property="dragSort" column="drag_sort"/>
    </resultMap>
    <select id="listProcessRouteItemDto" resultType="com.ruoyi.production.dto.ProcessRouteItemDto">
@@ -29,6 +30,6 @@
                left join process_route pr on pr.id = pri.route_id
        where
            pri.route_id = #{c.routeId}
        order by pri.id
        order by pri.drag_sort
    </select>
</mapper>
src/main/resources/mapper/production/ProcessRouteMapper.xml
@@ -13,8 +13,9 @@
    </resultMap>
    <select id="pageProcessRouteDto" resultType="com.ruoyi.production.dto.ProcessRouteDto">
        select ps.*, p.product_name,pm.product_id,pm.model
        select ps.*, p.product_name,pm.product_id,pm.model,pb.bom_no
        from process_route ps
        left join product_bom pb on ps.bom_id = pb.id
        left join product_model pm on ps.product_model_id = pm.id
        left join product p on pm.product_id = p.id
        <where>
src/main/resources/mapper/production/ProductBomMapper.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.production.mapper.ProductBomMapper">
    <!-- é€šç”¨æŸ¥è¯¢æ˜ å°„结果 -->
    <resultMap id="BaseResultMap" type="com.ruoyi.production.pojo.ProductBom">
        <id column="id" property="id"/>
        <result column="product_model_id" property="productModelId"/>
        <result column="bom_no" property="bomNo"/>
        <result column="remark" property="remark"/>
        <result column="version" property="version"/>
        <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="tenant_id" property="tenantId"/>
    </resultMap>
    <select id="listPage" resultType="com.ruoyi.production.dto.ProductBomDto">
        select * from (select pb.*,
        pm.model productModelName,
        p.product_name productName
        from product_bom pb
        left join product_model pm on pb.product_model_id = pm.id
        left join product p on pm.product_id = p.id)A
        where 1=1
        <if test="c.productModelName != null">
            and productModelName = #{c.productModelName}
        </if>
        <if test="c.productName != null">
            and productName = #{c.productName}
        </if>
        <if test="c.bomNo != null">
            and bom_no = #{c.bomNo}
        </if>
        <if test="c.version != null">
            and version = #{c.version}
        </if>
    </select>
    <select id="getById" resultType="com.ruoyi.production.dto.ProductBomDto">
        select pb.*,
               pm.model productModelName,
               p.product_name productName
        from product_bom pb
                 left join product_model pm on pb.product_model_id = pm.id
                 left join product p on pm.product_id = p.id
    </select>
</mapper>
src/main/resources/mapper/production/ProductOrderMapper.xml
@@ -14,11 +14,19 @@
        <result property="updateTime" column="update_time"/>
    </resultMap>
    <select id="pageProductOrder" resultType="com.ruoyi.production.dto.ProductOrderDto">
        select po.*,sl.sales_contract_no,sl.customer_name,slp.product_category,slp.specification_model
        select po.*,
        sl.sales_contract_no,
        sl.customer_name,
        slp.product_category,
        slp.specification_model,
        ppr.process_route_code,
        pb.bom_no,
        ROUND(po.complete_quantity / po.quantity * 100, 2) AS completionStatus
        from product_order po
        left join sales_ledger sl on po.sales_ledger_id = sl.id
        left join sales_ledger_product slp on po.product_model_id = slp.id
        left join process_route pr on po.route_id = pr.id
        left join product_process_route ppr on po.id = ppr.product_order_id
        left join product_bom pb on pb.id = ppr.bom_id
        <where>
            <if test="c.npsNo != null and c.npsNo != ''">
                and po.nps_no like concat('%',#{c.npsNo},'%')
@@ -38,17 +46,44 @@
        </where>
    </select>
    <select id="productMainByOrderId" resultType="com.ruoyi.production.dto.ProductOrderDto">
        select
            po.*,
            pwo.work_order_no,
            pwo.report_work,
            pwo.status,
            pwo.quantity,
            pwo.plan_quantity
        select po.*,
               pwo.work_order_no,
               pwo.report_work,
               pwo.status,
               pwo.quantity,
               pwo.plan_quantity
        from product_order po
        left join product_work_order pwo on po.id = pwo.product_order_id
                 left join product_work_order pwo on po.id = pwo.product_order_id
        where po.id = #{c.id}
    </select>
    <select id="listProcessRoute" resultType="com.ruoyi.production.pojo.ProcessRoute">
        select pr.*
        from process_route pr
                 left join product_model pm on pr.product_model_id = pm.id
                 left join sales_ledger_product slp on pm.id = slp.product_model_id
        where slp.id = #{productModelId}
    </select>
    <select id="listProcessBom" resultType="com.ruoyi.production.dto.ProductStructureDto">
        select ps.id,
               ps.product_model_id,
               ps.process_id,
               ps.unit_quantity,
               ps.unit_quantity * po.quantity as demandedQuantity,
               ps.unit,
               p.product_name,
               pp.name as  process_name,
               pm.product_id,
               pm.model
        from
            product_structure ps
                left join product_model pm on ps.product_model_id = pm.id
                left join product p on pm.product_id = p.id
                left join product_process pp on ps.process_id = pp.id
                left join product_process_route ppr on ps.bom_id = ppr.bom_id
                left join product_order po on po.id = ppr.product_order_id
        where ppr.product_order_id = #{orderId}
        order by ps.id
    </select>
</mapper>
src/main/resources/mapper/production/ProductProcessMapper.xml
@@ -4,11 +4,7 @@
    <select id="listPage" resultType="com.ruoyi.production.dto.ProductProcessDto">
        SELECT
        p.id,
        p.name,
        p.no,
        p.remark,
        p.salary_quota
        *
        FROM
        product_process p
        <where>
src/main/resources/mapper/production/ProductProcessRouteItemMapper.xml
@@ -20,7 +20,7 @@
                 left join product_model pm on ppri.product_model_id = pm.id
                 left join product p on pm.product_id = p.id
                 left join product_process pp on pp.id = ppri.process_id
        where ppri.route_id = #{orderId}
        where ppri.product_order_id = #{orderId}
        order by ppri.drag_sort
    </select>
src/main/resources/mapper/production/ProductProcessRouteMapper.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.ruoyi.production.mapper.ProductProcessRouteMapper">
    <!-- é€šç”¨æŸ¥è¯¢æ˜ å°„结果 -->
    <resultMap id="BaseResultMap" type="com.ruoyi.production.pojo.ProductProcessRoute">
        <id column="id" property="id"/>
        <result column="product_model_id" property="productModelId"/>
        <result column="description" property="description"/>
        <result column="tenant_id" property="tenantId"/>
        <result column="create_time" property="createTime"/>
        <result column="update_time" property="updateTime"/>
        <result column="bom_id" property="bomId"/>
        <result column="process_route_code" property="processRouteCode"/>
        <result column="product_order_id" property="productOrderId"/>
    </resultMap>
    <select id="listMain" resultType="com.ruoyi.production.dto.ProcessRouteDto">
        select ppr.*, p.product_name, pm.product_id, pm.model, pb.bom_no
        from product_process_route ppr
                 left join product_bom pb on ppr.bom_id = pb.id
                 left join product_model pm on ppr.product_model_id = pm.id
                 left join product p on pm.product_id = p.id
        where ppr.product_order_id = #{orderId}
    </select>
</mapper>
src/main/resources/mapper/production/ProductStructureMapper.xml
@@ -9,11 +9,9 @@
        <result property="unitQuantity" column="unit_quantity"/>
        <result property="demandedQuantity" column="demanded_quantity"/>
        <result property="unit" column="unit"/>
        <result property="diskQuantity" column="disk_quantity"/>
        <result property="tenantId" column="tenant_id"/>
    </resultMap>
    <select id="listByproductModelId" resultType="com.ruoyi.production.dto.ProductStructureDto">
    <select id="listBybomId" resultType="com.ruoyi.production.dto.ProductStructureDto">
        select ps.*,
               p.product_name,
               pp.name as  process_name,
@@ -24,7 +22,22 @@
                left join product_model pm on ps.product_model_id = pm.id
                left join product p on pm.product_id = p.id
                left join product_process pp on ps.process_id = pp.id
        where ps.parent_id = #{productModelId}
        where ps.bom_id = #{bomId}
        order by ps.id
    </select>
    <select id="listBybomAndProcess" resultType="com.ruoyi.production.dto.ProductStructureDto">
        select ps.*,
               p.product_name,
               pp.name as  process_name,
               pm.product_id,
               pm.model
        from
            product_structure ps
                left join product_model pm on ps.product_model_id = pm.id
                left join product p on pm.product_id = p.id
                left join product_process pp on ps.process_id = pp.id
        where ps.bom_id = #{bomId}
        and ps.process_id=#{processId}
        order by ps.id
    </select>
</mapper>
src/main/resources/mapper/production/ProductWorkOrderMapper.xml
@@ -25,9 +25,10 @@
        pm.model,
        pm.unit,
        p.product_name AS productName,
        po.nps_no AS productOrderNpsNo
        po.nps_no AS productOrderNpsNo,
        ROUND(pwo.complete_quantity / pwo.plan_quantity * 100, 2) AS completionStatus
        FROM
        `product_work_order` pwo
        product_work_order pwo
        LEFT JOIN product_process_route_item ppri ON ppri.id = pwo.product_process_route_item_id
        LEFT JOIN product_order po ON po.id = pwo.product_order_id
        LEFT JOIN product_process pp ON pp.id = ppri.process_id
@@ -44,28 +45,4 @@
        from product_work_order pwo
        left join product_order po on po.id = pwo.product_order_id
    </select>
    <update id="updatePlanQuantity" parameterType="java.util.Map">
        UPDATE product_work_order
        SET
            report_work = #{reportWork},
            quantity = #{quantity},
            plan_quantity = plan_quantity - #{deductQuantity},
            product_main_id = #{productMainId}
        WHERE id = #{workOrderId}
    </update>
    <update id="rollbackPlanQuantity" parameterType="java.lang.Long">
        UPDATE product_work_order pwo
        INNER JOIN production_product_main ppm
        ON pwo.id = ppm.work_order_id
        AND ppm.id = #{productMainId}
        INNER JOIN production_product_output ppo
        ON ppo.product_main_id = ppm.id
        SET
        pwo.plan_quantity = pwo.plan_quantity + ppo.quantity,
        pwo.report_work = 0,
        pwo.quantity = 0
        WHERE pwo.id = ppm.work_order_id
    </update>
</mapper>
src/main/resources/mapper/production/ProductionProductInputMapper.xml
@@ -13,11 +13,14 @@
    <select id="listPageProductionProductInputDto" resultType="com.ruoyi.production.dto.ProductionProductInputDto">
        select ppi.*,
        pm.model as model,
        ppm.product_no as productNo
        ppm.product_no as productNo,
        p.product_name,
        pm.unit
        from
        production_product_input ppi
        left join production_product_main ppm on ppm.id = ppi.product_main_id
        left join product_model pm on pm.id = ppi.product_model_id
        left join product p on p.id = pm.product_id
        <where>
            <if test="c.productMainId != null and c.productMainId > 0">
                and ppm.id = #{c.productMainId}
src/main/resources/mapper/production/ProductionProductMainMapper.xml
@@ -16,10 +16,20 @@
        select ppm.*,
               pwo.work_order_no as workOrderNo,
               pwo.status as workOrderStatus,
               u.nick_name as nickName
               u.nick_name as nickName,
               p.product_name as productName,
               pm.model as productModelName,
               ppo.quantity,
               pm.unit,
               sl.sales_contract_no salesContractNo
        from
            production_product_main ppm
                left join product_work_order pwo on pwo.id = ppm.work_order_id
                left join product_order po on po.id = pwo.product_order_id
                left join production_product_output ppo on ppm.id = ppo.product_main_id
                left join product_model pm on pm.id = ppo.product_model_id
                left join product p on p.id = pm.product_id
                left join sales_ledger sl on sl.id = po.sales_ledger_id
                left join sys_user u on u.user_id = ppm.user_id
        <where>
            <if test="c.nickName != null and c.nickName != ''">
@@ -36,6 +46,7 @@
            </if>
        </where>
        order by ppm.id
    </select>
    <delete id="deleteByWorkOrderIds" parameterType="java.util.List">
src/main/resources/mapper/purchase/ProductRecordMapper.xml
@@ -34,10 +34,10 @@
            and pl.supplier_name like concat('%',#{c.supplierName},'%')
        </if>
        <if test="c.createdAtStart != null and c.createdAtStart != ''">
            and pr.created_at &gt;= date_format(#{c.createdAtStart},'%Y-%m-%d hh:mm:ss')
            and pr.created_at &gt;= str_to_date(#{c.createdAtStart}, '%Y-%m-%d')
        </if>
        <if test="c.createdAtEnd != null and c.createdAtEnd != ''">
            and pr.created_at &lt;= date_format(#{c.createdAtEnd},'%Y-%m-%d hh:mm:ss')
            and pr.created_at &lt; date_add(str_to_date(#{c.createdAtEnd}, '%Y-%m-%d'), interval 1 day)
        </if>
        <if test="c.purchaseContractNumber != null and c.purchaseContractNumber != ''">
            and tr.purchase_contract_number like concat('%',#{c.purchaseContractNumber},'%')
@@ -60,7 +60,12 @@
                 left join sales_ledger sl on sl.id = pl.sales_ledger_id
                 left join ticket_registration tr on tr.id = pr.ticket_registration_id
                 left join product_model pm on pm.id = pr.product_model_id
        WHERE type = 2 and pr.id = #{id}
        WHERE type = 2
        <if test="c.purchaseLedgerId != null and c.purchaseLedgerId != ''">
            and pr.purchase_ledger_id = #{c.purchaseLedgerId}
        </if>
        <if test="c.productModelId != null and c.productModelId != ''">
            and pm.id = #{c.productModelId}
        </if>
    </select>
</mapper>
src/main/resources/mapper/purchase/PurchaseLedgerMapper.xml
@@ -18,8 +18,8 @@
        pl.supplier_name,
        pl.project_name,
        pl.contract_amount,
        sum(pr.tickets_amount)as receipt_payment_amount,
        pl.contract_amount-sum(pr.tickets_amount) AS unReceipt_payment_amount,
        sum(tr.invoice_amount)as receipt_payment_amount,
        pl.contract_amount-sum(tr.invoice_amount) AS unReceipt_payment_amount,
        pl.entry_date,
        pl.recorder_id,
        pl.recorder_name,
@@ -29,7 +29,9 @@
        pl.approval_status,
        pl.payment_method
        from purchase_ledger pl
        left join sales_ledger_product slp on slp.sales_ledger_id = pl.id and slp.type=2
        left join product_record pr on pl.id = pr.purchase_ledger_id
        left join ticket_registration tr on tr.id = pr.ticket_registration_id
        left join supplier_manage sm on pl.supplier_id = sm.id
        <where>
            1 = 1
src/main/resources/mapper/sales/InvoiceRegistrationProductMapper.xml
@@ -110,10 +110,10 @@
                     )
            </if>
            <if test="invoiceRegistrationProductDto.invoiceDateStart != null and invoiceRegistrationProductDto.invoiceDateStart != ''">
                AND T3.invoice_date &gt;= date_format(#{invoiceRegistrationProductDto.invoiceDateStart}, '%Y-%m-%d')
                AND T3.invoice_date &gt;= str_to_date(#{invoiceRegistrationProductDto.invoiceDateStart}, '%Y-%m-%d')
            </if>
            <if test="invoiceRegistrationProductDto.invoiceDateEnd != null and invoiceRegistrationProductDto.invoiceDateEnd != ''">
                AND T3.invoice_date &lt;= date_format(#{invoiceRegistrationProductDto.invoiceDateEnd}, '%Y-%m-%d')
                AND T3.invoice_date &lt; date_add(str_to_date(#{invoiceRegistrationProductDto.invoiceDateEnd}, '%Y-%m-%d'), interval 1 day)
            </if>
            <if test="invoiceRegistrationProductDto.createTimeStart != null ">
                AND T1.create_time &gt;= date_format(#{invoiceRegistrationProductDto.createTimeStart}, '%Y-%m-%d %H:%i:%s')