liyong
2026-05-14 4336d99906953517399187638925817d969c4e10
refactor(stock): 优化库存管理和产品模型查询功能

- 移除ApproveProcessServiceImpl中的采购入库相关代码逻辑
- 在ProductController中添加产品型号分页查询接口并完善文档注解
- 重构ProductionOrderPickServiceImpl中的库存操作方法调用
- 优化ProductionProductMainServiceImpl中的生产报工库存处理逻辑
- 在ProductModelMapper中新增分页查询产品型号及库存数量的方法
- 完善StockInRecord相关的批量审批功能,增加仓库信息参数
- 优化ProductServiceImpl中的批号数量映射填充逻辑
- 修改StockInRecord实体类,增加仓库信息字段
- 更新Mapper XML文件中的查询语句以支持新的功能需求
已添加7个文件
已修改39个文件
1049 ■■■■ 文件已修改
src/main/java/com/ruoyi/approve/service/impl/ApproveProcessServiceImpl.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/controller/ProductController.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/mapper/ProductModelMapper.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/service/IProductService.java 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/service/impl/ProductServiceImpl.java 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/basic/vo/ProductModelVo.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/procurementrecord/utils/StockUtils.java 54 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/ProductionOrderPickServiceImpl.java 49 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java 133 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/pojo/PurchaseReturnOrders.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/controller/StockInRecordController.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/controller/StockOutRecordController.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/controller/WarehouseInfoController.java 63 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/dto/StockInRecordDto.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/dto/StockInventoryDto.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/dto/StockOutRecordDto.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/dto/StockUninventoryDto.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/dto/WarehouseInfoDto.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/execl/StockInventoryExportData.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/mapper/StockInventoryMapper.java 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/mapper/WarehouseInfoMapper.java 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/pojo/StockInRecord.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/pojo/StockInventory.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/pojo/StockInventoryCheckItem.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/pojo/StockInventoryCheckMain.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/pojo/StockInventoryCheckPlan.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/pojo/StockInventoryCheckProduct.java 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/pojo/StockOutRecord.java 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/pojo/WarehouseInfo.java 100 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/service/StockInRecordService.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/service/StockInventoryService.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/service/StockOutRecordService.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/service/WarehouseInfoService.java 24 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/service/impl/StockInRecordServiceImpl.java 49 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/service/impl/StockInventoryCheckPlanServiceImpl.java 21 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/service/impl/StockInventoryServiceImpl.java 84 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/service/impl/StockOutRecordServiceImpl.java 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/service/impl/WarehouseInfoServiceImpl.java 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/basic/ProductModelMapper.xml 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/purchase/PurchaseLedgerMapper.xml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/stock/StockInRecordMapper.xml 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/stock/StockInventoryMapper.xml 49 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/stock/StockOutRecordMapper.xml 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/stock/WarehouseInfoMapper.xml 35 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/approve/service/impl/ApproveProcessServiceImpl.java
@@ -1,7 +1,6 @@
package com.ruoyi.approve.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
@@ -25,7 +24,6 @@
import com.ruoyi.basic.enums.RecordTypeEnum;
import com.ruoyi.basic.utils.FileUtil;
import com.ruoyi.common.enums.FileNameType;
import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum;
import com.ruoyi.common.utils.OrderUtils;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.procurementrecord.utils.StockUtils;
@@ -41,7 +39,6 @@
import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
import com.ruoyi.sales.mapper.ShippingInfoMapper;
import com.ruoyi.sales.pojo.CommonFile;
import com.ruoyi.sales.pojo.SalesLedgerProduct;
import com.ruoyi.sales.pojo.ShippingInfo;
import com.ruoyi.sales.service.impl.CommonFileServiceImpl;
import lombok.RequiredArgsConstructor;
@@ -164,14 +161,14 @@
                .eq(PurchaseLedger::getPurchaseContractNumber, approveProcessVO.getApproveReason())
                .set(PurchaseLedger::getApprovalStatus, 3));
        //采购入库
        PurchaseLedger purchaseLedger = purchaseLedgerMapper.selectOne(new LambdaQueryWrapper<PurchaseLedger>()
                .eq(PurchaseLedger::getPurchaseContractNumber, approveProcessVO.getApproveReason())
                .last("limit 1"));
        List<SalesLedgerProduct> salesLedgerProducts = salesLedgerProductMapper.selectList(new QueryWrapper<SalesLedgerProduct>()
                .lambda().eq(SalesLedgerProduct::getSalesLedgerId, purchaseLedger.getId()).eq(SalesLedgerProduct::getType, 2));
        for (SalesLedgerProduct salesLedgerProduct : salesLedgerProducts) {
            stockUtils.addStockWithBatchNo(salesLedgerProduct.getProductModelId(), salesLedgerProduct.getQuantity(), StockInQualifiedRecordTypeEnum.PURCHASE_STOCK_IN.getCode(), purchaseLedger.getId(),purchaseLedger.getPurchaseContractNumber()+"-"+salesLedgerProduct.getId());
        }
//        PurchaseLedger purchaseLedger = purchaseLedgerMapper.selectOne(new LambdaQueryWrapper<PurchaseLedger>()
//                .eq(PurchaseLedger::getPurchaseContractNumber, approveProcessVO.getApproveReason())
//                .last("limit 1"));
//        List<SalesLedgerProduct> salesLedgerProducts = salesLedgerProductMapper.selectList(new QueryWrapper<SalesLedgerProduct>()
//                .lambda().eq(SalesLedgerProduct::getSalesLedgerId, purchaseLedger.getId()).eq(SalesLedgerProduct::getType, 2));
//        for (SalesLedgerProduct salesLedgerProduct : salesLedgerProducts) {
//            stockUtils.addStockWithBatchNo(salesLedgerProduct.getProductModelId(), salesLedgerProduct.getQuantity(), StockInQualifiedRecordTypeEnum.PURCHASE_STOCK_IN.getCode(), purchaseLedger.getId(),purchaseLedger.getPurchaseContractNumber()+"-"+salesLedgerProduct.getId());
//        }
    }
    @Override
src/main/java/com/ruoyi/basic/controller/ProductController.java
@@ -19,6 +19,7 @@
import com.ruoyi.sales.pojo.SalesLedgerProduct;
import com.ruoyi.sales.service.ISalesLedgerProductService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
@@ -29,6 +30,7 @@
@RestController
@AllArgsConstructor
@RequestMapping("/basic/product")
@Tag(name = "产品管理", description = "产品管理")
public class ProductController extends BaseController {
    private IProductService productService;
@@ -120,6 +122,12 @@
        return productService.listPageProductModel(page, productModel);
    }
    @Operation(summary = "分页查询所有产品型号以及数量批号")
    @GetMapping("/pageModelAndQua")
    public IPage<ProductModelVo> pageModelAndQua(Page<ProductModelVo> page, ProductModel productModel) {
        return productService.pageModelAndQua(page, productModel);
    }
    /**
     * å¯¼å…¥äº§å“
     */
