src/main/java/com/ruoyi/approve/service/impl/ApproveNodeServiceImpl.java
@@ -13,7 +13,6 @@ import com.ruoyi.approve.service.IApproveNodeService; import com.ruoyi.common.enums.FileNameType; import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum; import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum; import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.device.mapper.DeviceRepairMapper; import com.ruoyi.device.pojo.DeviceRepair; @@ -25,7 +24,10 @@ import com.ruoyi.purchase.mapper.PurchaseLedgerMapper; import com.ruoyi.purchase.pojo.PurchaseLedger; import com.ruoyi.purchase.service.impl.PurchaseLedgerServiceImpl; import com.ruoyi.sales.mapper.*; import com.ruoyi.sales.mapper.CommonFileMapper; import com.ruoyi.sales.mapper.SalesLedgerProductMapper; import com.ruoyi.sales.mapper.SalesQuotationMapper; import com.ruoyi.sales.mapper.ShippingInfoMapper; import com.ruoyi.sales.pojo.CommonFile; import com.ruoyi.sales.pojo.SalesLedgerProduct; import com.ruoyi.sales.pojo.SalesQuotation; @@ -204,7 +206,8 @@ purchaseLedgerServiceImpl.addQualityInspect(purchaseLedger, salesLedgerProduct); }else { //直接入库 stockUtils.addStock(salesLedgerProduct.getProductModelId(), salesLedgerProduct.getQuantity(), StockInQualifiedRecordTypeEnum.PURCHASE_STOCK_IN.getCode(), purchaseLedger.getId()); stockUtils.addStock(salesLedgerProduct.getProductModelId(), salesLedgerProduct.getQuantity(), StockInQualifiedRecordTypeEnum.PURCHASE_STOCK_IN.getCode(), purchaseLedger.getId(),salesLedgerProduct.getBatchNo(),salesLedgerProduct.getCustomer()); } } } else if (status.equals(3)) { src/main/java/com/ruoyi/basic/dto/ProductTreeDto.java
@@ -9,6 +9,13 @@ private Long id; private Long parentId; private String productName; private String model; private String batchNo; private String customer; private String uidNo; private String unit; private Long productModelId; private String label; // 用于树形结构的显示名称 private List<ProductTreeDto> children; private String nodeType; } src/main/java/com/ruoyi/basic/pojo/Product.java
@@ -4,9 +4,11 @@ import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.io.Serializable; @Data @TableName("product") public class Product { public class Product implements Serializable { private static final long serialVersionUID = 1L; src/main/java/com/ruoyi/procurementrecord/utils/StockUtils.java
@@ -67,7 +67,7 @@ * @param recordType * @param recordId */ public void addStock(Long productModelId, BigDecimal quantity, String recordType,Long recordId) { public void addStock(Long productModelId, BigDecimal quantity, String recordType, Long recordId,String batchNo,String customer) { StockInventoryDto stockInventoryDto = new StockInventoryDto(); stockInventoryDto.setRecordId(recordId); if (recordType != null) { @@ -75,6 +75,8 @@ } stockInventoryDto.setQualitity(quantity); stockInventoryDto.setProductModelId(productModelId); stockInventoryDto.setBatchNo(batchNo); stockInventoryDto.setCustomer(customer); stockInventoryService.addstockInventory(stockInventoryDto); } @@ -85,12 +87,16 @@ * @param recordType * @param recordId */ public void substractStock(Long productModelId, BigDecimal quantity, String recordType,Long recordId) { public void substractStock(Long productModelId, BigDecimal quantity, String recordType, Long recordId,String batchNo,String customer) { StockInventoryDto stockInventoryDto = new StockInventoryDto(); stockInventoryDto.setRecordId(recordId); stockInventoryDto.setRecordType(String.valueOf(recordType)); if (recordType != null) { stockInventoryDto.setRecordType(recordType); } stockInventoryDto.setQualitity(quantity); stockInventoryDto.setProductModelId(productModelId); stockInventoryDto.setBatchNo(batchNo); stockInventoryDto.setCustomer(customer); stockInventoryService.subtractStockInventory(stockInventoryDto); } @@ -103,6 +109,7 @@ stockInRecordService.batchDelete(Collections.singletonList(one.getId())); } } public void deleteStockOutRecord(Long recordId, String recordType) { StockOutRecord one = stockOutRecordService.getOne(new QueryWrapper<StockOutRecord>() .lambda().eq(StockOutRecord::getRecordId, recordId) src/main/java/com/ruoyi/production/dto/DrawMaterialDto.java
@@ -1,28 +1,44 @@ package com.ruoyi.production.dto; import io.swagger.annotations.ApiModel; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import java.math.BigDecimal; @Data @ApiModel("领料单DTO") public class DrawMaterialDto { //订单id @ApiModelProperty("订单ID") private Long id; //型号id @ApiModelProperty("型号ID") private Long productModelId; //库存数量 @ApiModelProperty("库存数量") private BigDecimal qualitity; //领用数量 @ApiModelProperty("领用数量") private BigDecimal requisitionQty; //产品名称 @ApiModelProperty("产品名称") private String productName; //产品型号 @ApiModelProperty("产品型号") private String model; //产品单位 @ApiModelProperty("产品单位") private String unit; //报工领用数量 @ApiModelProperty("报工领用数量") private BigDecimal reportQty; //产品单位 @ApiModelProperty("备注") private String remark; @ApiModelProperty("批号") private String batchNo; @ApiModelProperty("供应商名称") private String customer; } src/main/java/com/ruoyi/production/pojo/ProductionProductInput.java
@@ -33,4 +33,10 @@ @ApiModelProperty(value = "备注") private String remark; @ApiModelProperty("批号") private String batchNo; @ApiModelProperty("供应商名称") private String customer; } src/main/java/com/ruoyi/production/service/impl/ProductOrderServiceImpl.java
@@ -24,6 +24,7 @@ import com.ruoyi.production.service.ProductOrderService; import com.ruoyi.quality.mapper.QualityInspectMapper; import com.ruoyi.stock.mapper.StockInventoryMapper; import com.ruoyi.stock.pojo.StockInventory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -247,8 +248,9 @@ @Override public List<SelectOptionDTO<String>> getProductOrderBatchNo() { List<ProductOrder> productOrders = productOrderMapper.selectList(null); return productOrders.stream().map(productOrder -> new SelectOptionDTO<>(productOrder.getBatchNo(), productOrder.getBatchNo())).collect(Collectors.toList()); //查询库存批号 List<StockInventory> stockInventoryList = stockInventoryMapper.selectList(null); return stockInventoryList.stream().map(stockInventory -> new SelectOptionDTO<>(stockInventory.getBatchNo(), stockInventory.getBatchNo())).collect(Collectors.toList()); } @Override @@ -278,7 +280,9 @@ if (productOrder != null) { List<DrawMaterialDto> materialDtoList = JSON.parseArray(productOrder.getDrawMaterials(), DrawMaterialDto.class); for (DrawMaterialDto drawMaterialDto : materialDtoList) { stockUtils.addStock(drawMaterialDto.getProductModelId(), drawMaterialDto.getRequisitionQty(), null, productOrderDto.getId()); stockUtils.addStock(drawMaterialDto.getProductModelId(), drawMaterialDto.getRequisitionQty(), null, productOrderDto.getId(), drawMaterialDto.getBatchNo(), drawMaterialDto.getCustomer() ); } } @@ -288,7 +292,9 @@ if (drawMaterialDto.getProductModelId() == null) { throw new RuntimeException("产品型号ID不能为空"); } stockUtils.substractStock(drawMaterialDto.getProductModelId(), drawMaterialDto.getRequisitionQty(), StockOutQualifiedRecordTypeEnum.DRAW_MATERIALS_STOCK_OUT.getCode(), productOrderDto.getId()); stockUtils.substractStock(drawMaterialDto.getProductModelId(), drawMaterialDto.getRequisitionQty(), StockOutQualifiedRecordTypeEnum.DRAW_MATERIALS_STOCK_OUT.getCode(), productOrderDto.getId(), drawMaterialDto.getBatchNo(),drawMaterialDto.getCustomer()); } } catch (Exception e) { throw new RuntimeException("领料失败:" + e.getMessage()); src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java
@@ -143,28 +143,32 @@ productionProductMain.setDeviceId(dto.getDeviceId()); productionProductMainMapper.insert(productionProductMain); /* 新增报工投入表 */ List<DrawMaterialDto> drawMaterialList = dto.getDrawMaterialList(); if (!CollectionUtils.isEmpty(drawMaterialList)) { // 1. 批量查询数据 ProductWorkOrder productWorkOrder = productWorkOrderMapper.selectById(dto.getWorkOrderId()); if (productWorkOrder == null) { ProductWorkOrder WorkOrder = productWorkOrderMapper.selectById(dto.getWorkOrderId()); if (WorkOrder == null) { throw new RuntimeException("工单不存在"); } ProductOrder productOrder = productOrderMapper.selectById(productWorkOrder.getProductOrderId()); if (productOrder == null) { ProductOrder order = productOrderMapper.selectById(WorkOrder.getProductOrderId()); if (order == null) { throw new RuntimeException("产品订单不存在"); } List<DrawMaterialDto> drawMaterialList = dto.getDrawMaterialList(); if (!CollectionUtils.isEmpty(drawMaterialList)) { // 2. 解析并构建物料Map List<DrawMaterialDto> existingMaterialList = JSON.parseArray(productOrder.getDrawMaterials(), DrawMaterialDto.class); // 物料Map List<DrawMaterialDto> existingMaterialList = JSON.parseArray(order.getDrawMaterials(), DrawMaterialDto.class); if (CollectionUtils.isEmpty(existingMaterialList)) { throw new RuntimeException("可领用物料列表为空"); } Map<Long, DrawMaterialDto> materialMap = existingMaterialList.stream() .collect(Collectors.toMap(DrawMaterialDto::getProductModelId, Function.identity())); Map<String, DrawMaterialDto> materialMap = existingMaterialList.stream() .collect(Collectors.toMap( materialDto -> materialDto.getProductModelId() + "_" + (materialDto.getBatchNo() == null ? "" : materialDto.getBatchNo()) + "_" + (materialDto.getCustomer() == null ? "" : materialDto.getCustomer()), Function.identity(), (existing, replacement) -> existing )); // 处理报工物料 List<ProductionProductInput> inputList = new ArrayList<>(); @@ -173,9 +177,15 @@ Long modelId = drawMaterial.getProductModelId(); BigDecimal reportQty = drawMaterial.getReportQty(); DrawMaterialDto material = materialMap.get(modelId); String key = drawMaterial.getProductModelId() + "_" + (drawMaterial.getBatchNo() == null ? "" : drawMaterial.getBatchNo()) + "_" + (drawMaterial.getCustomer() == null ? "" : drawMaterial.getCustomer()); DrawMaterialDto material = materialMap.get(key); if (material == null) { throw new RuntimeException("物料不存在: " + modelId); throw new RuntimeException("物料不存在: 产品型号ID=" + modelId + ", 批次号=" + drawMaterial.getBatchNo() + ", 客户=" + drawMaterial.getCustomer()); } // 验证库存 @@ -194,6 +204,8 @@ input.setQuantity(reportQty); input.setProductMainId(productionProductMain.getId()); input.setRemark(drawMaterial.getRemark()); input.setBatchNo(drawMaterial.getBatchNo()); input.setCustomer(drawMaterial.getCustomer()); inputList.add(input); } @@ -201,8 +213,8 @@ for (ProductionProductInput productionProductInput : inputList) { productionProductInputMapper.insert(productionProductInput); } productOrder.setDrawMaterials(JSON.toJSONString(existingMaterialList)); productOrderMapper.updateById(productOrder); order.setDrawMaterials(JSON.toJSONString(existingMaterialList)); productOrderMapper.updateById(order); } } /*新增报工产出表*/ @@ -266,7 +278,10 @@ } } else { //直接入库 stockUtils.addStock(productProcessRouteItem.getProductModelId(), productionProductOutput.getQuantity().subtract(productionProductOutput.getScrapQty()), StockInQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_IN.getCode(), productionProductMain.getId()); String customer = "长治市轴承制造有限公司"; stockUtils.addStock(productProcessRouteItem.getProductModelId(), productionProductOutput.getQuantity().subtract(productionProductOutput.getScrapQty()), StockInQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_IN.getCode(), productionProductMain.getId(),order.getBatchNo(),customer ); } /*更新工单和生产订单*/ ProductWorkOrder productWorkOrder = productWorkOrderMapper.selectById(dto.getWorkOrderId()); src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java
@@ -1,29 +1,23 @@ package com.ruoyi.purchase.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; import com.baomidou.mybatisplus.core.toolkit.ObjectUtils; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.ruoyi.account.pojo.AccountExpense; import com.ruoyi.account.pojo.AccountIncome; import com.ruoyi.account.service.AccountExpenseService; import com.ruoyi.account.service.AccountIncomeService; import com.ruoyi.approve.pojo.ApproveProcess; import com.ruoyi.approve.service.impl.ApproveProcessServiceImpl; import com.ruoyi.approve.vo.ApproveProcessVO; import com.ruoyi.basic.mapper.ProductMapper; import com.ruoyi.basic.mapper.ProductModelMapper; import com.ruoyi.basic.mapper.SupplierManageMapper; import com.ruoyi.basic.pojo.Customer; import com.ruoyi.basic.pojo.Product; import com.ruoyi.basic.pojo.ProductModel; import com.ruoyi.basic.pojo.SupplierManage; import com.ruoyi.common.enums.FileNameType; import com.ruoyi.common.exception.base.BaseException; import com.ruoyi.common.utils.DateUtils; import com.ruoyi.common.utils.SecurityUtils; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.poi.ExcelUtil; @@ -39,19 +33,25 @@ import com.ruoyi.purchase.dto.PurchaseLedgerImportDto; import com.ruoyi.purchase.dto.PurchaseLedgerProductImportDto; import com.ruoyi.purchase.mapper.*; import com.ruoyi.purchase.pojo.*; import com.ruoyi.purchase.pojo.PaymentRegistration; import com.ruoyi.purchase.pojo.ProductRecord; import com.ruoyi.purchase.pojo.PurchaseLedger; import com.ruoyi.purchase.pojo.TicketRegistration; import com.ruoyi.purchase.service.IPurchaseLedgerService; import com.ruoyi.quality.mapper.*; import com.ruoyi.quality.pojo.*; import com.ruoyi.sales.dto.SalesLedgerImportDto; import com.ruoyi.sales.dto.SalesLedgerProductImportDto; import com.ruoyi.sales.mapper.*; 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 com.ruoyi.sales.mapper.CommonFileMapper; import com.ruoyi.sales.mapper.InvoiceRegistrationProductMapper; import com.ruoyi.sales.mapper.SalesLedgerMapper; import com.ruoyi.sales.mapper.SalesLedgerProductMapper; import com.ruoyi.sales.pojo.CommonFile; import com.ruoyi.sales.pojo.InvoiceRegistrationProduct; import com.ruoyi.sales.pojo.SalesLedger; import com.ruoyi.sales.pojo.SalesLedgerProduct; import com.ruoyi.sales.service.impl.CommonFileServiceImpl; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.io.FilenameUtils; import org.springframework.beans.BeanUtils; @@ -207,7 +207,7 @@ // 4. 处理子表数据 List<SalesLedgerProduct> productList = purchaseLedgerDto.getProductData(); if (productList != null && !productList.isEmpty()) { handleSalesLedgerProducts(purchaseLedger.getId(), productList, purchaseLedgerDto.getType()); handleSalesLedgerProducts(purchaseLedger.getId(), productList, purchaseLedgerDto.getType(),supplierManage); } //新增原材料检验 审批之后才生成检验 // if (productList != null) { @@ -254,7 +254,7 @@ } } private void handleSalesLedgerProducts(Long salesLedgerId, List<SalesLedgerProduct> products, Integer type) { private void handleSalesLedgerProducts(Long salesLedgerId, List<SalesLedgerProduct> products, Integer type,SupplierManage supplierManage) { if (products == null || products.isEmpty()) { throw new BaseException("产品信息不存在"); } @@ -324,6 +324,8 @@ salesLedgerProduct.setFutureTickets(salesLedgerProduct.getQuantity()); salesLedgerProduct.setFutureTicketsAmount(salesLedgerProduct.getTaxInclusiveTotalPrice()); salesLedgerProduct.setPendingTicketsTotal(salesLedgerProduct.getTaxInclusiveTotalPrice()); salesLedgerProduct.setCustomer(supplierManage.getSupplierName()); salesLedgerProduct.setBatchNo(salesLedgerProduct.getBatchNo()); salesLedgerProductMapper.insert(salesLedgerProduct); } } src/main/java/com/ruoyi/quality/service/impl/QualityInspectServiceImpl.java
@@ -15,6 +15,12 @@ import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.procurementrecord.service.ProcurementRecordService; import com.ruoyi.procurementrecord.utils.StockUtils; import com.ruoyi.production.mapper.ProductOrderMapper; import com.ruoyi.production.mapper.ProductWorkOrderMapper; import com.ruoyi.production.mapper.ProductionProductMainMapper; import com.ruoyi.production.pojo.ProductOrder; import com.ruoyi.production.pojo.ProductWorkOrder; import com.ruoyi.production.pojo.ProductionProductMain; import com.ruoyi.quality.dto.QualityInspectDto; import com.ruoyi.quality.mapper.QualityInspectMapper; import com.ruoyi.quality.mapper.QualityTestStandardMapper; @@ -58,6 +64,13 @@ private ProductModelMapper productModelMapper; private ProductionProductMainMapper productionProductMainMapper; private ProductWorkOrderMapper productWorkOrderMapper; private ProductOrderMapper productOrderMapper; @Override public int add(QualityInspectDto qualityInspectDto) { QualityInspect qualityInspect = new QualityInspect(); @@ -85,6 +98,9 @@ @Override public int submit(QualityInspect inspect) { QualityInspect qualityInspect = qualityInspectMapper.selectById(inspect.getId()); ProductionProductMain productionProductMain = productionProductMainMapper.selectById(qualityInspect.getProductMainId()); ProductWorkOrder productWorkOrder = productWorkOrderMapper.selectById(productionProductMain.getWorkOrderId()); ProductOrder productOrder = productOrderMapper.selectById(productWorkOrder.getProductOrderId()); //提交前必须判断是否合格 if (ObjectUtils.isNull(qualityInspect.getCheckResult())) { throw new RuntimeException("请先判断是否合格"); @@ -101,7 +117,10 @@ qualityUnqualifiedMapper.insert(qualityUnqualified); } else { //合格直接入库 stockUtils.addStock(qualityInspect.getProductModelId(), qualityInspect.getQuantity(), StockInQualifiedRecordTypeEnum.QUALITYINSPECT_STOCK_IN.getCode(), qualityInspect.getId()); String customer = "长治市轴承制造有限公司"; stockUtils.addStock(qualityInspect.getProductModelId(), qualityInspect.getQuantity(), StockInQualifiedRecordTypeEnum.QUALITYINSPECT_STOCK_IN.getCode(), qualityInspect.getId(),productOrder.getBatchNo(),customer ); } qualityInspect.setInspectState(1);//已提交 return qualityInspectMapper.updateById(qualityInspect); src/main/java/com/ruoyi/quality/service/impl/QualityUnqualifiedServiceImpl.java
@@ -13,14 +13,8 @@ import com.ruoyi.common.utils.bean.BeanUtils; import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.procurementrecord.utils.StockUtils; import com.ruoyi.production.mapper.ProductProcessRouteItemMapper; import com.ruoyi.production.mapper.ProductProcessRouteMapper; import com.ruoyi.production.mapper.ProductWorkOrderMapper; import com.ruoyi.production.mapper.ProductionProductMainMapper; import com.ruoyi.production.pojo.ProductOrder; import com.ruoyi.production.pojo.ProductProcessRoute; import com.ruoyi.production.pojo.ProductProcessRouteItem; import com.ruoyi.production.pojo.ProductWorkOrder; import com.ruoyi.production.mapper.*; import com.ruoyi.production.pojo.*; import com.ruoyi.production.service.ProductOrderService; import com.ruoyi.quality.mapper.QualityUnqualifiedMapper; import com.ruoyi.quality.pojo.QualityInspect; @@ -54,6 +48,7 @@ private ProductProcessRouteItemMapper productProcessRouteItemMapper; private ProductWorkOrderMapper productWorkOrderMapper; private StockUninventoryService stockUninventoryService; private ProductOrderMapper productOrderMapper; @Override public IPage<QualityUnqualified> qualityUnqualifiedListPage(Page page, QualityUnqualified qualityUnqualified) { @@ -71,6 +66,9 @@ public int deal(QualityUnqualified qualityUnqualified) { QualityUnqualified unqualified = qualityUnqualifiedMapper.selectById(qualityUnqualified.getId()); QualityInspect qualityInspect = qualityInspectService.getById(unqualified.getInspectId()); ProductionProductMain productionProductMain = productionProductMainMapper.selectById(qualityInspect.getProductMainId()); ProductWorkOrder workOrder = productWorkOrderMapper.selectById(productionProductMain.getWorkOrderId()); ProductOrder orders = productOrderMapper.selectById(workOrder.getProductOrderId()); if (ObjectUtils.isNotNull(qualityInspect) && qualityInspect.getInspectType() != 0) { switch (qualityUnqualified.getDealResult()) { case "返修": @@ -137,7 +135,10 @@ break; case "让步放行": //调用提交合格的接口 stockUtils.addStock(qualityInspect.getProductModelId(), unqualified.getQuantity(), StockInQualifiedRecordTypeEnum.DEFECTIVE_PASS.getCode(), unqualified.getId()); String customer = "长治市轴承制造有限公司"; stockUtils.addStock(qualityInspect.getProductModelId(), unqualified.getQuantity(), StockInQualifiedRecordTypeEnum.DEFECTIVE_PASS.getCode(), unqualified.getId(), orders.getBatchNo(), customer ); break; case "返工": default: @@ -153,7 +154,8 @@ break; case "让步放行": //调用提交合格的接口 stockUtils.addStock(modelId, unqualified.getQuantity(), StockInQualifiedRecordTypeEnum.DEFECTIVE_PASS.getCode(), unqualified.getId()); String customer = "长治市轴承制造有限公司"; stockUtils.addStock(modelId, unqualified.getQuantity(), StockInQualifiedRecordTypeEnum.DEFECTIVE_PASS.getCode(), unqualified.getId(), orders.getBatchNo(), customer); break; default: break; src/main/java/com/ruoyi/sales/controller/ShipmentApprovalController.java
@@ -87,7 +87,7 @@ //出库 stockUtils.addStock(salesLedgerProduct.getProductModelId(), salesLedgerProduct.getQuantity(), StockOutQualifiedRecordTypeEnum.SALE_SHIP_STOCK_OUT.getCode(), req.getId()); stockUtils.addStock(salesLedgerProduct.getProductModelId(), salesLedgerProduct.getQuantity(), StockOutQualifiedRecordTypeEnum.SALE_SHIP_STOCK_OUT.getCode(), req.getId(),null,null); } return AjaxResult.success(); src/main/java/com/ruoyi/sales/pojo/SalesLedgerProduct.java
@@ -241,4 +241,7 @@ @ApiModelProperty(value = "批号") private String batchNo; @ApiModelProperty(value = "供应商") private String customer; } src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
@@ -194,6 +194,9 @@ product.setTempnoInvoiceAmount(product.getNoInvoiceAmount()); product.setTempNoInvoiceNum(product.getNoInvoiceNum()); product.setRegister(SecurityUtils.getLoginUser().getUser().getNickName()); product.setUidNo(product.getUidNo()); product.setUnit(product.getUnit()); product.setBatchNo(product.getBatchNo()); product.setRegisterDate(LocalDateTime.now()); // 发货信息 ShippingInfo shippingInfo = shippingInfoMapper.selectOne(new LambdaQueryWrapper<ShippingInfo>() src/main/java/com/ruoyi/sales/service/impl/ShippingInfoServiceImpl.java
@@ -67,7 +67,9 @@ //扣减库存 if(!"已发货".equals(byId.getStatus())){ SalesLedgerProduct salesLedgerProduct = salesLedgerProductMapper.selectById(byId.getSalesLedgerProductId()); stockUtils.substractStock(salesLedgerProduct.getProductModelId(), salesLedgerProduct.getQuantity(), StockOutQualifiedRecordTypeEnum.SALE_SHIP_STOCK_OUT.getCode(), req.getId()); stockUtils.substractStock(salesLedgerProduct.getProductModelId(), salesLedgerProduct.getQuantity(), StockOutQualifiedRecordTypeEnum.SALE_SHIP_STOCK_OUT.getCode(), req.getId(),null,null ); } byId.setExpressNumber(req.getExpressNumber()); byId.setExpressCompany(req.getExpressCompany()); src/main/java/com/ruoyi/stock/controller/StockInventoryController.java
@@ -2,6 +2,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.ruoyi.basic.dto.ProductDto; import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum; import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum; import com.ruoyi.common.utils.poi.ExcelUtil; @@ -108,7 +109,13 @@ @ApiOperation("查询库存原材料") @GetMapping("/getMaterials") public R getMaterials() { return R.ok(stockInventoryService.getMaterials()); public R getMaterials(StockInventoryDto stockInventoryDto) { return R.ok(stockInventoryService.getMaterials(stockInventoryDto)); } @ApiOperation("查询库存产品") @GetMapping("/getStockInventoryAll") public R getStockInventoryAll(ProductDto productDto) { return R.ok(stockInventoryService.getStockInventoryAll(productDto)); } } src/main/java/com/ruoyi/stock/dto/StockInventoryDto.java
@@ -42,4 +42,7 @@ private BigDecimal currentStock; private BigDecimal unLockedQuantity; private Long productId; // 产品ID private Long parentId; // 父级产品ID private Long productModelId; // 产品型号ID } src/main/java/com/ruoyi/stock/mapper/StockInventoryMapper.java
@@ -3,6 +3,7 @@ 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.basic.dto.ProductDto; import com.ruoyi.stock.dto.StockInRecordDto; import com.ruoyi.stock.dto.StockInventoryDto; import com.ruoyi.stock.execl.StockInventoryExportData; @@ -52,5 +53,7 @@ List<StockInventoryDto> getStockInventory(@Param("ids") List<Long> ids); List<StockInventoryDto> getMaterials(); List<StockInventoryDto> getMaterials(@Param("ew")StockInventoryDto stockInventoryDto); List<StockInventoryDto> getStockInventoryAll(@Param("ew") ProductDto productDto); } src/main/java/com/ruoyi/stock/pojo/StockInRecord.java
@@ -63,4 +63,10 @@ @ApiModelProperty(value = "修改用户") @TableField(fill = FieldFill.INSERT_UPDATE) private Integer updateUser; @ApiModelProperty("批号") private String batchNo; @ApiModelProperty("供应商名称") private String customer; } src/main/java/com/ruoyi/stock/pojo/StockInventory.java
@@ -63,4 +63,10 @@ @ApiModelProperty("备注") private String remark; @ApiModelProperty("批号") private String batchNo; @ApiModelProperty("供应商名称") private String customer; } src/main/java/com/ruoyi/stock/pojo/StockOutRecord.java
@@ -71,4 +71,11 @@ @ApiModelProperty(value = "类型 0合格入库 1不合格入库") private String type; @ApiModelProperty("批号") private String batchNo; @ApiModelProperty("供应商名称") private String customer; } src/main/java/com/ruoyi/stock/pojo/StockUninventory.java
@@ -59,4 +59,10 @@ @ApiModelProperty("被订单锁定数量") private BigDecimal lockedQuantity; @ApiModelProperty("批号") private String batchNo; @ApiModelProperty("供应商名称") private String customer; } src/main/java/com/ruoyi/stock/service/StockInventoryService.java
@@ -3,6 +3,8 @@ 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.dto.ProductDto; import com.ruoyi.basic.dto.ProductTreeDto; import com.ruoyi.framework.web.domain.R; import com.ruoyi.stock.dto.StockInRecordDto; import com.ruoyi.stock.dto.StockInventoryDto; @@ -40,5 +42,7 @@ Boolean thawStock(StockInventoryDto stockInventoryDto); List<StockInventoryDto> getMaterials(); List<StockInventoryDto> getMaterials(StockInventoryDto stockInventoryDto); List<ProductTreeDto> getStockInventoryAll(ProductDto productDto); } src/main/java/com/ruoyi/stock/service/impl/StockInventoryServiceImpl.java
@@ -1,11 +1,19 @@ package com.ruoyi.stock.service.impl; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.CollectionUtils; 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.dto.ProductDto; 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.common.enums.StockInQualifiedRecordTypeEnum; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.framework.web.domain.R; import com.ruoyi.sales.mapper.SalesLedgerProductMapper; @@ -19,15 +27,14 @@ import com.ruoyi.stock.service.StockInRecordService; import com.ruoyi.stock.service.StockInventoryService; import com.ruoyi.stock.service.StockOutRecordService; import lombok.AllArgsConstructor; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletResponse; import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; import java.util.*; /** * <p> @@ -38,13 +45,22 @@ * @since 2026-01-21 04:16:36 */ @Service @AllArgsConstructor public class StockInventoryServiceImpl extends ServiceImpl<StockInventoryMapper, StockInventory> implements StockInventoryService { @Autowired private StockInventoryMapper stockInventoryMapper; @Autowired private StockInRecordService stockInRecordService; @Autowired private StockOutRecordService stockOutRecordService; @Autowired private SalesLedgerProductMapper salesLedgerProductMapper; @Autowired private ProductMapper productMapper; @Autowired private ProductModelMapper productModelMapper; @Override public IPage<StockInventoryDto> pagestockInventory(Page page, StockInventoryDto stockInventoryDto) { return stockInventoryMapper.pagestockInventory(page, stockInventoryDto); @@ -62,11 +78,17 @@ stockInRecordDto.setStockInNum(stockInventoryDto.getQualitity()); stockInRecordDto.setProductModelId(stockInventoryDto.getProductModelId()); stockInRecordDto.setType("0"); stockInRecordDto.setBatchNo(stockInventoryDto.getBatchNo()); stockInRecordDto.setCustomer(stockInventoryDto.getCustomer()); stockInRecordService.add(stockInRecordDto); } //再进行新增库存数量库存 //先查询库存表中的产品是否存在,不存在新增,存在更新 StockInventory oldStockInventory = stockInventoryMapper.selectOne(new QueryWrapper<StockInventory>().lambda().eq(StockInventory::getProductModelId, stockInventoryDto.getProductModelId())); StockInventory oldStockInventory = stockInventoryMapper.selectOne(new QueryWrapper<StockInventory>().lambda() .eq(StockInventory::getProductModelId, stockInventoryDto.getProductModelId()) .eq(StockInventory::getBatchNo, stockInventoryDto.getBatchNo()) .eq(StockInventory::getCustomer, stockInventoryDto.getCustomer()) ); if (ObjectUtils.isEmpty(oldStockInventory)) { StockInventory newStockInventory = new StockInventory(); newStockInventory.setProductModelId(stockInventoryDto.getProductModelId()); @@ -75,6 +97,8 @@ newStockInventory.setRemark(stockInventoryDto.getRemark()); newStockInventory.setLockedQuantity(stockInventoryDto.getLockedQuantity()); newStockInventory.setWarnNum(stockInventoryDto.getWarnNum()); newStockInventory.setBatchNo(stockInventoryDto.getBatchNo()); newStockInventory.setCustomer(stockInventoryDto.getCustomer()); stockInventoryMapper.insert(newStockInventory); }else { stockInventoryMapper.updateAddStockInventory(stockInventoryDto); @@ -87,14 +111,22 @@ @Transactional(rollbackFor = Exception.class) public Boolean subtractStockInventory(StockInventoryDto stockInventoryDto) { // 新增出库记录 if (stockInventoryDto.getRecordType() != null) { StockOutRecordDto stockOutRecordDto = new StockOutRecordDto(); stockOutRecordDto.setRecordId(stockInventoryDto.getRecordId()); stockOutRecordDto.setRecordType(stockInventoryDto.getRecordType()); stockOutRecordDto.setStockOutNum(stockInventoryDto.getQualitity()); stockOutRecordDto.setProductModelId(stockInventoryDto.getProductModelId()); stockOutRecordDto.setBatchNo(stockInventoryDto.getBatchNo()); stockOutRecordDto.setCustomer(stockInventoryDto.getCustomer()); stockOutRecordDto.setType("0"); stockOutRecordService.add(stockOutRecordDto); StockInventory oldStockInventory = stockInventoryMapper.selectOne(new QueryWrapper<StockInventory>().lambda().eq(StockInventory::getProductModelId, stockInventoryDto.getProductModelId())); } StockInventory oldStockInventory = stockInventoryMapper.selectOne(new QueryWrapper<StockInventory>().lambda() .eq(StockInventory::getProductModelId, stockInventoryDto.getProductModelId()) .eq(StockInventory::getBatchNo, stockInventoryDto.getBatchNo()) .eq(StockInventory::getCustomer, stockInventoryDto.getCustomer()) ); if (ObjectUtils.isEmpty(oldStockInventory)) { throw new RuntimeException("产品库存不存在"); } @@ -210,7 +242,214 @@ } @Override public List<StockInventoryDto> getMaterials() { return stockInventoryMapper.getMaterials(); public List<StockInventoryDto> getMaterials(StockInventoryDto stockInventoryDto) { return stockInventoryMapper.getMaterials(stockInventoryDto); } @Override public List<ProductTreeDto> getStockInventoryAll(ProductDto productDto) { // 查询库存列表 List<StockInventoryDto> stockList = stockInventoryMapper.getStockInventoryAll(productDto); if (CollectionUtils.isEmpty(stockList)) { return new ArrayList<>(); } // 构建产品树(基于产品表的父子关系) Map<Long, ProductTreeDto> productNodeMap = buildProductTree(stockList); // 将库存数据(型号->批次->客户)挂载到对应的产品节点下 attachStockDataToProduct(productNodeMap, stockList); // 返回根节点 List<ProductTreeDto> tree = new ArrayList<>(); for (ProductTreeDto node : productNodeMap.values()) { if (node.getParentId() == null || node.getParentId() == 0) { tree.add(node); } } return tree; } /** * 构建产品树(自动递归查询所有父级,包含根节点) */ private Map<Long, ProductTreeDto> buildProductTree(List<StockInventoryDto> stockList) { // 1. 收集所有需要加载的产品ID Set<Long> needQueryIds = new HashSet<>(); for (StockInventoryDto stock : stockList) { if (stock.getProductId() != null) { needQueryIds.add(stock.getProductId()); } } // 递归查询所有节点(直到根节点) Set<Long> allAncestors = getAllAncestorIds(needQueryIds); needQueryIds.addAll(allAncestors); // 批量查询所有产品(包含完整层级) LambdaQueryWrapper<Product> wrapper = new LambdaQueryWrapper<>(); wrapper.in(Product::getId, needQueryIds); List<Product> products = productMapper.selectList(wrapper); // 构建节点Map Map<Long, ProductTreeDto> nodeMap = new HashMap<>(); for (Product product : products) { ProductTreeDto node = new ProductTreeDto(); node.setId(product.getId()); node.setParentId(product.getParentId()); node.setProductName(product.getProductName()); node.setLabel(product.getProductName()); node.setNodeType("product"); node.setChildren(new ArrayList<>()); nodeMap.put(product.getId(), node); } // 构建父子关系 for (ProductTreeDto node : nodeMap.values()) { Long parentId = node.getParentId(); if (parentId != null && parentId != 0 && nodeMap.containsKey(parentId)) { nodeMap.get(parentId).getChildren().add(node); } } return nodeMap; } /** * 递归查询所有产品的祖先ID(直到根节点) */ private Set<Long> getAllAncestorIds(Set<Long> productIds) { Set<Long> ancestorIds = new HashSet<>(); Queue<Long> queue = new LinkedList<>(productIds); while (!queue.isEmpty()) { Long currentId = queue.poll(); Product product = productMapper.selectById(currentId); if (product == null) continue; Long parentId = product.getParentId(); if (parentId != null && parentId != 0 && !ancestorIds.contains(parentId)) { ancestorIds.add(parentId); queue.add(parentId); } } return ancestorIds; } /** * 将库存数据(型号->批次->客户)挂载到产品节点下 */ private void attachStockDataToProduct(Map<Long, ProductTreeDto> productNodeMap, List<StockInventoryDto> stockList) { for (StockInventoryDto stock : stockList) { Long productId = stock.getProductId(); if (productId == null || !productNodeMap.containsKey(productId)) { continue; } ProductTreeDto productNode = productNodeMap.get(productId); // 构建该产品的库存树(型号 -> 批次 -> 客户) ProductTreeDto stockTree = buildStockTree(stock); // 合并到产品节点的 children 中 mergeStockTree(productNode.getChildren(), stockTree); } } /** * 构建单个库存的树结构(型号 -> 批次 -> 客户) */ private ProductTreeDto buildStockTree(StockInventoryDto stock) { // 型号节点 ProductTreeDto modelNode = new ProductTreeDto(); modelNode.setModel(stock.getModel()); modelNode.setUidNo(stock.getUidNo()); modelNode.setUnit(stock.getUnit()); modelNode.setProductModelId(stock.getProductModelId()); modelNode.setLabel(stock.getModel()); modelNode.setNodeType("model"); modelNode.setChildren(new ArrayList<>()); // 批次节点 ProductTreeDto batchNode = new ProductTreeDto(); String batchNo = StringUtils.isBlank(stock.getBatchNo()) ? "无批次" : stock.getBatchNo(); batchNode.setBatchNo(batchNo); batchNode.setLabel("批次: " + batchNo); batchNode.setNodeType("batch"); batchNode.setChildren(new ArrayList<>()); // 客户节点 ProductTreeDto customerNode = new ProductTreeDto(); String customer = StringUtils.isBlank(stock.getCustomer()) ? "无客户" : stock.getCustomer(); customerNode.setCustomer(customer); customerNode.setLabel(customer); customerNode.setNodeType("customer"); customerNode.setChildren(new ArrayList<>()); batchNode.getChildren().add(customerNode); modelNode.getChildren().add(batchNode); return modelNode; } /** * 合并库存树到产品节点的 children 中 */ private void mergeStockTree(List<ProductTreeDto> children, ProductTreeDto newStockTree) { if (children == null) { return; } // 查找是否已有相同型号的节点 ProductTreeDto existingModelNode = null; for (ProductTreeDto child : children) { if (child.getNodeType().equals("model") && child.getModel() != null && child.getModel().equals(newStockTree.getModel())) { existingModelNode = child; break; } } if (existingModelNode == null) { // 没有相同型号,直接添加 children.add(newStockTree); } else { // 有相同型号,合并批次节点 ProductTreeDto newBatchNode = newStockTree.getChildren().get(0); // 查找是否已有相同批次 ProductTreeDto existingBatchNode = null; for (ProductTreeDto batchChild : existingModelNode.getChildren()) { if (batchChild.getNodeType().equals("batch") && batchChild.getBatchNo() != null && batchChild.getBatchNo().equals(newBatchNode.getBatchNo())) { existingBatchNode = batchChild; break; } } if (existingBatchNode == null) { existingModelNode.getChildren().add(newBatchNode); } else { // 合并客户节点 ProductTreeDto newCustomerNode = newBatchNode.getChildren().get(0); boolean customerExists = false; for (ProductTreeDto customerChild : existingBatchNode.getChildren()) { if (customerChild.getNodeType().equals("customer") && customerChild.getCustomer() != null && customerChild.getCustomer().equals(newCustomerNode.getCustomer())) { customerExists = true; break; } } if (!customerExists) { existingBatchNode.getChildren().add(newCustomerNode); } } } } } src/main/resources/mapper/purchase/PaymentRegistrationMapper.xml
@@ -197,7 +197,7 @@ T1.supplier_name LIKE CONCAT ('%',#{req.supplierName},'%') </if> </where> GROUP BY T1.supplier_name GROUP BY T1.supplier_id, T1.supplier_name </select> <select id="supplierNameListPageDetails" resultType="com.ruoyi.purchase.dto.PaymentRegistrationDto"> src/main/resources/mapper/stock/StockInventoryMapper.xml
@@ -65,7 +65,9 @@ si.remark, pm.unit, pm.uid_no as uidNo, p.product_name p.product_name, si.batch_no, si.customer from stock_inventory si left join product_model pm on si.product_model_id = pm.id left join product p on pm.product_id = p.id @@ -273,7 +275,9 @@ pm.unit, pm.uid_no AS uidNo, p.product_name, p1.product_name AS parentName p1.product_name AS parentName, si.batch_no, si.customer FROM stock_inventory si LEFT JOIN product_model pm ON si.product_model_id = pm.id @@ -281,6 +285,47 @@ LEFT JOIN product p1 ON p1.id = p.parent_id WHERE p1.product_name = '原材料'; <if test="ew.batchNo != null and ew.batchNo !=''"> and si.batch_no like concat('%',#{ew.batchNo},'%') </if> <if test="ew.customer != null and ew.customer !=''"> and si.customer like concat('%',#{ew.customer},'%') </if> </select> <select id="getStockInventoryAll" resultType="com.ruoyi.stock.dto.StockInventoryDto"> SELECT si.id, si.qualitity, COALESCE(si.locked_quantity, 0) AS locked_quantity, si.product_model_id, si.create_time, si.update_time, COALESCE(si.warn_num, 0) AS warn_num, si.version, (si.qualitity - COALESCE(si.locked_quantity, 0)) AS un_locked_quantity, pm.id as productModelId, pm.model, si.remark, pm.unit, pm.uid_no AS uidNo, p.id AS product_id, p.product_name, p.parent_id AS parent_id, p1.product_name AS parentName, si.batch_no, si.customer FROM stock_inventory si LEFT JOIN product_model pm ON si.product_model_id = pm.id LEFT JOIN product p ON pm.product_id = p.id LEFT JOIN product p1 ON p1.id = p.parent_id <where> <if test="ew.productName != null and ew.productName != ''"> AND p.product_name LIKE CONCAT('%', #{ew.productName}, '%') </if> </where> </select> </mapper>