src/main/java/com/ruoyi/basic/mapper/ProductModelMapper.java
@@ -30,4 +30,8 @@
    List<Map<String, Object>> getProductAndModelList();
    List<ProductModelDto> selectModelByIds( @Param("list") List<Long> productIdList);
    IPage<ProductModelVo> pageModelAndQua(Page<ProductModelVo> page, @Param("c") ProductModel productModel);
    List<Map<String, Object>> selectBatchNoQtyByProductModelIds(@Param("list") List<Long> productModelIds);
}
src/main/java/com/ruoyi/basic/service/IProductService.java
@@ -12,7 +12,7 @@
import java.util.List;
public interface IProductService extends IService<Product> {
    int addOrEditProduct(ProductDto productDto);
    int delProductByIds(Long[] ids);
@@ -20,4 +20,6 @@
    List<ProductTreeDto> selectProductList(ProductDto productDto);
    IPage<ProductModelVo> listPageProductModel(Page<ProductModelVo> page, ProductModel productModel);
    IPage<ProductModelVo> pageModelAndQua(Page<ProductModelVo> page, ProductModel productModel);
}
src/main/java/com/ruoyi/basic/service/impl/ProductServiceImpl.java
@@ -14,17 +14,18 @@
import com.ruoyi.basic.service.IProductService;
import com.ruoyi.basic.vo.ProductModelVo;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.stock.mapper.WarehouseInfoMapper;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.math.BigDecimal;
import java.util.*;
@Service
@AllArgsConstructor
public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> implements IProductService {
    private final WarehouseInfoMapper warehouseInfoMapper;
    private ProductMapper productMapper;
    private ProductModelMapper productModelMapper;
@@ -64,6 +65,83 @@
        return productModelMapper.listPageProductModel(page, productModel);
    }
    @Override
    public IPage<ProductModelVo> pageModelAndQua(Page<ProductModelVo> page, ProductModel productModel) {
        IPage<ProductModelVo> result = productModelMapper.pageModelAndQua(page, productModel);
        fillBatchNoMaps(result.getRecords());
        return result;
    }
    private void fillBatchNoMaps(List<ProductModelVo> records) {
        if (records == null || records.isEmpty()) {
            return;
        }
        List<Long> productModelIds = records.stream()
                .map(ProductModelVo::getId)
                .filter(Objects::nonNull)
                .toList();
        if (productModelIds.isEmpty()) {
            return;
        }
        List<Map<String, Object>> batchRows = productModelMapper.selectBatchNoQtyByProductModelIds(productModelIds);
        Map<Long, HashMap<String, HashMap<String, BigDecimal>>> batchNoQtyMapsByProductModelId = new HashMap<>();
        for (Map<String, Object> batchRow : batchRows) {
            Long productModelId = toLong(batchRow.get("productModelId"));
            Long warehouseId = toLong(batchRow.get("warehouseId"));
            String batchNo = (String) batchRow.get("batchNo");
            if (productModelId == null || warehouseId == null || batchNo == null || batchNo.isBlank()) {
                continue;
            }
            batchNoQtyMapsByProductModelId
                    .computeIfAbsent(productModelId, key -> new HashMap<>())
                    .computeIfAbsent(String.valueOf(warehouseId), key -> new HashMap<>())
                    .merge(batchNo, toBigDecimal(batchRow.get("qty")), BigDecimal::add);
        }
        for (ProductModelVo record : records) {
            HashMap<String, List<Map<String, BigDecimal>>> batchNoMaps = new HashMap<>();
            HashMap<String, HashMap<String, BigDecimal>> stockBatchNoQtyMaps =
                    batchNoQtyMapsByProductModelId.getOrDefault(record.getId(), new HashMap<>());
            for (Map.Entry<String, HashMap<String, BigDecimal>> entry : stockBatchNoQtyMaps.entrySet()) {
                List<Map<String, BigDecimal>> batchList = new ArrayList<>();
                for (Map.Entry<String, BigDecimal> batchEntry : entry.getValue().entrySet()) {
                    Map<String, BigDecimal> batchItem = new HashMap<>();
                    batchItem.put(batchEntry.getKey(), batchEntry.getValue());
                    batchList.add(batchItem);
                }
                batchNoMaps.put(entry.getKey(), batchList);
            }
            record.setBatchNoMaps(batchNoMaps);
        }
    }
    private Long toLong(Object value) {
        if (value instanceof Number number) {
            return number.longValue();
        }
        if (value instanceof String str && !str.isBlank()) {
            return Long.parseLong(str);
        }
        return null;
    }
    private BigDecimal toBigDecimal(Object value) {
        if (value instanceof BigDecimal bigDecimal) {
            return bigDecimal;
        }
        if (value instanceof Number number) {
            return BigDecimal.valueOf(number.doubleValue());
        }
        if (value instanceof String str && !str.isBlank()) {
            return new BigDecimal(str);
        }
        return BigDecimal.ZERO;
    }
    // é€’归构建子节点
    private List<ProductTreeDto> buildChildrenNodes(Long parentId) {
src/main/java/com/ruoyi/basic/vo/ProductModelVo.java
@@ -4,11 +4,16 @@
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@EqualsAndHashCode(callSuper = true)
@Data
public class ProductModelVo extends ProductModel {
    private List<String> batchNoList;
    private HashMap<String, List<Map<String, BigDecimal>>> batchNoMaps;
}
src/main/java/com/ruoyi/procurementrecord/utils/StockUtils.java
@@ -34,7 +34,7 @@
    private final StockInventoryMapper stockInventoryMapper;
    /**
     * ä¸åˆæ ¼å…¥åº“
     * æ¶“嶅悎鏍煎叆搴?
     *
     * @param productModelId
     * @param quantity
@@ -47,11 +47,11 @@
        stockUninventoryDto.setRecordType(String.valueOf(recordType));
        stockUninventoryDto.setQualitity(quantity);
        stockUninventoryDto.setProductModelId(productModelId);
        stockUninventoryService.addStockInRecordOnly(stockUninventoryDto);
        stockUninventoryService.addStockUninventory(stockUninventoryDto);
    }
    /**
     * ä¸åˆæ ¼å‡ºåº“
     * æ¶“嶅悎鏍煎嚭搴?
     *
     * @param productModelId
     * @param quantity
@@ -68,38 +68,49 @@
    }
    /**
     * åˆæ ¼å…¥åº“
     * éšå Ÿç‰¸éãƒ¥ç°±
     * @param recordType
     * @param recordId
     */
    public void addStock(Long productModelId, BigDecimal quantity, String recordType, Long recordId) {
        addStock(productModelId, quantity, recordType, recordId, resolveWarehouseInfoId(null, productModelId, null));
    }
    public void addStock(Long productModelId, BigDecimal quantity, String recordType, Long recordId, Long warehouseInfoId) {
        StockInventoryDto stockInventoryDto = new StockInventoryDto();
        stockInventoryDto.setRecordId(recordId);
        stockInventoryDto.setRecordType(String.valueOf(recordType));
        stockInventoryDto.setQualitity(quantity);
        stockInventoryDto.setProductModelId(productModelId);
        stockInventoryDto.setWarehouseInfoId(warehouseInfoId);
        stockInventoryService.addStockInRecordOnly(stockInventoryDto);
    }
    /**
     * åˆæ ¼å…¥åº“带批次号
     * éšå Ÿç‰¸éãƒ¥ç°±ç”¯ï¸½å£’娆″彿
     * @param productModelId
     * @param quantity
     * @param recordType
     * @param recordId
     */
    public StockInRecordDto addStockWithBatchNo(Long productModelId, BigDecimal quantity, String recordType, Long recordId, String batchNo) {
        return addStockWithBatchNo(productModelId, quantity, recordType, recordId, batchNo,
                resolveWarehouseInfoId(null, productModelId, batchNo));
    }
    public StockInRecordDto addStockWithBatchNo(Long productModelId, BigDecimal quantity, String recordType, Long recordId, String batchNo, Long warehouseInfoId) {
        StockInventoryDto stockInventoryDto = new StockInventoryDto();
        stockInventoryDto.setRecordId(recordId);
        stockInventoryDto.setRecordType(String.valueOf(recordType));
        stockInventoryDto.setQualitity(quantity);
        stockInventoryDto.setProductModelId(productModelId);
        stockInventoryDto.setBatchNo(batchNo);
       return stockInventoryService.addStockInRecordOnly(stockInventoryDto);
        stockInventoryDto.setWarehouseInfoId(warehouseInfoId);
        return stockInventoryService.addStockInRecordOnly(stockInventoryDto);
    }
    /**
     * åˆæ ¼å‡ºåº“
     * éšå Ÿç‰¸é‘å“„ç°±
     *
     * @param productModelId
     * @param quantity
@@ -107,26 +118,36 @@
     * @param recordId
     */
    public void substractStock(Long productModelId, BigDecimal quantity, String recordType, Long recordId) {
        substractStock(productModelId, quantity, recordType, recordId, resolveWarehouseInfoId(null, productModelId, null));
    }
    public void substractStock(Long productModelId, BigDecimal quantity, String recordType, Long recordId, Long warehouseInfoId) {
        StockInventoryDto stockInventoryDto = new StockInventoryDto();
        stockInventoryDto.setRecordId(recordId);
        stockInventoryDto.setRecordType(String.valueOf(recordType));
        stockInventoryDto.setQualitity(quantity);
        stockInventoryDto.setProductModelId(productModelId);
        stockInventoryDto.setWarehouseInfoId(warehouseInfoId);
        stockInventoryService.subtractStockInventory(stockInventoryDto);
    }
    public StockOutRecordDto substractStock(Long productModelId, BigDecimal quantity, String recordType, Long recordId, String batchNo) {
        return substractStock(productModelId, quantity, recordType, recordId, batchNo,
                resolveWarehouseInfoId(null, productModelId, batchNo));
    }
    public StockOutRecordDto substractStock(Long productModelId, BigDecimal quantity, String recordType, Long recordId, String batchNo, Long warehouseInfoId) {
        StockInventoryDto stockInventoryDto = new StockInventoryDto();
        stockInventoryDto.setRecordId(recordId);
        stockInventoryDto.setRecordType(String.valueOf(recordType));
        stockInventoryDto.setQualitity(quantity);
        stockInventoryDto.setProductModelId(productModelId);
        stockInventoryDto.setBatchNo(batchNo);
       return stockInventoryService.addStockOutRecordOnly(stockInventoryDto);
        stockInventoryDto.setWarehouseInfoId(warehouseInfoId);
        return stockInventoryService.addStockOutRecordOnly(stockInventoryDto);
    }
    /**
     * å‘货审批状态更改
     * @param recordType
     * @param recordId
     */
@@ -138,18 +159,18 @@
        stockOutRecordService.updateById(stockOutRecord);
    }
    //不合格库存删除
    public void deleteStockInRecord(Long recordId, String recordType) {
        StockInRecord one = stockInRecordService.getOne(new QueryWrapper<StockInRecord>()
                .lambda().eq(StockInRecord::getRecordId, recordId)
                .eq(StockInRecord::getRecordType, recordType));
        if (ObjectUtils.isNotEmpty(one)) {
            stockInRecordService.batchDelete(Collections.singletonList(one.getId()));
            //将库存减回来
            StockInventoryDto stockInventoryDto = new StockInventoryDto();
            stockInventoryDto.setRecordId(recordId);
            stockInventoryDto.setRecordType(recordType);
            stockInventoryDto.setQualitity(one.getStockInNum());
            stockInventoryDto.setProductModelId(one.getProductModelId());
            stockInventoryDto.setBatchNo(one.getBatchNo());
            stockInventoryMapper.updateSubtractStockInventory((stockInventoryDto));
        }
@@ -161,13 +182,22 @@
                .eq(StockOutRecord::getRecordType, recordType));
        if (ObjectUtils.isNotEmpty(one)) {
            stockOutRecordService.batchDelete(Collections.singletonList(one.getId()));
            //将库存加回来
            StockInventoryDto stockInventoryDto = new StockInventoryDto();
            stockInventoryDto.setRecordId(recordId);
            stockInventoryDto.setRecordType(recordType);
            stockInventoryDto.setQualitity(one.getStockOutNum());
            stockInventoryDto.setProductModelId(one.getProductModelId());
            stockInventoryDto.setBatchNo(one.getBatchNo());
            stockInventoryDto.setWarehouseInfoId(one.getWarehouseInfoId());
            stockInventoryMapper.updateAddStockInventory((stockInventoryDto));
        }
    }
    private Long resolveWarehouseInfoId(Long warehouseInfoId, Long productModelId, String batchNo) {
        if (warehouseInfoId == null) {
            throw new IllegalArgumentException("warehouseInfoId不能为空");
        }
        return warehouseInfoId;
    }
}
src/main/java/com/ruoyi/production/service/impl/ProductionOrderPickServiceImpl.java
@@ -3,7 +3,6 @@
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.enums.ReviewStatusEnum;
import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum;
import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum;
import com.ruoyi.common.exception.ServiceException;
@@ -23,8 +22,8 @@
import com.ruoyi.stock.pojo.StockInRecord;
import com.ruoyi.stock.pojo.StockInventory;
import com.ruoyi.stock.pojo.StockOutRecord;
import com.ruoyi.stock.service.StockInventoryService;
import com.ruoyi.stock.service.StockInRecordService;
import com.ruoyi.stock.service.StockInventoryService;
import com.ruoyi.stock.service.StockOutRecordService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
@@ -96,7 +95,7 @@
            baseMapper.insert(orderPick);
            // å…ˆæ–°å¢žå‡ºåº“申请,再审批通过,完成库存扣减。
            subtractInventory(orderPick.getId(), resolvedDto.getProductModelId(), storedBatchNo, resolvedDto.getPickQuantity(), rowNo, PICK_STOCK_OUT_RECORD_TYPE);
//            subtractInventory(orderPick.getId(), resolvedDto.getProductModelId(), storedBatchNo, resolvedDto.getPickQuantity(), rowNo, PICK_STOCK_OUT_RECORD_TYPE);
            // è®°å½•本次领料流水(before=0,after=本次领料量)。
            insertPickRecord(orderPick.getId(),
@@ -216,7 +215,7 @@
            }
            String oldBatchNo = resolveInventoryBatchNoFromStored(existingPick.getBatchNo());
            BigDecimal oldQuantity = defaultDecimal(existingPick.getQuantity());
            addInventory(existingPick.getId(), existingPick.getProductModelId(), oldBatchNo, oldQuantity, PICK_RETURN_IN_RECORD_TYPE);
//            addInventory(existingPick.getId(), existingPick.getProductModelId(), oldBatchNo, oldQuantity, PICK_RETURN_IN_RECORD_TYPE);
            // åˆ é™¤å…³è”领料流水,避免遗留无主记录。
            productionOrderPickRecordMapper.delete(
                    Wrappers.<ProductionOrderPickRecord>lambdaQuery()
@@ -260,7 +259,7 @@
        for (ProductionOrderPick missingPick : missingPickList) {
            String oldBatchNo = resolveInventoryBatchNoFromStored(missingPick.getBatchNo());
            BigDecimal oldQuantity = defaultDecimal(missingPick.getQuantity());
            addInventory(missingPick.getId(), missingPick.getProductModelId(), oldBatchNo, oldQuantity, PICK_RETURN_IN_RECORD_TYPE);
//            addInventory(missingPick.getId(), missingPick.getProductModelId(), oldBatchNo, oldQuantity, PICK_RETURN_IN_RECORD_TYPE);
            // åˆ é™¤å…³è”领料流水,避免遗留无主记录。
            productionOrderPickRecordMapper.delete(
                    Wrappers.<ProductionOrderPickRecord>lambdaQuery()
@@ -306,7 +305,7 @@
        baseMapper.insert(orderPick);
        // å…ˆæ–°å¢žå‡ºåº“申请,再审批通过,完成库存扣减。
        subtractInventory(orderPick.getId(), dto.getProductModelId(), storedBatchNo, dto.getPickQuantity(), rowNo, PICK_STOCK_OUT_RECORD_TYPE);
//        subtractInventory(orderPick.getId(), dto.getProductModelId(), storedBatchNo, dto.getPickQuantity(), rowNo, PICK_STOCK_OUT_RECORD_TYPE);
        insertPickRecord(orderPick.getId(),
                dto.getProductionOrderId(),
@@ -365,7 +364,7 @@
                : formatBatchNoStorage(batchNoList);
        BigDecimal feedingQuantity = dto.getFeedingQuantity();
        subtractInventory(oldPick.getId(), productModelId, inventoryBatchNo, feedingQuantity, rowNo, FEED_STOCK_OUT_RECORD_TYPE);
//        subtractInventory(oldPick.getId(), productModelId, inventoryBatchNo, feedingQuantity, rowNo, FEED_STOCK_OUT_RECORD_TYPE);
        // è®¡ç®—补料前后数量并写补料流水。
        BigDecimal beforeFeedingQty = sumFeedingQuantity(dto.getProductionOrderId(), oldPick.getId());
@@ -430,7 +429,7 @@
        BigDecimal totalReturnQty = oldReturnQty.add(currentReturnQty);
        if (currentReturnQty.compareTo(BigDecimal.ZERO) > 0) {
            String returnBatchNo = resolveInventoryBatchNoFromStored(oldPick.getBatchNo());
            addInventoryRecordOnly(oldPick.getId(), oldPick.getProductModelId(), returnBatchNo, currentReturnQty, FEED_RETURN_IN_RECORD_TYPE);
//            addInventoryRecordOnly(oldPick.getId(), oldPick.getProductModelId(), returnBatchNo, currentReturnQty, FEED_RETURN_IN_RECORD_TYPE);
        }
        BigDecimal actualQty = defaultDecimal(oldPick.getQuantity())
@@ -487,15 +486,15 @@
            BigDecimal deltaQuantity = newQuantity.subtract(oldQuantity);
            if (deltaQuantity.compareTo(BigDecimal.ZERO) > 0) {
                // æ•°é‡å¢žåŠ ï¼Œåªæ‰£å‡æ–°å¢žéƒ¨åˆ†ã€‚
                subtractInventory(oldPick.getId(), newProductModelId, newStoredBatchNo, deltaQuantity, rowNo, PICK_STOCK_OUT_RECORD_TYPE);
//                subtractInventory(oldPick.getId(), newProductModelId, newStoredBatchNo, deltaQuantity, rowNo, PICK_STOCK_OUT_RECORD_TYPE);
            } else if (deltaQuantity.compareTo(BigDecimal.ZERO) < 0) {
                // æ•°é‡å‡å°‘,只回退差值部分。
                addInventory(oldPick.getId(), oldProductModelId, oldBatchNo, deltaQuantity.abs(), PICK_RETURN_IN_RECORD_TYPE);
//                addInventory(oldPick.getId(), oldProductModelId, oldBatchNo, deltaQuantity.abs(), PICK_RETURN_IN_RECORD_TYPE);
            }
        } else {
            // è§„格或批次变化:先全量回退旧领料,再全量扣减新领料。
            addInventory(oldPick.getId(), oldProductModelId, oldBatchNo, oldQuantity, PICK_RETURN_IN_RECORD_TYPE);
            subtractInventory(oldPick.getId(), newProductModelId, newStoredBatchNo, newQuantity, rowNo, PICK_STOCK_OUT_RECORD_TYPE);
//            addInventory(oldPick.getId(), oldProductModelId, oldBatchNo, oldQuantity, PICK_RETURN_IN_RECORD_TYPE);
//            subtractInventory(oldPick.getId(), newProductModelId, newStoredBatchNo, newQuantity, rowNo, PICK_STOCK_OUT_RECORD_TYPE);
        }
        if (needReissuePickRecord) {
            // æ­£å¸¸é¢†æ–™æµæ°´æŒ‰â€œæœ€æ–°é¢†æ–™é‡â€é‡å»ºï¼Œé¿å…ä¿ç•™åŽ†å²æ—§å€¼ã€‚
@@ -635,7 +634,7 @@
                continue;
            }
            BigDecimal currentDeductQuantity = remainingQuantity.min(availableQuantity);
            createAndApproveStockOutRecord(recordId, productModelId, entry.getKey(), currentDeductQuantity, rowNo, stockOutRecordType);
//            createAndApproveStockOutRecord(recordId, productModelId, entry.getKey(), currentDeductQuantity, rowNo, stockOutRecordType);
            remainingQuantity = remainingQuantity.subtract(currentDeductQuantity);
        }
@@ -674,14 +673,14 @@
            } else {
                recordWrapper.eq(StockOutRecord::getBatchNo, batchNo);
            }
            StockOutRecord stockOutRecord = stockOutRecordService.getOne(recordWrapper, false);
            if (stockOutRecord == null || stockOutRecord.getId() == null) {
                throw new ServiceException("第" + rowNo + "行扣减库存失败:未找到对应出库申请记录");
            }
            stockOutRecordService.batchApprove(
                    Collections.singletonList(stockOutRecord.getId()),
                    ReviewStatusEnum.APPROVED.getCode()
            );
//            StockOutRecord stockOutRecord = stockOutRecordService.getOne(recordWrapper, false);
//            if (stockOutRecord == null || stockOutRecord.getId() == null) {
//                throw new ServiceException("第" + rowNo + "行扣减库存失败:未找到对应出库申请记录");
//            }
//            stockOutRecordService.batchApprove(
//                    Collections.singletonList(stockOutRecord.getId()),
//                    ReviewStatusEnum.APPROVED.getCode()
//            );
        } catch (ServiceException ex) {
            throw ex;
        } catch (Exception ex) {
@@ -726,10 +725,10 @@
            if (stockInRecord == null || stockInRecord.getId() == null) {
                throw new ServiceException("回补库存失败:未找到对应入库申请记录");
            }
            stockInRecordService.batchApprove(
                    Collections.singletonList(stockInRecord.getId()),
                    ReviewStatusEnum.APPROVED.getCode()
            );
//            stockInRecordService.batchApprove(
//                    Collections.singletonList(stockInRecord.getId()),
//                    ReviewStatusEnum.APPROVED.getCode(),stockInRecord.getWarehouseInfoId()
//            );
        } catch (ServiceException ex) {
            throw ex;
        } catch (Exception ex) {
src/main/java/com/ruoyi/production/service/impl/ProductionProductMainServiceImpl.java
@@ -9,12 +9,8 @@
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.basic.mapper.ProductMapper;
import com.ruoyi.basic.mapper.ProductModelMapper;
import com.ruoyi.basic.pojo.Product;
import com.ruoyi.basic.pojo.ProductModel;
import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum;
import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.procurementrecord.utils.StockUtils;
import com.ruoyi.production.bean.dto.ProductStructureDto;
import com.ruoyi.production.bean.dto.ProductionProductMainDto;
@@ -25,8 +21,7 @@
import com.ruoyi.project.system.domain.SysUser;
import com.ruoyi.project.system.mapper.SysUserMapper;
import com.ruoyi.quality.mapper.*;
import com.ruoyi.quality.pojo.*;
import com.ruoyi.stock.dto.StockInventoryDto;
import com.ruoyi.quality.pojo.QualityInspect;
import com.ruoyi.stock.service.StockInventoryService;
import com.ruoyi.technology.mapper.TechnologyOperationMapper;
import com.ruoyi.technology.mapper.TechnologyRoutingOperationMapper;
@@ -40,15 +35,7 @@
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.*;
import java.util.stream.Collectors;
@Service
@@ -314,45 +301,45 @@
                        .eq(ProductionOrderRoutingOperation::getProductionOrderId, routingOperation.getProductionOrderId()));
        boolean isLastOperation = routingOperation.getDragSort() != null && routingOperation.getDragSort().equals(routingOperationList.size());
        if (productQty.compareTo(BigDecimal.ZERO) > 0) {
            if (Boolean.TRUE.equals(routingOperation.getIsQuality())) {
                // è´¨æ£€å·¥åºå…ˆç”Ÿæˆæ£€éªŒå•,非质检工序直接入合格品库存。
                int inspectType = isLastOperation ? 2 : 1;
                String process = isLastOperation ? null : technologyOperation == null ? null : technologyOperation.getName();
                Product product = productMapper.selectById(productModel.getProductId());
                QualityInspect qualityInspect = new QualityInspect();
                qualityInspect.setProductId(product.getId());
                qualityInspect.setProductName(product.getProductName());
                qualityInspect.setModel(productModel.getModel());
                qualityInspect.setUnit(productModel.getUnit());
                qualityInspect.setQuantity(productQty);
                qualityInspect.setProcess(process);
                qualityInspect.setInspectState(0);
                qualityInspect.setInspectType(inspectType);
                qualityInspect.setProductMainId(productionProductMain.getId());
                qualityInspect.setProductModelId(productModel.getId());
                qualityInspectMapper.insert(qualityInspect);
                List<QualityTestStandard> qualityTestStandard = qualityTestStandardMapper.getQualityTestStandardByProductId(product.getId(), inspectType, process);
                if (!qualityTestStandard.isEmpty()) {
                    qualityInspect.setTestStandardId(qualityTestStandard.get(0).getId());
                    qualityInspectMapper.updateById(qualityInspect);
                    qualityTestStandardParamMapper.selectList(Wrappers.<QualityTestStandardParam>lambdaQuery()
                                    .eq(QualityTestStandardParam::getTestStandardId, qualityTestStandard.get(0).getId()))
                            .forEach(qualityTestStandardParam -> {
                                QualityInspectParam param = new QualityInspectParam();
                                BeanUtils.copyProperties(qualityTestStandardParam, param);
                                param.setId(null);
                                param.setInspectId(qualityInspect.getId());
                                qualityInspectParamMapper.insert(param);
                            });
                }
            } else {
                StockInventoryDto stockInventoryDto = new StockInventoryDto();
                stockInventoryDto.setRecordId(productionProductMain.getId());
                stockInventoryDto.setRecordType(String.valueOf(StockInQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_IN.getCode()));
                stockInventoryDto.setQualitity(productQty);
                stockInventoryDto.setProductModelId(productModel.getId());
                stockInventoryService.addStockInRecordOnly(stockInventoryDto);
            }
//            if (Boolean.TRUE.equals(routingOperation.getIsQuality())) {
//                // è´¨æ£€å·¥åºå…ˆç”Ÿæˆæ£€éªŒå•,非质检工序直接入合格品库存。
//                int inspectType = isLastOperation ? 2 : 1;
//                String process = isLastOperation ? null : technologyOperation == null ? null : technologyOperation.getName();
//                Product product = productMapper.selectById(productModel.getProductId());
//                QualityInspect qualityInspect = new QualityInspect();
//                qualityInspect.setProductId(product.getId());
//                qualityInspect.setProductName(product.getProductName());
//                qualityInspect.setModel(productModel.getModel());
//                qualityInspect.setUnit(productModel.getUnit());
//                qualityInspect.setQuantity(productQty);
//                qualityInspect.setProcess(process);
//                qualityInspect.setInspectState(0);
//                qualityInspect.setInspectType(inspectType);
//                qualityInspect.setProductMainId(productionProductMain.getId());
//                qualityInspect.setProductModelId(productModel.getId());
//                qualityInspectMapper.insert(qualityInspect);
//                List<QualityTestStandard> qualityTestStandard = qualityTestStandardMapper.getQualityTestStandardByProductId(product.getId(), inspectType, process);
//                if (!qualityTestStandard.isEmpty()) {
//                    qualityInspect.setTestStandardId(qualityTestStandard.get(0).getId());
//                    qualityInspectMapper.updateById(qualityInspect);
//                    qualityTestStandardParamMapper.selectList(Wrappers.<QualityTestStandardParam>lambdaQuery()
//                                    .eq(QualityTestStandardParam::getTestStandardId, qualityTestStandard.get(0).getId()))
//                            .forEach(qualityTestStandardParam -> {
//                                QualityInspectParam param = new QualityInspectParam();
//                                BeanUtils.copyProperties(qualityTestStandardParam, param);
//                                param.setId(null);
//                                param.setInspectId(qualityInspect.getId());
//                                qualityInspectParamMapper.insert(param);
//                            });
//                }
//            } else {
//                StockInventoryDto stockInventoryDto = new StockInventoryDto();
//                stockInventoryDto.setRecordId(productionProductMain.getId());
//                stockInventoryDto.setRecordType(String.valueOf(StockInQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_IN.getCode()));
//                stockInventoryDto.setQualitity(productQty);
//                stockInventoryDto.setProductModelId(productModel.getId());
//                stockInventoryService.addStockInRecordOnly(stockInventoryDto);
//            }
            productionOperationTask.setCompleteQuantity(defaultDecimal(productionOperationTask.getCompleteQuantity()).add(productQty));
            if (ObjectUtils.isNull(productionOperationTask.getActualStartTime())) {
@@ -529,15 +516,15 @@
        List<QualityInspect> qualityInspects = qualityInspectMapper.selectList(
                Wrappers.<QualityInspect>lambdaQuery().eq(QualityInspect::getProductMainId, productionProductMain.getId()));
        // å‚数与前置条件校验
        if (qualityInspects.size() > 0) {
            List<QualityUnqualified> qualityUnqualifieds = qualityUnqualifiedMapper.selectList(
                    Wrappers.<QualityUnqualified>lambdaQuery()
        // éåŽ†å¤„ç†æ•°æ®å¹¶ç»„è£…ç»“æžœ
                            .in(QualityUnqualified::getInspectId, qualityInspects.stream().map(QualityInspect::getId).collect(Collectors.toList())));
            if (qualityUnqualifieds.size() > 0 && qualityUnqualifieds.get(0).getInspectState() == 1) {
                throw new ServiceException("该条报工已经不合格处理了,不允许删除");
            }
        }
//        if (!qualityInspects.isEmpty()) {
//            List<QualityUnqualified> qualityUnqualifieds = qualityUnqualifiedMapper.selectList(
//                    Wrappers.<QualityUnqualified>lambdaQuery()
//        // éåŽ†å¤„ç†æ•°æ®å¹¶ç»„è£…ç»“æžœ
//                            .in(QualityUnqualified::getInspectId, qualityInspects.stream().map(QualityInspect::getId).collect(Collectors.toList())));
//            if (!qualityUnqualifieds.isEmpty() && qualityUnqualifieds.getFirst().getInspectState() == 1) {
//                throw new ServiceException("该条报工已经不合格处理了,不允许删除");
//            }
//        }
        ProductionProductOutput productionProductOutput = productionProductOutputMapper.selectList(
                Wrappers.<ProductionProductOutput>lambdaQuery()
                        .eq(ProductionProductOutput::getProductionProductMainId, productionProductMain.getId()))
@@ -584,13 +571,13 @@
            }
        }
        qualityInspectMapper.selectList(new LambdaQueryWrapper<QualityInspect>()
                .eq(QualityInspect::getProductMainId, productionProductMain.getId())).forEach(q -> {
            qualityInspectParamMapper.delete(new LambdaQueryWrapper<QualityInspectParam>()
                    .eq(QualityInspectParam::getInspectId, q.getId()));
            qualityInspectMapper.deleteById(q.getId());
            stockUtils.deleteStockInRecord(q.getId(), StockInQualifiedRecordTypeEnum.QUALITYINSPECT_STOCK_IN.getCode());
        });
//        qualityInspectMapper.selectList(new LambdaQueryWrapper<QualityInspect>()
//                .eq(QualityInspect::getProductMainId, productionProductMain.getId())).forEach(q -> {
//            qualityInspectParamMapper.delete(new LambdaQueryWrapper<QualityInspectParam>()
//                    .eq(QualityInspectParam::getInspectId, q.getId()));
//            qualityInspectMapper.deleteById(q.getId());
//            stockUtils.deleteStockInRecord(q.getId(), StockInQualifiedRecordTypeEnum.QUALITYINSPECT_STOCK_IN.getCode());
//        });
        productionProductOutputMapper.delete(new LambdaQueryWrapper<ProductionProductOutput>()
                .eq(ProductionProductOutput::getProductionProductMainId, productionProductMain.getId()));
        productionProductInputMapper.delete(new LambdaQueryWrapper<ProductionProductInput>()
@@ -598,9 +585,9 @@
        productionOrderRoutingOperationParamMapper.delete(
                Wrappers.<ProductionOrderRoutingOperationParam>lambdaQuery()
                        .eq(ProductionOrderRoutingOperationParam::getProductionProductMainId, productionProductMain.getId()));
        stockUtils.deleteStockInRecord(productionProductMain.getId(), StockInQualifiedRecordTypeEnum.PRODUCTION_SCRAP.getCode());
        stockUtils.deleteStockInRecord(productionProductMain.getId(), StockInQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_IN.getCode());
        stockUtils.deleteStockOutRecord(productionProductMain.getId(), StockOutQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_OUT.getCode());
//        stockUtils.deleteStockInRecord(productionProductMain.getId(), StockInQualifiedRecordTypeEnum.PRODUCTION_SCRAP.getCode());
//        stockUtils.deleteStockInRecord(productionProductMain.getId(), StockInQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_IN.getCode());
//        stockUtils.deleteStockOutRecord(productionProductMain.getId(), StockOutQualifiedRecordTypeEnum.PRODUCTION_REPORT_STOCK_OUT.getCode());
        productionProductMainMapper.deleteById(productionProductMain.getId());
        return true;
    }
src/main/java/com/ruoyi/purchase/pojo/PurchaseReturnOrders.java
@@ -18,7 +18,7 @@
/**
 * <p>
 *
 *
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
src/main/java/com/ruoyi/purchase/service/impl/PurchaseLedgerServiceImpl.java
@@ -180,7 +180,7 @@
            handleSalesLedgerProducts(purchaseLedger.getId(), productList, purchaseLedgerDto.getType());
        }
        // 6.采购审核新增;审批管理未配置采购审批人时,审批服务会自动置为审批通过。
        addApproveByPurchase(loginUser, purchaseLedger);
//        addApproveByPurchase(loginUser, purchaseLedger);
        // 5. è¿ç§»ä¸´æ—¶æ–‡ä»¶åˆ°æ­£å¼ç›®å½•
        fileUtil.saveStorageAttachment(ApplicationTypeEnum.FILE, RecordTypeEnum.PURCHASE_LEDGER, purchaseLedger.getId(), purchaseLedgerDto.getStorageBlobDTOS());
        return 1;
@@ -637,7 +637,7 @@
                    salesLedgerProductMapper.insert(salesLedgerProduct);
                }
                // é‡‡è´­å®¡æ ¸
                addApproveByPurchase(loginUser,salesLedger);
//                addApproveByPurchase(loginUser,salesLedger);
            }
            return AjaxResult.success("导入成功");
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerProductServiceImpl.java
@@ -34,6 +34,7 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
import java.lang.reflect.Field;
import java.math.BigDecimal;
@@ -263,7 +264,7 @@
     */
    public void addProductionData(SalesLedgerProduct salesLedgerProduct) {
        //先判断该产品是否需要生产
        if (!salesLedgerProduct.getIsProduction()) {
        if (ObjectUtils.isEmpty(salesLedgerProduct.getIsProduction()) || !salesLedgerProduct.getIsProduction()) {
            return;
        }
        SalesLedger salesLedger = salesLedgerMapper.selectById(salesLedgerProduct.getSalesLedgerId());
src/main/java/com/ruoyi/stock/controller/StockInRecordController.java
@@ -66,7 +66,7 @@
        if(CollectionUtils.isEmpty(approveDto.getIds())){
            return AjaxResult.error("请选择至少一条数据");
        }
        stockInRecordService.batchApprove(approveDto.getIds(), approveDto.getApprovalStatus());
        stockInRecordService.batchApprove(approveDto.getIds(), approveDto.getApprovalStatus(),approveDto.getWarehouseInfoId());
        return AjaxResult.success();
    }
src/main/java/com/ruoyi/stock/controller/StockOutRecordController.java
@@ -83,7 +83,7 @@
        if(CollectionUtils.isEmpty(approveDto.getIds())){
            return AjaxResult.error("请选择至少一条数据");
        }
        stockOutRecordService.batchApprove(approveDto.getIds(), approveDto.getApprovalStatus());
        stockOutRecordService.batchApprove(approveDto.getIds(), approveDto.getApprovalStatus(),approveDto.getWarehouseInfoId());
        return AjaxResult.success();
    }
src/main/java/com/ruoyi/stock/controller/WarehouseInfoController.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,63 @@
package com.ruoyi.stock.controller;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.stock.dto.WarehouseInfoDto;
import com.ruoyi.stock.pojo.WarehouseInfo;
import com.ruoyi.stock.service.WarehouseInfoService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.AllArgsConstructor;
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
/**
 * <p>
 * ä»“库信息表 å‰ç«¯æŽ§åˆ¶å™¨
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-05-12 05:44:22
 */
@RestController
@RequestMapping("/warehouseInfo")
@AllArgsConstructor
@Tag(name = "仓库信息表")
public class WarehouseInfoController {
    private final WarehouseInfoService warehouseInfoService;
    @GetMapping("/listPage")
    @Operation(summary = "分页查询")
    public R listPage(Page  page, WarehouseInfoDto warehouseInfoDto) {
        return R.ok(warehouseInfoService.listPage(page, warehouseInfoDto));
    }
    @PostMapping("/add")
    @Operation(summary = "添加")
    public R add(@RequestBody WarehouseInfoDto warehouseInfoDto) {
        return R.ok(warehouseInfoService.save(warehouseInfoDto));
    }
    @PostMapping("/edit")
    @Operation(summary = "修改")
    public R edit(@RequestBody WarehouseInfoDto warehouseInfoDto) {
        return R.ok(warehouseInfoService.updateById(warehouseInfoDto));
    }
    @PostMapping("/delete")
    @Operation(summary = "删除")
    public R delete(@RequestBody ArrayList<Long> ids) {
        return R.ok(warehouseInfoService.deleteByIds(ids));
    }
    @GetMapping("/list")
    @Operation(summary = "查询仓库信息")
    public R list() {
        return R.ok(warehouseInfoService.list(new LambdaQueryWrapper<WarehouseInfo>().eq(WarehouseInfo::getStatus, true)));
    }
}
src/main/java/com/ruoyi/stock/dto/StockInRecordDto.java
@@ -35,4 +35,7 @@
    @Schema(description = "记录ID列表")
    private List<Long> ids;
    @Schema(description = "仓库名称")
    private String warehouseName;
}
src/main/java/com/ruoyi/stock/dto/StockInventoryDto.java
@@ -77,4 +77,6 @@
    @Schema(description = "不合格库存ID")
    private Long unQualifiedId;
    private String warehouseName;
}
src/main/java/com/ruoyi/stock/dto/StockOutRecordDto.java
@@ -34,4 +34,7 @@
    @Schema(description = "记录ID列表")
    private List<Long> ids;
    @Schema(description = "仓库名称")
    private String warehouseName;
}
src/main/java/com/ruoyi/stock/dto/StockUninventoryDto.java
@@ -19,4 +19,6 @@
    private Long recordId;
    private BigDecimal unLockedQuantity;
    private String warehouseName;
}
src/main/java/com/ruoyi/stock/dto/WarehouseInfoDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,8 @@
package com.ruoyi.stock.dto;
import com.ruoyi.stock.pojo.WarehouseInfo;
import lombok.Data;
@Data
public class WarehouseInfoDto extends WarehouseInfo {
}
src/main/java/com/ruoyi/stock/execl/StockInventoryExportData.java
@@ -19,6 +19,12 @@
    @Excel(name = "单位")
    private String unit;
    @Excel(name = "仓库名称")
    private String warehouseName;
    @Excel(name = "批号")
    private String batchNo;
    @Excel(name = "合格库存数量")
    private BigDecimal qualifiedQuantity;
src/main/java/com/ruoyi/stock/mapper/StockInventoryMapper.java
@@ -13,6 +13,7 @@
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -51,7 +52,7 @@
    BigDecimal selectTotalByDate(@Param("now") LocalDate now);
    BigDecimal selectPendingOutQuantity(@Param("productModelId") Long productModelId, @Param("batchNo") String batchNo, @Param("type") String type);
    BigDecimal selectPendingOutQuantity(@Param("productModelId") Long productModelId, @Param("batchNo") String batchNo, @Param("warehouseInfoId") Long warehouseInfoId, @Param("type") String type);
    List<StockInventory> listSelectableBatchNoByProductModelIds(@Param("productModelIds") List<Long> productModelIds);
@@ -62,4 +63,6 @@
    IPage<StockInventoryDto> pagestockInventoryNoQua(Page page, @Param("ew") StockInventoryDto stockInventoryDto);
    int updateLocked(@Param("productModelId") Long productModelId, @Param("batchNo") String batchNo, @Param("locked") boolean b);
    Long existsUsed(@Param("ids") ArrayList<Long> ids);
}
src/main/java/com/ruoyi/stock/mapper/WarehouseInfoMapper.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,23 @@
package com.ruoyi.stock.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.stock.dto.WarehouseInfoDto;
import com.ruoyi.stock.pojo.WarehouseInfo;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
/**
 * <p>
 * ä»“库信息表 Mapper æŽ¥å£
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-05-12 05:44:22
 */
@Mapper
public interface WarehouseInfoMapper extends BaseMapper<WarehouseInfo> {
    IPage<WarehouseInfoDto> listPage(Page page,@Param("ew") WarehouseInfoDto warehouseInfoDto);
}
src/main/java/com/ruoyi/stock/pojo/StockInRecord.java
@@ -71,4 +71,6 @@
    @TableField(fill = FieldFill.INSERT)
    private Long deptId;
    private Long warehouseInfoId;
}
src/main/java/com/ruoyi/stock/pojo/StockInventory.java
@@ -74,4 +74,8 @@
    @Schema(description = "是否锁定")
    private Boolean locked;
    @Schema(description = "仓库id")
    @TableField("warehouse_info_id")
    private Long warehouseInfoId;
}
src/main/java/com/ruoyi/stock/pojo/StockInventoryCheckItem.java
@@ -78,6 +78,12 @@
    private String batchNo;
    /**
     * ä»“库ID
     */
    @Schema(description ="仓库ID")
    private Long warehouseInfoId;
    /**
     * ç³»ç»Ÿåº“存数量
     */
    @Schema(description ="系统库存数量")
@@ -119,6 +125,6 @@
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;
    @TableField(fill = FieldFill.INSERT)
    private Long deptId;
}
src/main/java/com/ruoyi/stock/pojo/StockInventoryCheckMain.java
@@ -124,6 +124,6 @@
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Long updateUser;
    @TableField(fill = FieldFill.INSERT)
    private Long deptId;
}
src/main/java/com/ruoyi/stock/pojo/StockInventoryCheckPlan.java
@@ -110,6 +110,6 @@
     */
    @Schema(description = "删除标志(0代表存在 1代表删除)")
    private String delFlag;
    @TableField(fill = FieldFill.INSERT)
    private Long deptId;
}
src/main/java/com/ruoyi/stock/pojo/StockInventoryCheckProduct.java
@@ -1,8 +1,6 @@
package com.ruoyi.stock.pojo;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import com.baomidou.mybatisplus.annotation.*;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Getter;
@@ -70,7 +68,8 @@
    @ApiModelProperty("创建人")
    @TableField(fill = FieldFill.INSERT)
    private int createUser;
    @TableField(fill = FieldFill.INSERT)
    private int deptId;
}
src/main/java/com/ruoyi/stock/pojo/StockOutRecord.java
@@ -31,19 +31,19 @@
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    @Schema(description = "入库批次")
    @Schema(description = "出库批次")
    private String outboundBatches;
    @Schema(description = "批号")
    private String batchNo;
    @Schema(description = "入库数量")
    @Schema(description = "出库数量")
    private BigDecimal stockOutNum;
    @Schema(description = "入库来源id")
    @Schema(description = "出库来源id")
    private Long recordId;
    @Schema(description = "入库类型")
    @Schema(description = "出库类型")
    private String recordType;
    @Schema(description = "产品规格id")
@@ -80,4 +80,7 @@
    @TableField(fill = FieldFill.INSERT)
    private Long deptId;
    @TableField("warehouse_info_id")
    private Long warehouseInfoId;
}
src/main/java/com/ruoyi/stock/pojo/WarehouseInfo.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,100 @@
package com.ruoyi.stock.pojo;
import com.baomidou.mybatisplus.annotation.*;
import com.fasterxml.jackson.annotation.JsonFormat;
import io.swagger.annotations.ApiModel;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.io.Serializable;
import java.time.LocalDateTime;
/**
 * <p>
 * ä»“库信息表
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-05-12 05:44:22
 */
@Data
@TableName("stock_warehouse_info")
@ApiModel(value = "WarehouseInfo对象", description = "仓库信息表")
public class WarehouseInfo implements Serializable {
    private static final long serialVersionUID = 1L;
    /**
     * ä¸»é”®ID
     */
    @Schema(description = "主键ID")
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    /**
     * ä»“库名称
     */
    @Schema(description = "仓库名称")
    private String warehouseName;
    /**
     * ä»“库位置
     */
    @Schema(description = "仓库位置")
    private String location;
    /**
     * è´Ÿè´£äºº
     */
    @Schema(description = "负责人")
    private String managerName;
    /**
     * è”系电话
     */
    @Schema(description = "联系电话")
    private String contactPhone;
    /**
     * çŠ¶æ€ï¼ˆ0停用 1启用)
     */
    @Schema(description = "状态(0停用 1启用)")
    private Boolean status;
    /**
     * å¤‡æ³¨
     */
    @Schema(description = "备注")
    private String remark;
    /**
     * åˆ›å»ºäººID
     */
    @Schema(description = "创建人ID")
    @TableField(fill = FieldFill.INSERT)
    private Long createUser;
    /**
     * éƒ¨é—¨ID
     */
    @Schema(description = "部门ID")
    @TableField(fill = FieldFill.INSERT)
    private Long deptId;
    /**
     * åˆ›å»ºæ—¶é—´
     */
    @Schema(description = "创建时间")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;
    /**
     * æ›´æ–°æ—¶é—´
     */
    @Schema(description = "更新时间")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;
}
src/main/java/com/ruoyi/stock/service/StockInRecordService.java
@@ -22,5 +22,5 @@
    void exportStockInRecord(HttpServletResponse response, StockInRecordDto stockInRecordDto);
    int batchApprove(List<Long> ids, Integer approvalStatus);
    int batchApprove(List<Long> ids, Integer approvalStatus,Long warehouseInfoId);
}
src/main/java/com/ruoyi/stock/service/StockInventoryService.java
@@ -28,7 +28,7 @@
    IPage<StockInventoryDto> pageListCombinedStockInventory(Page page, StockInventoryDto stockInventoryDto);
    Boolean addstockInventory(StockInventoryDto stockInventoryDto);
    StockInRecordDto addstockInventory(StockInventoryDto stockInventoryDto);
    StockOutRecordDto subtractStockInventory(StockInventoryDto stockInventoryDto);
src/main/java/com/ruoyi/stock/service/StockOutRecordService.java
@@ -30,5 +30,5 @@
    void exportStockOutRecord(HttpServletResponse response, StockOutRecordDto stockOutRecordDto);
    int batchApprove(List<Long> ids, Integer approvalStatus);
    int batchApprove(List<Long> ids, Integer approvalStatus,Long warehouseInfoId);
}
src/main/java/com/ruoyi/stock/service/WarehouseInfoService.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,24 @@
package com.ruoyi.stock.service;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.stock.dto.WarehouseInfoDto;
import com.ruoyi.stock.pojo.WarehouseInfo;
import com.baomidou.mybatisplus.extension.service.IService;
import java.util.ArrayList;
/**
 * <p>
 * ä»“库信息表 æœåŠ¡ç±»
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-05-12 05:44:22
 */
public interface WarehouseInfoService extends IService<WarehouseInfo> {
    IPage<WarehouseInfoDto> listPage(Page page, WarehouseInfoDto warehouseInfoDto);
    Boolean deleteByIds(ArrayList<Long> ids);
}
src/main/java/com/ruoyi/stock/service/impl/StockInRecordServiceImpl.java
@@ -78,13 +78,11 @@
        for (Long id : ids) {
            StockInRecord stockInRecord = stockInRecordMapper.selectById(id);
            if (stockInRecord.getType().equals("0")) {
                LambdaQueryWrapper<StockInventory> eq = new LambdaQueryWrapper<StockInventory>()
                        .eq(StockInventory::getProductModelId, stockInRecord.getProductModelId());
                if (StringUtils.isEmpty(stockInRecord.getBatchNo())) {
                    eq.isNull(StockInventory::getBatchNo);
                } else {
                    eq.eq(StockInventory::getBatchNo, stockInRecord.getBatchNo());
                }
                LambdaQueryWrapper<StockInventory> eq = buildQualifiedInventoryQuery(
                        stockInRecord.getProductModelId(),
                        stockInRecord.getBatchNo(),
                        stockInRecord.getWarehouseInfoId()
               );
                StockInventory stockInventory = stockInventoryMapper.selectOne(eq);
                if (stockInventory == null) {
                    throw new BaseException("库存记录中没有对应的产品,无法删除!!!");
@@ -92,6 +90,7 @@
                    StockInventoryDto stockInRecordDto = new StockInventoryDto();
                    stockInRecordDto.setProductModelId(stockInventory.getProductModelId());
                    stockInRecordDto.setBatchNo(stockInventory.getBatchNo());
                    stockInRecordDto.setWarehouseInfoId(stockInventory.getWarehouseInfoId());
                    stockInRecordDto.setQualitity(stockInRecord.getStockInNum());
                    stockInventoryMapper.updateSubtractStockInventory(stockInRecordDto);
                }
@@ -132,15 +131,8 @@
        util.exportExcel(response,list, "入库记录信息");
    }
    private StockInventory getStockInventory(Long productModelId, String batchNo) {
        LambdaQueryWrapper<StockInventory> eq = new LambdaQueryWrapper<>();
        eq.eq(StockInventory::getProductModelId, productModelId);
        if (StringUtils.isEmpty(batchNo)) {
            eq.isNull(StockInventory::getBatchNo);
        } else {
            eq.eq(StockInventory::getBatchNo, batchNo);
        }
        return stockInventoryMapper.selectOne(eq);
    private StockInventory getStockInventory(Long productModelId, String batchNo, Long warehouseInfoId) {
        return stockInventoryMapper.selectOne(buildQualifiedInventoryQuery(productModelId, batchNo, warehouseInfoId));
    }
    private StockUninventory getStockUninventory(Long productModelId, String batchNo) {
@@ -171,7 +163,7 @@
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int batchApprove(List<Long> ids, Integer approvalStatus) {
    public int batchApprove(List<Long> ids, Integer approvalStatus,Long warehouseInfoId) {
        if (CollectionUtils.isEmpty(ids)) {
            throw new BaseException("请选择至少一条数据");
        }
@@ -187,12 +179,17 @@
                throw new BaseException("只有待审批状态的记录才能审批,入库批次:" + stockInRecord.getInboundBatches());
            }
            stockInRecord.setApprovalStatus(approvalStatus);
            stockInRecord.setWarehouseInfoId(warehouseInfoId);
            stockInRecordMapper.updateById(stockInRecord);
            // å®¡æ‰¹é€šè¿‡æ—¶ï¼Œåº“存增加
            if (ReviewStatusEnum.APPROVED.getCode().equals(approvalStatus)) {
                if ("0".equals(stockInRecord.getType())) {
                    // åˆæ ¼å…¥åº“ -> å…ˆæŸ¥åº“存,存在则更新,不存在则新增
                    StockInventory stockInventory = getStockInventory(stockInRecord.getProductModelId(), stockInRecord.getBatchNo());
                    StockInventory stockInventory = getStockInventory(
                            stockInRecord.getProductModelId(),
                            stockInRecord.getBatchNo(),
                            warehouseInfoId
                    );
                    if (!ObjectUtils.isEmpty(stockInventory)) {
                        if (stockInventory.getLocked().equals( true)&&!stockInRecord.getRecordType().equals(StockInQualifiedRecordTypeEnum.INVENTORY_CHECK_STOCK_IN.getCode())) {
                            throw new BaseException("正在库存盘点,无法入库,入库批次:" + stockInRecord.getInboundBatches());
@@ -201,6 +198,7 @@
                    StockInventoryDto stockInventoryDto = new StockInventoryDto();
                    stockInventoryDto.setProductModelId(stockInRecord.getProductModelId());
                    stockInventoryDto.setBatchNo(stockInRecord.getBatchNo());
                    stockInventoryDto.setWarehouseInfoId(warehouseInfoId);
                    stockInventoryDto.setQualitity(stockInRecord.getStockInNum());
                    stockInventoryDto.setRemark(stockInRecord.getRemark());
                    if (stockInventory == null) {
@@ -209,6 +207,7 @@
                            setQualitity(stockInRecord.getStockInNum());
                            setBatchNo(stockInRecord.getBatchNo());
                            setRemark(stockInRecord.getRemark());
                            setWarehouseInfoId(warehouseInfoId);
                            setVersion(1);
                        }});
                    } else {
@@ -238,4 +237,18 @@
        }
        return ids.size();
    }
    private LambdaQueryWrapper<StockInventory> buildQualifiedInventoryQuery(Long productModelId, String batchNo, Long warehouseInfoId) {
        LambdaQueryWrapper<StockInventory> wrapper = new LambdaQueryWrapper<StockInventory>()
                .eq(StockInventory::getProductModelId, productModelId);
        if (warehouseInfoId != null) {
            wrapper.eq(StockInventory::getWarehouseInfoId, warehouseInfoId);
        }
        if (StringUtils.isEmpty(batchNo)) {
            wrapper.isNull(StockInventory::getBatchNo);
        } else {
            wrapper.eq(StockInventory::getBatchNo, batchNo);
        }
        return wrapper;
    }
}
src/main/java/com/ruoyi/stock/service/impl/StockInventoryCheckPlanServiceImpl.java
@@ -21,6 +21,7 @@
import com.ruoyi.stock.service.*;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.util.*;
@@ -59,6 +60,7 @@
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R start(Long id) {
        StockInventoryCheckPlan stockInventoryCheckPlan = this.getById(id);
        StockInventoryCheckPlanDto stockInventoryCheckPlanDto = new StockInventoryCheckPlanDto();
@@ -97,6 +99,7 @@
                StockInventoryCheckItemDto stockInventoryCheckItemDto = new StockInventoryCheckItemDto();
                stockInventoryCheckItemDto.setProductModelId(stockInventory.getProductModelId());
                stockInventoryCheckItemDto.setBatchNo(stockInventory.getBatchNo());
                stockInventoryCheckItemDto.setWarehouseInfoId(stockInventory.getWarehouseInfoId());
                stockInventoryCheckItemDto.setSystemQuantity(stockInventory.getQualitity());
                stockInventoryCheckItemDto.setModel(stockInventory.getModel());
                stockInventoryCheckItemDto.setUnit(stockInventory.getUnit());
@@ -131,14 +134,14 @@
            if (item.getDifferenceQuantity().compareTo(BigDecimal.ZERO) > 0) {
                stockInventoryDto.setRecordType(StockInQualifiedRecordTypeEnum.INVENTORY_CHECK_STOCK_IN.getCode());
                StockInRecordDto stockInRecordDto = stockUtils.addStockWithBatchNo(stockInventoryDto.getProductModelId(), item.getDifferenceQuantity().abs (), stockInventoryDto.getRecordType(), stockInventoryDto.getRecordId(), stockInventoryDto.getBatchNo());
                StockInRecordDto stockInRecordDto = stockUtils.addStockWithBatchNo(stockInventoryDto.getProductModelId(), item.getDifferenceQuantity().abs (), stockInventoryDto.getRecordType(), stockInventoryDto.getRecordId(), stockInventoryDto.getBatchNo(), resolveWarehouseInfoId(item.getProductModelId(), item.getBatchNo()));
                //直接审核通过
                stockInRecordService.batchApprove(Collections.singletonList(stockInRecordDto.getId()), 1);
                stockInRecordService.batchApprove(Collections.singletonList(stockInRecordDto.getId()), 1, resolveWarehouseInfoId(item.getProductModelId(), item.getBatchNo()));
            }else {
                stockInventoryDto.setRecordType(StockOutQualifiedRecordTypeEnum.INVENTORY_CHECK_STOCK_OUT.getCode());
                StockOutRecordDto stock = stockUtils.substractStock(stockInventoryDto.getProductModelId(), item.getDifferenceQuantity().abs(), stockInventoryDto.getRecordType(), stockInventoryDto.getRecordId(), stockInventoryDto.getBatchNo());
                StockOutRecordDto stock = stockUtils.substractStock(stockInventoryDto.getProductModelId(), item.getDifferenceQuantity().abs(), stockInventoryDto.getRecordType(), stockInventoryDto.getRecordId(), stockInventoryDto.getBatchNo(), resolveWarehouseInfoId(item.getProductModelId(), item.getBatchNo()));
                //直接审核通过
                stockOutRecordService.batchApprove(Collections.singletonList(stock.getId()), 1);
                stockOutRecordService.batchApprove(Collections.singletonList(stock.getId()), 1,item.getWarehouseInfoId());
            }
        }
        stockInventoryCheckItemMapper.updateById(stockInventoryCheckPlanDto.getCheckItems());
@@ -254,4 +257,14 @@
    }
    private Long resolveWarehouseInfoId(Long productModelId, String batchNo) {
        List<StockInventory> inventories = stockInventoryService.list(new LambdaQueryWrapper<StockInventory>()
                .eq(StockInventory::getProductModelId, productModelId)
                .eq(batchNo != null, StockInventory::getBatchNo, batchNo)
                .isNull(batchNo == null, StockInventory::getBatchNo));
        if (inventories.isEmpty() || inventories.get(0).getWarehouseInfoId() == null) {
            return 1L;
        }
        return inventories.get(0).getWarehouseInfoId();
    }
}
src/main/java/com/ruoyi/stock/service/impl/StockInventoryServiceImpl.java
@@ -22,12 +22,15 @@
import com.ruoyi.stock.dto.StockUninventoryDto;
import com.ruoyi.stock.execl.StockInventoryExportData;
import com.ruoyi.stock.mapper.StockInventoryMapper;
import com.ruoyi.stock.mapper.WarehouseInfoMapper;
import com.ruoyi.stock.pojo.StockInRecord;
import com.ruoyi.stock.pojo.StockInventory;
import com.ruoyi.stock.pojo.WarehouseInfo;
import com.ruoyi.stock.service.StockInRecordService;
import com.ruoyi.stock.service.StockInventoryService;
import com.ruoyi.stock.service.StockOutRecordService;
import com.ruoyi.stock.service.StockUninventoryService;
import com.ruoyi.warehouse.service.impl.WarehouseServiceImpl;
import jakarta.servlet.http.HttpServletResponse;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
@@ -54,6 +57,8 @@
@AllArgsConstructor
public class StockInventoryServiceImpl extends ServiceImpl<StockInventoryMapper, StockInventory> implements StockInventoryService {
    private final WarehouseServiceImpl warehouseServiceImpl;
    private final WarehouseInfoMapper warehouseInfoMapper;
    private  StockInventoryMapper stockInventoryMapper;
    private StockInRecordService stockInRecordService;
    private StockOutRecordService stockOutRecordService;
@@ -73,16 +78,18 @@
    //入库调用
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean addstockInventory(StockInventoryDto stockInventoryDto) {
    public StockInRecordDto addstockInventory(StockInventoryDto stockInventoryDto) {
        Long warehouseInfoId = requireWarehouseInfoId(stockInventoryDto.getWarehouseInfoId());
        String batchNo = StringUtils.trim(stockInventoryDto.getBatchNo());
        if (StringUtils.isEmpty(batchNo)) {
            batchNo = generateAutoBatchNo(stockInventoryDto.getProductModelId());
        }
        stockInventoryDto.setBatchNo(batchNo);
        LambdaQueryWrapper<StockInventory> eq = new QueryWrapper<StockInventory>().lambda()
                .eq(StockInventory::getProductModelId, stockInventoryDto.getProductModelId());
        eq.eq(StockInventory::getBatchNo, stockInventoryDto.getBatchNo());
        LambdaQueryWrapper<StockInventory> eq = buildQualifiedInventoryQuery(
                stockInventoryDto.getProductModelId(),
                stockInventoryDto.getBatchNo(),
                stockInventoryDto.getWarehouseInfoId()
        );
        //新增入库记录再添加库存
        StockInRecordDto stockInRecordDto = new StockInRecordDto();
        stockInRecordDto.setRecordId(stockInventoryDto.getRecordId());
@@ -91,6 +98,7 @@
        stockInRecordDto.setBatchNo(stockInventoryDto.getBatchNo());
        stockInRecordDto.setProductModelId(stockInventoryDto.getProductModelId());
        stockInRecordDto.setType("0");
        stockInRecordDto.setWarehouseInfoId(warehouseInfoId);
        stockInRecordService.add(stockInRecordDto);
        //再进行新增库存数量库存
        //先查询库存表中的产品是否存在,不存在新增,存在更新
@@ -103,26 +111,28 @@
            newStockInventory.setRemark(stockInventoryDto.getRemark());
            newStockInventory.setBatchNo(stockInventoryDto.getBatchNo());
            newStockInventory.setLockedQuantity(stockInventoryDto.getLockedQuantity());
            newStockInventory.setWarehouseInfoId(stockInventoryDto.getWarehouseInfoId());
            newStockInventory.setWarnNum(stockInventoryDto.getWarnNum());
            stockInventoryMapper.insert(newStockInventory);
        }else {
             stockInventoryMapper.updateAddStockInventory(stockInventoryDto);
        }
        return true;
        return stockInRecordDto;
    }
    //出库调用
    @Override
    @Transactional(rollbackFor = Exception.class)
    public StockOutRecordDto subtractStockInventory(StockInventoryDto stockInventoryDto) {
        LambdaQueryWrapper<StockInventory> eq = new QueryWrapper<StockInventory>().lambda()
            .eq(StockInventory::getProductModelId, stockInventoryDto.getProductModelId());
        Long warehouseInfoId = requireWarehouseInfoId(stockInventoryDto.getWarehouseInfoId());
        if (StringUtils.isEmpty(stockInventoryDto.getBatchNo())) {
            eq.isNull(StockInventory::getBatchNo);
            stockInventoryDto.setBatchNo(null);
        } else {
            eq.eq(StockInventory::getBatchNo, stockInventoryDto.getBatchNo());
        }
        LambdaQueryWrapper<StockInventory> eq = buildQualifiedInventoryQuery(
                stockInventoryDto.getProductModelId(),
                stockInventoryDto.getBatchNo(),
                stockInventoryDto.getWarehouseInfoId()
        );
        //  æ–°å¢žå‡ºåº“记录
        StockOutRecordDto stockOutRecordDto = new StockOutRecordDto();
        stockOutRecordDto.setRecordId(stockInventoryDto.getRecordId());
@@ -132,6 +142,7 @@
        stockOutRecordDto.setApprovalStatus(0);
        stockOutRecordDto.setProductModelId(stockInventoryDto.getProductModelId());
        stockOutRecordDto.setType("0");
        stockOutRecordDto.setWarehouseInfoId(warehouseInfoId);
        Long id = stockOutRecordService.add(stockOutRecordDto);
        stockInventoryDto.setId(id);
@@ -155,6 +166,7 @@
    @Override
    @Transactional(rollbackFor = Exception.class)
    public StockInRecordDto addStockInRecordOnly(StockInventoryDto stockInventoryDto) {
        Long warehouseInfoId = requireWarehouseInfoId(stockInventoryDto.getWarehouseInfoId());
        String batchNo = StringUtils.trim(stockInventoryDto.getBatchNo());
        if (StringUtils.isEmpty(batchNo)) {
            batchNo = generateAutoBatchNo(stockInventoryDto.getProductModelId());
@@ -169,6 +181,7 @@
        stockInRecordDto.setApprovalStatus(0);
        stockInRecordDto.setProductModelId(stockInventoryDto.getProductModelId());
        stockInRecordDto.setType("0");
        stockInRecordDto.setWarehouseInfoId(warehouseInfoId);
        stockInRecordDto.setRemark(stockInventoryDto.getRemark());
        Long add = stockInRecordService.add(stockInRecordDto);
        stockInRecordDto.setId( add);
@@ -254,13 +267,15 @@
    @Override
    @Transactional(rollbackFor = Exception.class)
    public StockOutRecordDto addStockOutRecordOnly(StockInventoryDto stockInventoryDto) {
        LambdaQueryWrapper<StockInventory> eq = new LambdaQueryWrapper<>();
        eq.eq(StockInventory::getProductModelId, stockInventoryDto.getProductModelId());
        if (StringUtils.isEmpty(stockInventoryDto.getBatchNo())) {
            eq.isNull(StockInventory::getBatchNo);
        } else {
            eq.eq(StockInventory::getBatchNo, stockInventoryDto.getBatchNo());
            stockInventoryDto.setBatchNo(null);
        }
        Long warehouseInfoId = requireWarehouseInfoId(stockInventoryDto.getWarehouseInfoId());
        LambdaQueryWrapper<StockInventory> eq = buildQualifiedInventoryQuery(
                stockInventoryDto.getProductModelId(),
                stockInventoryDto.getBatchNo(),
                warehouseInfoId
        );
        StockInventory stockInventory = stockInventoryMapper.selectOne(eq);
        if (stockInventory == null) {
            throw new ServiceException("库存记录不存在");
@@ -272,6 +287,7 @@
        BigDecimal pendingOut = stockInventoryMapper.selectPendingOutQuantity(
                stockInventoryDto.getProductModelId(),
                stockInventoryDto.getBatchNo(),
                warehouseInfoId,
                "0"
        );
        if (pendingOut == null) {
@@ -288,10 +304,35 @@
        stockOutRecordDto.setBatchNo(stockInventoryDto.getBatchNo());
        stockOutRecordDto.setProductModelId(stockInventoryDto.getProductModelId());
        stockOutRecordDto.setType("0");
        stockOutRecordDto.setWarehouseInfoId(warehouseInfoId);
        stockOutRecordDto.setRemark(stockInventoryDto.getRemark());
        Long add = stockOutRecordService.add(stockOutRecordDto);
        stockInventoryDto.setId(add);
        return stockOutRecordDto;
    }
    private Long requireWarehouseInfoId(Long warehouseInfoId) {
        if (warehouseInfoId == null) {
//            throw new ServiceException("仓库不能为空");
            warehouseInfoId = 1L;
        }
        return warehouseInfoId;
    }
    private LambdaQueryWrapper<StockInventory> buildQualifiedInventoryQuery(Long productModelId, String batchNo, Long warehouseInfoId) {
        LambdaQueryWrapper<StockInventory> wrapper = new QueryWrapper<StockInventory>().lambda()
                .eq(StockInventory::getProductModelId, productModelId);
        if (warehouseInfoId == null) {
            wrapper.isNull(StockInventory::getWarehouseInfoId);
        } else {
            wrapper.eq(StockInventory::getWarehouseInfoId, warehouseInfoId);
        }
        if (StringUtils.isEmpty(batchNo)) {
            wrapper.isNull(StockInventory::getBatchNo);
        } else {
            wrapper.eq(StockInventory::getBatchNo, batchNo);
        }
        return wrapper;
    }
    @Override
@@ -300,6 +341,7 @@
        try {
            // æŸ¥è¯¢æ‰€æœ‰çš„产品并构建映射,提高查找效率
            List<SalesLedgerProduct> salesLedgerProducts = salesLedgerProductMapper.selectProduct();
            List<WarehouseInfo> warehouseInfos = warehouseInfoMapper.selectList(null);
            Map<String, SalesLedgerProduct> productMap = new HashMap<>();
            for (SalesLedgerProduct product : salesLedgerProducts) {
                // ä½¿ç”¨äº§å“ç±»åˆ«å’Œè§„格型号作为键
@@ -329,6 +371,14 @@
                        stockInventoryDto.setQualitity(dto.getQualifiedQuantity());
                        stockInventoryDto.setRemark(dto.getRemark());
                        stockInventoryDto.setWarnNum(dto.getWarnNum());
                        stockInventoryDto.setBatchNo(dto.getBatchNo());
                        stockInventoryDto.setWarehouseName(dto.getWarehouseName());
                        Long warehouseInfoId = warehouseInfos.stream()
                                .filter(warehouseInfo -> dto.getWarehouseName().equals(warehouseInfo.getWarehouseName()))
                                .map(WarehouseInfo::getId)
                                .findFirst()
                                .orElseThrow(() -> new RuntimeException("系统未找到仓库:" + dto.getWarehouseName()));
                        stockInventoryDto.setWarehouseInfoId(warehouseInfoId);
                        // éªŒè¯åˆæ ¼å†»ç»“数量
                        if (ObjectUtils.isNotEmpty(dto.getQualifiedLockedQuantity())) {
@@ -352,6 +402,8 @@
                        stockUninventoryDto.setRecordType(StockInQualifiedRecordTypeEnum.CUSTOMIZATION_UNSTOCK_IN.getCode());
                        stockUninventoryDto.setQualitity(dto.getUnQualifiedQuantity());
                        stockUninventoryDto.setRemark(dto.getRemark());
                        stockUninventoryDto.setBatchNo(dto.getBatchNo());
                        stockUninventoryDto.setWarehouseName(dto.getWarehouseName());
                        // éªŒè¯ä¸åˆæ ¼å†»ç»“数量
                        if (ObjectUtils.isNotEmpty(dto.getUnQualifiedLockedQuantity())) {
src/main/java/com/ruoyi/stock/service/impl/StockOutRecordServiceImpl.java
@@ -84,13 +84,11 @@
        for (Long id : ids) {
            StockOutRecord stockOutRecord = stockOutRecordMapper.selectById(id);
            if (stockOutRecord.getType().equals("0")) {
                LambdaQueryWrapper<StockInventory> wrapper = new LambdaQueryWrapper<StockInventory>()
                    .eq(StockInventory::getProductModelId, stockOutRecord.getProductModelId());
                if (StringUtils.isEmpty(stockOutRecord.getBatchNo())) {
                    wrapper.isNull(StockInventory::getBatchNo);
                } else {
                    wrapper.eq(StockInventory::getBatchNo, stockOutRecord.getBatchNo());
                }
                LambdaQueryWrapper<StockInventory> wrapper = buildQualifiedInventoryQuery(
                        stockOutRecord.getProductModelId(),
                        stockOutRecord.getBatchNo(),
                        stockOutRecord.getWarehouseInfoId()
                );
                StockInventory stockInventory = stockInventoryMapper.selectOne(wrapper);
                if (stockInventory == null) {
                    throw new BaseException("库存记录中没有对应的产品,无法删除!!!");
@@ -99,6 +97,7 @@
                    stockInRecordDto.setProductModelId(stockInventory.getProductModelId());
                    stockInRecordDto.setQualitity(stockOutRecord.getStockOutNum());
                    stockInRecordDto.setBatchNo(stockInventory.getBatchNo());
                    stockInRecordDto.setWarehouseInfoId(stockInventory.getWarehouseInfoId());
                    stockInventoryMapper.updateAddStockInventory(stockInRecordDto);
                }
            }else if (stockOutRecord.getType().equals("1")) {
@@ -150,12 +149,12 @@
                throw new BaseException("只有待审批状态的记录才能删除,出库批次:" + stockOutRecord.getOutboundBatches());
            }
        }
        return stockOutRecordMapper.deleteBatchIds(ids);
        return stockOutRecordMapper.deleteByIds(ids);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int batchApprove(List<Long> ids, Integer approvalStatus) {
    public int batchApprove(List<Long> ids, Integer approvalStatus,Long warehouseInfoId) {
        if (CollectionUtils.isEmpty(ids)) {
            throw new BaseException("请选择至少一条数据");
        }
@@ -176,7 +175,11 @@
            if (ReviewStatusEnum.APPROVED.getCode().equals(approvalStatus)) {
                if ("0".equals(stockOutRecord.getType())) {
                    // åˆæ ¼å‡ºåº“ -> å…ˆæŸ¥åº“存是否存在,存在才扣减
                    StockInventory stockInventory = getStockInventory(stockOutRecord.getProductModelId(), stockOutRecord.getBatchNo());
                    StockInventory stockInventory = getStockInventory(
                            stockOutRecord.getProductModelId(),
                            stockOutRecord.getBatchNo(),
                            stockOutRecord.getWarehouseInfoId()
                    );
                    if (stockInventory == null) {
                        throw new BaseException("合格库存记录不存在,出库批次:" + stockOutRecord.getOutboundBatches());
                    }
@@ -186,6 +189,7 @@
                    StockInventoryDto stockInventoryDto = new StockInventoryDto();
                    stockInventoryDto.setProductModelId(stockOutRecord.getProductModelId());
                    stockInventoryDto.setBatchNo(stockOutRecord.getBatchNo());
                    stockInventoryDto.setWarehouseInfoId(stockOutRecord.getWarehouseInfoId());
                    stockInventoryDto.setQualitity(stockOutRecord.getStockOutNum());
                    stockInventoryMapper.updateSubtractStockInventory(stockInventoryDto);
                } else if ("1".equals(stockOutRecord.getType())) {
@@ -205,15 +209,8 @@
        return ids.size();
    }
    private StockInventory getStockInventory(Long productModelId, String batchNo) {
        LambdaQueryWrapper<StockInventory> eq = new LambdaQueryWrapper<>();
        eq.eq(StockInventory::getProductModelId, productModelId);
        if (StringUtils.isEmpty(batchNo)) {
            eq.isNull(StockInventory::getBatchNo);
        } else {
            eq.eq(StockInventory::getBatchNo, batchNo);
        }
        return stockInventoryMapper.selectOne(eq);
    private StockInventory getStockInventory(Long productModelId, String batchNo, Long warehouseInfoId) {
        return stockInventoryMapper.selectOne(buildQualifiedInventoryQuery(productModelId, batchNo, warehouseInfoId));
    }
    private StockUninventory getStockUninventory(Long productModelId, String batchNo) {
@@ -226,4 +223,20 @@
        }
        return stockUninventoryMapper.selectOne(eq);
    }
    private LambdaQueryWrapper<StockInventory> buildQualifiedInventoryQuery(Long productModelId, String batchNo, Long warehouseInfoId) {
        LambdaQueryWrapper<StockInventory> wrapper = new LambdaQueryWrapper<StockInventory>()
                .eq(StockInventory::getProductModelId, productModelId);
        if (warehouseInfoId == null) {
            wrapper.isNull(StockInventory::getWarehouseInfoId);
        } else {
            wrapper.eq(StockInventory::getWarehouseInfoId, warehouseInfoId);
        }
        if (StringUtils.isEmpty(batchNo)) {
            wrapper.isNull(StockInventory::getBatchNo);
        } else {
            wrapper.eq(StockInventory::getBatchNo, batchNo);
        }
        return wrapper;
    }
}
src/main/java/com/ruoyi/stock/service/impl/WarehouseInfoServiceImpl.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,45 @@
package com.ruoyi.stock.service.impl;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.stock.dto.WarehouseInfoDto;
import com.ruoyi.stock.mapper.StockInventoryMapper;
import com.ruoyi.stock.mapper.WarehouseInfoMapper;
import com.ruoyi.stock.pojo.WarehouseInfo;
import com.ruoyi.stock.service.WarehouseInfoService;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
/**
 * <p>
 * ä»“库信息表 æœåŠ¡å®žçŽ°ç±»
 * </p>
 *
 * @author èŠ¯å¯¼è½¯ä»¶ï¼ˆæ±Ÿè‹ï¼‰æœ‰é™å…¬å¸
 * @since 2026-05-12 05:44:22
 */
@Service
@RequiredArgsConstructor
public class WarehouseInfoServiceImpl extends ServiceImpl<WarehouseInfoMapper, WarehouseInfo> implements WarehouseInfoService {
    private final WarehouseInfoMapper warehouseInfoMapper;
    private final StockInventoryMapper stockInventoryMapper;
    @Override
    public IPage<WarehouseInfoDto> listPage(Page page, WarehouseInfoDto warehouseInfoDto) {
        return warehouseInfoMapper.listPage(page, warehouseInfoDto);
    }
    @Override
    public Boolean deleteByIds(ArrayList<Long> ids) {
        Long usedCount = stockInventoryMapper.existsUsed(ids);
        if (usedCount != null && usedCount > 0) {
            throw new ServiceException("选中的仓库已被库存记录使用,无法删除");
        }
        return removeByIds(ids);
    }
}
src/main/resources/mapper/basic/ProductModelMapper.xml
@@ -23,6 +23,10 @@
                    select="selectBatchNoListByProductModelId"/>
    </resultMap>
    <resultMap id="ProductModelVoBaseResultMap" type="com.ruoyi.basic.vo.ProductModelVo" extends="BaseResultMap">
        <result column="create_time" property="createTime" />
    </resultMap>
    <select id="listPageProductModel" resultMap="ProductModelVoResultMap">
        select pm.*,p.product_name
        from product_model pm
@@ -128,7 +132,6 @@
                )
            </if>
        </where>
        ORDER BY pm.id DESC
    </select>
    <select id="getProductAndModelList" resultType="java.util.Map">
@@ -153,5 +156,51 @@
            </if>
        </where>
    </select>
    <select id="pageModelAndQua" resultMap="ProductModelVoBaseResultMap">
        select pm.*, p.product_name
        from product_model pm
        left join product p on pm.product_id = p.id
        <where>
            <if test="c.model != null and c.model != ''">
                and pm.model like concat('%',#{c.model},'%')
            </if>
            <if test="c.productName != null and c.productName != ''">
                and p.product_name like concat('%',#{c.productName},'%')
            </if>
            <if test="c.topProductParentId != null and c.topProductParentId > 0">
                and p.id in (
                    WITH RECURSIVE product_tree AS (
                        SELECT id
                        FROM product
                        WHERE id = #{c.topProductParentId}
                        UNION ALL
                        SELECT p.id
                        FROM product p
                        INNER JOIN product_tree pt ON p.parent_id = pt.id
                    )
                    select id from product_tree
                )
            </if>
        </where>
        order by pm.id
    </select>
    <select id="selectBatchNoQtyByProductModelIds" resultType="java.util.Map">
        select si.product_model_id as productModelId,
               si.warehouse_info_id as warehouseId,
               si.batch_no as batchNo,
               si.qualitity as qty
        from stock_inventory si
        where si.product_model_id in
        <foreach collection="list" item="productModelId" separator="," open="(" close=")">
            #{productModelId}
        </foreach>
          and si.warehouse_info_id is not null
          and si.batch_no is not null
          and si.batch_no != ''
        order by si.product_model_id, si.warehouse_info_id, si.batch_no, si.id
    </select>
</mapper>
src/main/resources/mapper/purchase/PurchaseLedgerMapper.xml
@@ -111,4 +111,4 @@
            </if>
        </where>
    </select>
</mapper>
</mapper>
src/main/resources/mapper/stock/StockInRecordMapper.xml
@@ -19,11 +19,13 @@
        p.product_name as product_name,
        pm.model,
        pm.unit,
        u.nick_name as createBy
        u.nick_name as createBy,
        swi.warehouse_name
        FROM stock_in_record as sir
        LEFT JOIN product_model as pm on sir.product_model_id = pm.id
        LEFT JOIN product as p on pm.product_id = p.id
        LEFT JOIN sys_user as u on sir.create_user = u.user_id
        left join stock_warehouse_info swi on swi.id = sir.warehouse_info_id
        <where>
            <if test="params.timeStr != null and params.timeStr != ''">
                and sir.create_time like concat('%',#{params.timeStr},'%')
src/main/resources/mapper/stock/StockInventoryMapper.xml
@@ -6,12 +6,16 @@
    <resultMap id="BaseResultMap" type="com.ruoyi.stock.pojo.StockInventory">
        <result column="id" property="id"/>
        <result column="product_model_id" property="productModelId"/>
        <result column="batch_no" property="batchNo"/>
        <result column="qualitity" property="qualitity"/>
        <result column="create_time" property="createTime"/>
        <result column="update_time" property="updateTime"/>
        <result column="version" property="version"/>
        <result column="locked_quantity" property="lockedQuantity"/>
        <result column="warn_num" property="warnNum"/>
        <result column="remark" property="remark"/>
        <result column="locked" property="locked"/>
        <result column="warehouse_info_id" property="warehouseInfoId"/>
    </resultMap>
    <update id="updateAddStockInventory">
        update stock_inventory
@@ -34,6 +38,12 @@
            update_time = now()
        </set>
        where product_model_id = #{ew.productModelId}
            <if test="ew.warehouseInfoId == null">
                and warehouse_info_id is null
            </if>
            <if test="ew.warehouseInfoId != null">
                and warehouse_info_id = #{ew.warehouseInfoId}
            </if>
            <if test="ew.batchNo == null">
                and batch_no is null
            </if>
@@ -56,6 +66,12 @@
            update_time = now()
        </set>
        where product_model_id = #{ew.productModelId} and qualitity >= #{ew.qualitity}
            <if test="ew.warehouseInfoId == null">
                and warehouse_info_id is null
            </if>
            <if test="ew.warehouseInfoId != null">
                and warehouse_info_id = #{ew.warehouseInfoId}
            </if>
            <if test="ew.batchNo == null">
                and batch_no is null
            </if>
@@ -79,6 +95,7 @@
        si.qualitity,
        COALESCE(si.locked_quantity, 0) as locked_quantity,
        si.product_model_id,
        si.warehouse_info_id,
        si.create_time,
        si.update_time,
        COALESCE(si.warn_num, 0) as warn_num,
@@ -87,10 +104,12 @@
        pm.model,
        si.remark,
        pm.unit,
        p.product_name
        p.product_name,
        siw.warehouse_name
        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 stock_warehouse_info siw on si.warehouse_info_id = siw.id
        where 1 = 1
        <if test="ew.productName != null and ew.productName !=''">
            and p.product_name like concat('%',#{ew.productName},'%')
@@ -122,6 +141,8 @@
            SUM(IFNULL(qualifiedPendingOut, 0)) as qualifiedPendingOutQuantity,
            SUM(IFNULL(unQualifiedPendingOut, 0)) as unQualifiedPendingOutQuantity,
            product_model_id,
            warehouse_info_id,
            warehouse_name,
            MAX(create_time) as create_time,
            MAX(update_time) as update_time,
            MAX(warn_num) as warn_num,
@@ -143,6 +164,8 @@
            COALESCE(si.locked_quantity, 0) as qualifiedLockedQuantity,
            0 as unQualifiedLockedQuantity,
            si.product_model_id,
            si.warehouse_info_id,
            siw.warehouse_name,
            si.create_time,
            si.update_time,
            COALESCE(si.warn_num, 0) as warn_num,
@@ -157,6 +180,7 @@
                select IFNULL(SUM(sor.stock_out_num), 0)
                from stock_out_record sor
                where sor.product_model_id = si.product_model_id
                  and sor.warehouse_info_id = si.warehouse_info_id
                  and (si.batch_no is null and sor.batch_no is null or si.batch_no = sor.batch_no)
                  and sor.type = '0'
                  and sor.approval_status = 0
@@ -165,6 +189,7 @@
            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 stock_warehouse_info siw on si.warehouse_info_id = siw.id
            union all
@@ -178,6 +203,8 @@
            0 as qualifiedLockedQuantity,
            COALESCE(su.locked_quantity, 0) as unQualifiedLockedQuantity,
            su.product_model_id,
            null as warehouse_info_id,
            null as warehouse_name,
            su.create_time,
            su.update_time,
            0 as warn_num,
@@ -214,7 +241,7 @@
                and combined.product_id in (select id from product_tree)
            </if>
        </where>
        group by batch_no, product_model_id, model, unit, product_name, product_id
        group by batch_no, product_model_id, warehouse_info_id, warehouse_name, model, unit, product_name, product_id
    </select>
    <select id="listStockInventoryExportData" resultType="com.ruoyi.stock.execl.StockInventoryExportData">
@@ -303,6 +330,8 @@
        from
        stock_in_record sir
        left join stock_inventory si on sir.product_model_id = si.product_model_id
            and (sir.batch_no = si.batch_no or (sir.batch_no is null and si.batch_no is null))
            and sir.warehouse_info_id = si.warehouse_info_id
        left join product_model pm on sir.product_model_id = pm.id
        left join product p on pm.product_id = p.id
        left join sys_user su on sir.create_user = su.user_id
@@ -445,6 +474,7 @@
        SELECT IFNULL(SUM(sor.stock_out_num), 0)
        FROM stock_out_record sor
        WHERE sor.product_model_id = #{productModelId}
          AND sor.warehouse_info_id = #{warehouseInfoId}
          AND (sor.batch_no = #{batchNo} OR (#{batchNo} IS NULL AND sor.batch_no IS NULL))
          AND sor.type = #{type}
          AND sor.approval_status IN (0, 3)
@@ -464,7 +494,7 @@
        order by si.product_model_id, si.batch_no
    </select>
    <select id="getByModelId" resultType="com.ruoyi.stock.pojo.StockInventory">
        select si.id, si.batch_no, si.locked_quantity, (si.qualitity - IFNULL(sd.qualitity, 0)) as qualitity
        select si.id, si.batch_no, si.locked_quantity, si.warehouse_info_id, (si.qualitity - IFNULL(sd.qualitity, 0)) as qualitity
        from stock_inventory si
                 left join (
                    select spd.stock_inventory_id, sum(spd.quantity) as qualitity
@@ -484,9 +514,10 @@
        where si.product_model_id = #{productModelId}
    </select>
    <select id="selectStockInvenrory" resultType="com.ruoyi.stock.dto.StockInventoryDto">
        select spd.id, spd.batch_no,pm.model,pm.unit,p.product_name, spd.qualitity,spd.product_model_id
        select spd.id, spd.batch_no, spd.warehouse_info_id, siw.warehouse_name, pm.model, pm.unit, p.product_name, spd.qualitity, spd.product_model_id
        from stock_inventory spd
            left join product_model pm on pm.id = spd.product_model_id
        left join stock_warehouse_info siw on siw.id = spd.warehouse_info_id
        left join product_model pm on pm.id = spd.product_model_id
        left join product p on p.id = pm.product_id
        where product_model_id = #{productModelId}
    </select>
@@ -511,6 +542,14 @@
        pm.unit,
        p.product_name
    </select>
    <select id="existsUsed" resultType="java.lang.Long">
        select count(1)
        from stock_inventory
        where warehouse_info_id in
        <foreach collection="ids" item="id" open="(" separator="," close=")">
            #{id}
        </foreach>
    </select>
</mapper>
src/main/resources/mapper/stock/StockOutRecordMapper.xml
@@ -34,11 +34,13 @@
        p.product_name as productName,
        pm.model,
        pm.unit,
        u.nick_name as createBy
        u.nick_name as createBy,
        swi.warehouse_name
        FROM stock_out_record as sor
        LEFT JOIN product_model as pm on sor.product_model_id = pm.id
        LEFT JOIN product as p on pm.product_id = p.id
        LEFT JOIN sys_user as u on sor.create_user = u.user_id
        left join stock_warehouse_info as swi on sor.warehouse_info_id = swi.id
        <where>
            <if test="params.timeStr != null and params.timeStr != ''">
                and sor.create_time like concat('%',#{params.timeStr},'%')
src/main/resources/mapper/stock/WarehouseInfoMapper.xml
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,35 @@
<?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.stock.mapper.WarehouseInfoMapper">
    <!-- é€šç”¨æŸ¥è¯¢æ˜ å°„结果 -->
    <resultMap id="BaseResultMap" type="com.ruoyi.stock.pojo.WarehouseInfo">
        <id column="id" property="id"/>
        <result column="warehouse_name" property="warehouseName"/>
        <result column="location" property="location"/>
        <result column="manager_name" property="managerName"/>
        <result column="contact_phone" property="contactPhone"/>
        <result column="status" property="status"/>
        <result column="remark" property="remark"/>
        <result column="create_user" property="createUser"/>
        <result column="dept_id" property="deptId"/>
        <result column="create_time" property="createTime"/>
        <result column="update_time" property="updateTime"/>
    </resultMap>
    <select id="listPage" resultType="com.ruoyi.stock.dto.WarehouseInfoDto">
        select * from
        stock_warehouse_info
        <where>
            <if test="ew.warehouseName != null and ew.warehouseName != ''">
                and warehouse_name like concat('%',#{ew.warehouseName},'%')
            </if>
            <if test="ew.location != null and ew.location != ''">
                and location like concat('%',#{ew.location},'%')
            </if>
            <if test="ew.managerName != null and ew.managerName != ''">
                and manager_name like concat('%',#{ew.managerName},'%')
            </if>
        </where>
    </select>
</mapper>