fix: 1.已发货的销售台账对应的出入库记录做限制不能删除;2.销售台账入库操作后,点击删除,对应的销售入库记录未一并删除;3.销售台账入库状态新增部分入库
已添加1个文件
已修改19个文件
367 ■■■■ 文件已修改
doc/河南鹤壁天沐钢化玻璃厂.sql 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/common/enums/StockInQualifiedRecordTypeEnum.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/procurementrecord/utils/StockUtils.java 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/controller/SalesLedgerController.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/controller/ShipmentApprovalController.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/dto/SalesProductStockDto.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/pojo/SalesLedger.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/pojo/SalesLedgerProduct.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/ISalesLedgerService.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java 66 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/sales/service/impl/ShippingInfoServiceImpl.java 24 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/dto/StockInventoryDto.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/pojo/StockInRecord.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/pojo/StockOutRecord.java 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/service/impl/StockInRecordServiceImpl.java 72 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/service/impl/StockInventoryServiceImpl.java 34 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/ruoyi/stock/service/impl/StockOutRecordServiceImpl.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/sales/SalesLedgerMapper.xml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/stock/StockInventoryMapper.xml 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mybatis/mybatis-config.xml 22 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
doc/ºÓÄϺױÚÌìãå¸Ö»¯²£Á§³§.sql
@@ -109,3 +109,17 @@
                                                                    `user_id` int NULL DEFAULT NULL COMMENT '用户id',
                                                                    PRIMARY KEY (`id`)
    );
ALTER TABLE `product-inventory-management-hbtmblc`.`stock_in_record`
    ADD COLUMN `sales_ledger_id`         bigint NULL COMMENT '销售台账ID' AFTER `weighing_date`,
    ADD COLUMN `sales_ledger_product_id` bigint NULL COMMENT '销售台账产品ID' AFTER `sales_ledger_id`;
ALTER TABLE `product-inventory-management-hbtmblc`.`sales_ledger_product`
    ADD COLUMN `product_stock_status` int NULL COMMENT '产品入库状态' AFTER `floor_code`;
ALTER TABLE `product-inventory-management-hbtmblc`.`stock_out_record`
    MODIFY COLUMN `outbound_batches` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NULL DEFAULT NULL COMMENT '出库批次' AFTER `id`,
    MODIFY COLUMN `stock_out_num` decimal(16, 4) NULL DEFAULT NULL COMMENT '出库数量' AFTER `outbound_batches`,
    MODIFY COLUMN `record_id` int NULL DEFAULT NULL COMMENT '出库来源id' AFTER `stock_out_num`,
    ADD COLUMN `sales_ledger_id`         bigint NULL COMMENT '销售订单ID' AFTER `type`,
    ADD COLUMN `sales_ledger_product_id` bigint NULL COMMENT '销售订单产品ID' AFTER `sales_ledger_id`;
src/main/java/com/ruoyi/common/enums/StockInQualifiedRecordTypeEnum.java
@@ -12,7 +12,7 @@
    QUALITYINSPECT_STOCK_IN("6", "质检-合格入库"),
    DEFECTIVE_PASS("11", "不合格-让步放行"),
    RETURN_HE_IN("14", "销售退货-合格入库"),
    SALE_STOCK_IN("15", "销售-合格入库");
    SALE_STOCK_IN("15", "销售订单-合格入库");
    private final String code;
src/main/java/com/ruoyi/procurementrecord/utils/StockUtils.java
@@ -35,12 +35,13 @@
    /**
     * ä¸åˆæ ¼å…¥åº“
     *
     * @param productModelId
     * @param quantity
     * @param recordType
     * @param recordId
     */
    public void addUnStock(Long productModelId, BigDecimal quantity, String recordType,Long recordId) {
    public void addUnStock(Long productModelId, BigDecimal quantity, String recordType, Long recordId) {
        StockUninventoryDto stockUninventoryDto = new StockUninventoryDto();
        stockUninventoryDto.setRecordId(recordId);
        stockUninventoryDto.setRecordType(String.valueOf(recordType));
@@ -51,12 +52,13 @@
    /**
     * ä¸åˆæ ¼å‡ºåº“
     *
     * @param productModelId
     * @param quantity
     * @param recordType
     * @param recordId
     */
    public void subtractUnStock(Long productModelId, BigDecimal quantity, Integer recordType,Long recordId) {
    public void subtractUnStock(Long productModelId, BigDecimal quantity, Integer recordType, Long recordId) {
        StockUninventoryDto stockUninventoryDto = new StockUninventoryDto();
        stockUninventoryDto.setRecordId(recordId);
        stockUninventoryDto.setRecordType(String.valueOf(recordType));
@@ -67,33 +69,69 @@
    /**
     * åˆæ ¼å…¥åº“
     *
     * @param productModelId
     * @param quantity
     * @param recordType
     * @param recordId
     */
    public void addStock(Long productModelId, BigDecimal quantity, String recordType,Long recordId) {
    public void addStock(Long productModelId, BigDecimal quantity, String recordType, Long recordId) {
        addStock(null, null, productModelId, quantity, recordType, recordId);
    }
    /**
     * åˆæ ¼å…¥åº“
     *
     * @param productModelId
     * @param quantity
     * @param recordType
     * @param recordId
     */
    public void addStock(Long salesLedgerId, Long salesLedgerProductId, Long productModelId, BigDecimal quantity, String recordType, Long recordId) {
        StockInventoryDto stockInventoryDto = new StockInventoryDto();
        stockInventoryDto.setRecordId(recordId);
        stockInventoryDto.setRecordType(String.valueOf(recordType));
        stockInventoryDto.setQualitity(quantity);
        stockInventoryDto.setProductModelId(productModelId);
        stockInventoryDto.setSalesLedgerId(salesLedgerId);
        stockInventoryDto.setSalesLedgerProductId(salesLedgerProductId);
        stockInventoryService.addstockInventory(stockInventoryDto);
    }
    /**
     * åˆæ ¼å‡ºåº“
     *
     * @param productModelId
     * @param quantity
     * @param recordType
     * @param recordId
     */
    public void substractStock(Long productModelId, BigDecimal quantity, String recordType, Long recordId) {
        StockInventoryDto stockInventoryDto = new StockInventoryDto();
        stockInventoryDto.setRecordId(recordId);
        stockInventoryDto.setRecordType(String.valueOf(recordType));
        stockInventoryDto.setQualitity(quantity);
        stockInventoryDto.setProductModelId(productModelId);
        stockInventoryService.subtractStockInventory(stockInventoryDto);
    }
    /**
     * åˆæ ¼å‡ºåº“
     *
     * @param productModelId
     * @param quantity
     * @param recordType
     * @param recordId
     */
    public void substractStock(Long productModelId, BigDecimal quantity, String recordType,Long recordId) {
    public void substractStock(Long salesId, Long salseProductId, Long productModelId, BigDecimal quantity, String recordType, Long recordId) {
        StockInventoryDto stockInventoryDto = new StockInventoryDto();
        stockInventoryDto.setRecordId(recordId);
        stockInventoryDto.setRecordType(String.valueOf(recordType));
        stockInventoryDto.setQualitity(quantity);
        stockInventoryDto.setProductModelId(productModelId);
        stockInventoryDto.setSalesLedgerId(salesId);
        stockInventoryDto.setSalesLedgerProductId(salseProductId);
        stockInventoryService.subtractStockInventory(stockInventoryDto);
    }
@@ -106,6 +144,7 @@
            stockInRecordService.batchDelete(Collections.singletonList(one.getId()));
        }
    }
    public void deleteStockOutRecord(Long recordId, String recordType) {
        StockOutRecord one = stockOutRecordService.getOne(new QueryWrapper<StockOutRecord>()
                .lambda().eq(StockOutRecord::getRecordId, recordId)
src/main/java/com/ruoyi/sales/controller/SalesLedgerController.java
@@ -397,8 +397,8 @@
    @PostMapping("/salesStock")
    @ApiOperation("销售台账产品入库")
    public AjaxResult salesStock(@RequestBody SalesLedger salesLedger) {
        salesLedgerService.salesStock(salesLedger);
    public AjaxResult salesStock(@RequestBody SalesProductStockDto dto) {
        salesLedgerService.salesStock(dto);
        return AjaxResult.success();
    }
src/main/java/com/ruoyi/sales/controller/ShipmentApprovalController.java
@@ -40,7 +40,7 @@
    @GetMapping("/listPage")
    @ApiOperation("发货审批列表")
    public AjaxResult listPage(Page page, ShipmentApproval req) {
        IPage<ShipmentApproval> listPage = shipmentApprovalService.listPage(page,req);
        IPage<ShipmentApproval> listPage = shipmentApprovalService.listPage(page, req);
        return AjaxResult.success(listPage);
    }
@@ -87,12 +87,11 @@
            //出库
            stockUtils.addStock(salesLedgerProduct.getProductModelId(), salesLedgerProduct.getQuantity(), StockOutQualifiedRecordTypeEnum.SALE_SHIP_STOCK_OUT.getCode(), req.getId());
            stockUtils.addStock(salesLedgerProduct.getSalesLedgerId(), salesLedgerProduct.getId(), salesLedgerProduct.getProductModelId(), salesLedgerProduct.getQuantity(), StockOutQualifiedRecordTypeEnum.SALE_SHIP_STOCK_OUT.getCode(), req.getId());
        }
        return AjaxResult.success();
    }
    /**
src/main/java/com/ruoyi/sales/dto/SalesProductStockDto.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,28 @@
package com.ruoyi.sales.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.util.List;
/**
 * <br>
 * é”€å”®è®¢å•产品入库Dto
 * </br>
 *
 * @author deslrey
 * @version 1.0
 * @since 2026/4/17 13:53
 */
@Data
@ApiModel(value = "SalesProductStockDto", description = "销售订单产品入库Dto")
public class SalesProductStockDto {
    @ApiModelProperty("销售订单Id")
    private Long salesLedgerId;
    @ApiModelProperty("销售订单产品Id")
    private List<Long> salesLedgerProducts;
}
src/main/java/com/ruoyi/sales/pojo/SalesLedger.java
@@ -149,9 +149,9 @@
    private Integer deliveryStatus;
    /**
     * å…¥åº“状态:0-未入库,1-已入库
     * å…¥åº“状态:0-未入库,1-部分入库,2-已入库
     */
    @ApiModelProperty("入库状态:0-未入库,1-已入库")
    @ApiModelProperty("入库状态:0-未入库,1-部分入库,2-已入库")
    private Integer stockStatus;
    @TableField(exist = false)
src/main/java/com/ruoyi/sales/pojo/SalesLedgerProduct.java
@@ -292,6 +292,12 @@
    @ApiModelProperty("楼层编号")
    private String floorCode;
    /**
     * äº§å“å…¥åº“状态   0-未入库,1-已入库
     */
    @ApiModelProperty("产品入库状态")
    private Integer productStockStatus;
    @TableField(exist = false)
    @ApiModelProperty("销售产品额外加工")
    private List<SalesLedgerProductProcess> salesProductProcessList;
src/main/java/com/ruoyi/sales/service/ISalesLedgerService.java
@@ -67,5 +67,5 @@
    List<SalesLabelDto> salesLabel(Long salesLedgerId);
    void salesStock(SalesLedger salesLedger);
    void salesStock(SalesProductStockDto dto);
}
src/main/java/com/ruoyi/sales/service/impl/SalesLedgerServiceImpl.java
@@ -49,7 +49,13 @@
import com.ruoyi.sales.service.ISalesLedgerProductProcessService;
import com.ruoyi.sales.service.ISalesLedgerService;
import com.ruoyi.stock.dto.StockInventoryDto;
import com.ruoyi.stock.mapper.StockInRecordMapper;
import com.ruoyi.stock.mapper.StockOutRecordMapper;
import com.ruoyi.stock.pojo.StockInRecord;
import com.ruoyi.stock.pojo.StockOutRecord;
import com.ruoyi.stock.service.StockInRecordService;
import com.ruoyi.stock.service.StockInventoryService;
import com.ruoyi.stock.service.StockOutRecordService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
@@ -130,6 +136,10 @@
    private final ISalesLedgerProcessRouteService salesLedgerProcessRouteService;
    private final StockInventoryService stockInventoryService;
    private final StockInRecordMapper stockInRecordMapper;
    private final StockOutRecordMapper stockOutRecordMapper;
    private final StockInRecordService stockInRecordService;
    private final StockOutRecordService stockOutRecordService;
    @Autowired
    private SysDeptMapper sysDeptMapper;
@@ -703,6 +713,25 @@
        if (CollectionUtils.isNotEmpty(shippingInfos)) {
            shippingInfoServiceImpl.delete(shippingInfos.stream().map(ShippingInfo::getId).collect(Collectors.toList()));
        }
        // åˆ é™¤å…³è”的入库/出库记录(走服务层删除,触发库存数量回退)
        List<Long> stockInRecordIds = stockInRecordMapper.selectList(new LambdaQueryWrapper<StockInRecord>()
                        .in(StockInRecord::getSalesLedgerId, idList)
                        .select(StockInRecord::getId))
                .stream()
                .map(StockInRecord::getId)
                .collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(stockInRecordIds)) {
            stockInRecordService.batchDelete(stockInRecordIds);
        }
        List<Long> stockOutRecordIds = stockOutRecordMapper.selectList(new LambdaQueryWrapper<StockOutRecord>()
                        .in(StockOutRecord::getSalesLedgerId, idList)
                        .select(StockOutRecord::getId))
                .stream()
                .map(StockOutRecord::getId)
                .collect(Collectors.toList());
        if (CollectionUtils.isNotEmpty(stockOutRecordIds)) {
            stockOutRecordService.batchDelete(stockOutRecordIds);
        }
        // åˆ é™¤é™„件表
        commonFileService.deleteByBusinessIds(idList, FileNameType.SALE.getValue());
@@ -860,6 +889,7 @@
        if (!updateList.isEmpty()) {
            for (SalesLedgerProduct product : updateList) {
                product.setType(type.getCode());
                product.setProductStockStatus(0);
                salesLedgerProductMapper.updateById(product);
                //  æ¸…空销售产品绑定的加工
                salesLedgerProductProcessBindService.updateProductProcessBind(product.getSalesProductProcessList(), product.getId());
@@ -872,6 +902,7 @@
                salesLedgerProduct.setNoInvoiceNum(salesLedgerProduct.getQuantity());
                salesLedgerProduct.setNoInvoiceAmount(salesLedgerProduct.getTaxInclusiveTotalPrice());
                salesLedgerProduct.setPendingInvoiceTotal(salesLedgerProduct.getTaxInclusiveTotalPrice());
                salesLedgerProduct.setProductStockStatus(0);
                salesLedgerProductMapper.insert(salesLedgerProduct);
                //  ç»‘定产品额外加工
                //  æ¸…空销售产品绑定的加工
@@ -1509,23 +1540,27 @@
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void salesStock(SalesLedger salesLedger) {
        if (salesLedger == null || salesLedger.getId() == null) {
    public void salesStock(SalesProductStockDto dto) {
        if (dto == null || dto.getSalesLedgerId() == null) {
            throw new NullPointerException("入库失败,请选择需要入库的销售订单");
        }
        //  æŸ¥è¯¢é”€å”®è®¢å•是否存在
        SalesLedger ledger = baseMapper.selectById(salesLedger.getId());
        SalesLedger ledger = baseMapper.selectById(dto.getSalesLedgerId());
        if (ledger == null) {
            throw new ServiceException("入库失败,销售订单不存在");
        }
        if (ledger.getStockStatus() == null) {
            throw new ServiceException("入库失败,销售订单入库状态异常");
        }
        if (ledger.getStockStatus() == 1) {
        if (ledger.getStockStatus() == 2) {
            throw new ServiceException("入库失败,该销售订单已入库,请勿重复入库");
        }
        List<Long> products = dto.getSalesLedgerProducts();
        if (products == null || products.isEmpty()) {
            throw new ServiceException("入库失败,入库产品不能为空");
        }
        //  æŸ¥è¯¢é”€å”®è®¢å•的产品
        List<SalesLedgerProduct> salesLedgerProducts = salesLedgerProductMapper.selectList(Wrappers.<SalesLedgerProduct>lambdaQuery().eq(SalesLedgerProduct::getSalesLedgerId, ledger.getId()));
        List<SalesLedgerProduct> salesLedgerProducts = salesLedgerProductMapper.selectList(Wrappers.<SalesLedgerProduct>lambdaQuery().in(SalesLedgerProduct::getId, products));
        if (salesLedgerProducts == null || salesLedgerProducts.isEmpty()) {
            throw new ServiceException("入库失败,未查询到该销售订单的销售产品");
        }
@@ -1533,15 +1568,20 @@
            if (product.getProductModelId() == null) {
                continue;
            }
            StockInventoryDto dto = new StockInventoryDto();
            dto.setRecordId(product.getId());
            dto.setRecordType(StockInQualifiedRecordTypeEnum.SALE_STOCK_IN.getCode());
            dto.setQualitity(product.getQuantity());
            dto.setProductModelId(product.getProductModelId());
            stockInventoryService.addstockInventory(dto);
            StockInventoryDto stockInventoryDto = new StockInventoryDto();
            stockInventoryDto.setRecordId(product.getId());
            stockInventoryDto.setRecordType(StockInQualifiedRecordTypeEnum.SALE_STOCK_IN.getCode());
            stockInventoryDto.setQualitity(product.getQuantity());
            stockInventoryDto.setProductModelId(product.getProductModelId());
            stockInventoryDto.setSalesLedgerId(ledger.getId());
            stockInventoryDto.setSalesLedgerProductId(product.getId());
            stockInventoryService.addstockInventory(stockInventoryDto);
        }
        //  æ›´æ–°é”€å”®è®¢å•入库状态
        ledger.setStockStatus(1);
        //  æŒ‰é”€å”®è®¢å•产品入库情况更新主单入库状态:1-部分入库,2-已入库
        List<SalesLedgerProduct> ledgerAllProducts = salesLedgerProductMapper.selectList(Wrappers.<SalesLedgerProduct>lambdaQuery().eq(SalesLedgerProduct::getSalesLedgerId, ledger.getId()));
        boolean hasStocked = CollectionUtils.isNotEmpty(ledgerAllProducts) && ledgerAllProducts.stream().anyMatch(item -> Objects.equals(item.getProductStockStatus(), 1));
        boolean allStocked = CollectionUtils.isNotEmpty(ledgerAllProducts) && ledgerAllProducts.stream().allMatch(item -> Objects.equals(item.getProductStockStatus(), 1));
        ledger.setStockStatus(allStocked ? 2 : (hasStocked ? 1 : 0));
        baseMapper.updateById(ledger);
    }
}
src/main/java/com/ruoyi/sales/service/impl/ShippingInfoServiceImpl.java
@@ -24,9 +24,11 @@
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import org.springframework.transaction.annotation.Transactional;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
@@ -68,7 +70,7 @@
    @Override
    public IPage<ShippingInfoDto> listPage(Page page, ShippingInfo req) {
        IPage<ShippingInfoDto> listPage = shippingInfoMapper.listPage(page, req);
        listPage.getRecords().forEach(item ->{
        listPage.getRecords().forEach(item -> {
            item.setCommonFileList(commonFileService.getFileListByBusinessId(item.getId(), FileNameType.SHIP.getValue()));
        });
        return listPage;
@@ -82,10 +84,10 @@
            throw new RuntimeException("发货信息不存在");
        }
        //扣减库存
        if(!"已发货".equals(byId.getStatus())){
        if (!"已发货".equals(byId.getStatus())) {
            SalesLedgerProduct salesLedgerProduct = salesLedgerProductMapper.selectById(byId.getSalesLedgerProductId());
            if (salesLedgerProduct != null) {
                stockUtils.substractStock(salesLedgerProduct.getProductModelId(), salesLedgerProduct.getQuantity(), StockOutQualifiedRecordTypeEnum.SALE_SHIP_STOCK_OUT.getCode(), req.getId());
                stockUtils.substractStock(salesLedgerProduct.getSalesLedgerId(), salesLedgerProduct.getId(), salesLedgerProduct.getProductModelId(), salesLedgerProduct.getQuantity(), StockOutQualifiedRecordTypeEnum.SALE_SHIP_STOCK_OUT.getCode(), req.getId());
            }
        }
        byId.setExpressNumber(req.getExpressNumber());
@@ -108,10 +110,10 @@
        }
        // è¿ç§»æ–‡ä»¶
        if(CollectionUtils.isNotEmpty(req.getTempFileIds())){
        if (CollectionUtils.isNotEmpty(req.getTempFileIds())) {
            tempFileService.migrateTempFilesToFormal(req.getId(), req.getTempFileIds(), FileNameType.SHIP.getValue());
        }
        return update ;
        return update;
    }
@@ -119,21 +121,21 @@
    public boolean delete(List<Long> ids) {
        List<ShippingInfo> shippingInfos = shippingInfoMapper.selectList(new LambdaQueryWrapper<ShippingInfo>()
                .in(ShippingInfo::getId, ids));
        if(CollectionUtils.isEmpty(shippingInfos)) return false;
        if (CollectionUtils.isEmpty(shippingInfos)) return false;
        // åˆ é™¤é™„ä»¶
        commonFileService.deleteByBusinessIds(ids, FileNameType.SHIP.getValue());
        // æ‰£å·²å‘货库存
        for (ShippingInfo shippingInfo : shippingInfos) {
            if("已发货".equals(shippingInfo.getStatus())) {
            if ("已发货".equals(shippingInfo.getStatus())) {
                stockUtils.deleteStockOutRecord(shippingInfo.getId(), StockOutQualifiedRecordTypeEnum.SALE_SHIP_STOCK_OUT.getCode());
            }
        }
        // åˆ é™¤å‘货审批
        if(CollectionUtils.isNotEmpty(shippingInfos)){
            for (ShippingInfo shippingInfo : shippingInfos){
        if (CollectionUtils.isNotEmpty(shippingInfos)) {
            for (ShippingInfo shippingInfo : shippingInfos) {
                ApproveProcess one = approveProcessService.getOne(new LambdaQueryWrapper<ApproveProcess>()
                        .like(ApproveProcess::getApproveReason, shippingInfo.getShippingNo()));
                if(one != null){
                if (one != null) {
                    approveProcessService.delByIds(Collections.singletonList(one.getId()));
                }
            }
@@ -144,7 +146,7 @@
    @Override
    public List<SalesLedgerProductDto> getReturnManagementDtoById(Long shippingId) {
        return shippingInfoMapper.getReturnManagementDtoById(shippingId );
        return shippingInfoMapper.getReturnManagementDtoById(shippingId);
    }
src/main/java/com/ruoyi/stock/dto/StockInventoryDto.java
@@ -39,4 +39,8 @@
    private BigDecimal currentStock;
    private BigDecimal  unLockedQuantity;
    private Long salesLedgerId;
    private Long salesLedgerProductId;
}
src/main/java/com/ruoyi/stock/pojo/StockInRecord.java
@@ -62,4 +62,10 @@
    @ApiModelProperty(value = "修改用户")
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private Integer updateUser;
    @ApiModelProperty("销售订单ID")
    private Long salesLedgerId;
    @ApiModelProperty("销售订单产品ID")
    private Long salesLedgerProductId;
}
src/main/java/com/ruoyi/stock/pojo/StockOutRecord.java
@@ -71,4 +71,10 @@
    @ApiModelProperty(value = "类型  0合格入库 1不合格入库")
    private String type;
    @ApiModelProperty("销售订单ID")
    private Long salesLedgerId;
    @ApiModelProperty("销售订单产品ID")
    private Long salesLedgerProductId;
}
src/main/java/com/ruoyi/stock/service/impl/StockInRecordServiceImpl.java
@@ -2,6 +2,8 @@
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum;
@@ -11,6 +13,10 @@
import com.ruoyi.common.utils.OrderUtils;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.sales.mapper.SalesLedgerMapper;
import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
import com.ruoyi.sales.pojo.SalesLedger;
import com.ruoyi.sales.pojo.SalesLedgerProduct;
import com.ruoyi.stock.dto.StockInRecordDto;
import com.ruoyi.stock.dto.StockInventoryDto;
import com.ruoyi.stock.dto.StockUninventoryDto;
@@ -28,6 +34,7 @@
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Objects;
@Service
@AllArgsConstructor
@@ -36,6 +43,8 @@
    private StockInRecordMapper stockInRecordMapper;
    private StockInventoryMapper stockInventoryMapper;
    private StockUninventoryMapper stockUninventoryMapper;
    private SalesLedgerProductMapper salesLedgerProductMapper;
    private SalesLedgerMapper salesLedgerMapper;
    @Override
    public IPage<StockInRecordDto> listPage(Page page, StockInRecordDto stockInRecordDto) {
@@ -58,7 +67,7 @@
    public int update(Long id, StockInRecordDto stockInRecordDto) {
        // åˆ¤æ–­å¯¹è±¡æ˜¯å¦å­˜åœ¨
        StockInRecord stockInRecord = stockInRecordMapper.selectById(id);
        if (stockInRecord == null){
        if (stockInRecord == null) {
            throw new BaseException("该入库记录不存在,无法更新!!!");
        }
@@ -72,29 +81,76 @@
    public int batchDelete(List<Long> ids) {
        for (Long id : ids) {
            StockInRecord stockInRecord = stockInRecordMapper.selectById(id);
            validateCanDeleteBySalesLedger(stockInRecord);
            if (stockInRecord.getType().equals("0")) {
                StockInventory stockInventory = stockInventoryMapper.selectOne(new LambdaQueryWrapper<StockInventory>().eq(StockInventory::getProductModelId, stockInRecord.getProductModelId()));
                if (stockInventory == null) {
                    throw new BaseException("库存记录中没有对应的产品,无法删除!!!");
                }else {
                } else {
                    StockInventoryDto stockInRecordDto = new StockInventoryDto();
                    stockInRecordDto.setProductModelId(stockInventory.getProductModelId());
                    stockInRecordDto.setQualitity(stockInRecord.getStockInNum());
                    stockInventoryMapper.updateSubtractStockInventory(stockInRecordDto);
                    int affectRows = stockInventoryMapper.updateSubtractStockInventory(stockInRecordDto);
                    if (affectRows <= 0) {
                        throw new BaseException("库存回退失败,当前库存不足,无法删除该入库记录");
                    }
                    // é”€å”®å…¥åº“记录删除时,回退销售产品和销售订单入库状态
                    rollbackSalesStockStatus(stockInRecord);
                }
            }else if (stockInRecord.getType().equals("1")) {
            } else if (stockInRecord.getType().equals("1")) {
                StockUninventory stockUninventory = stockUninventoryMapper.selectOne(new LambdaQueryWrapper<StockUninventory>().eq(StockUninventory::getProductModelId, stockInRecord.getProductModelId()));
                if (stockUninventory == null) {
                    throw new BaseException("库存记录中没有对应的产品,无法删除!!!");
                }else {
                } else {
                    StockUninventoryDto stockUninventoryDto = new StockUninventoryDto();
                    stockUninventoryDto.setProductModelId(stockUninventory.getProductModelId());
                    stockUninventoryDto.setQualitity(stockInRecord.getStockInNum());
                    stockUninventoryMapper.updateSubtractStockUnInventory(stockUninventoryDto);
                    int affectRows = stockUninventoryMapper.updateSubtractStockUnInventory(stockUninventoryDto);
                    if (affectRows <= 0) {
                        throw new BaseException("不合格库存回退失败,当前库存不足,无法删除该入库记录");
                    }
                }
            }
        }
        return stockInRecordMapper.deleteBatchIds(ids);
    }
    private void validateCanDeleteBySalesLedger(StockInRecord stockInRecord) {
        if (stockInRecord == null || stockInRecord.getSalesLedgerId() == null) {
            return;
        }
        SalesLedger salesLedger = salesLedgerMapper.selectById(stockInRecord.getSalesLedgerId());
        if (salesLedger != null && Objects.equals(salesLedger.getDeliveryStatus(), 5)) {
            throw new BaseException("销售订单已发货,对应入库记录不允许删除");
        }
    }
    private void rollbackSalesStockStatus(StockInRecord stockInRecord) {
        if (stockInRecord == null || stockInRecord.getSalesLedgerProductId() == null) {
            return;
        }
        SalesLedgerProduct salesLedgerProduct = salesLedgerProductMapper.selectById(stockInRecord.getSalesLedgerProductId());
        if (salesLedgerProduct == null) {
            return;
        }
        salesLedgerProduct.setProductStockStatus(0);
        salesLedgerProductMapper.updateById(salesLedgerProduct);
        Long salesLedgerId = stockInRecord.getSalesLedgerId() != null ? stockInRecord.getSalesLedgerId() : salesLedgerProduct.getSalesLedgerId();
        if (salesLedgerId == null) {
            return;
        }
        SalesLedger salesLedger = salesLedgerMapper.selectById(salesLedgerId);
        if (salesLedger == null) {
            return;
        }
        List<SalesLedgerProduct> ledgerProducts = salesLedgerProductMapper.selectList(Wrappers.<SalesLedgerProduct>lambdaQuery().eq(SalesLedgerProduct::getSalesLedgerId, salesLedgerId));
        boolean hasStocked = CollectionUtils.isNotEmpty(ledgerProducts)
                && ledgerProducts.stream().anyMatch(item -> Objects.equals(item.getProductStockStatus(), 1));
        boolean allStocked = CollectionUtils.isNotEmpty(ledgerProducts)
                && ledgerProducts.stream().allMatch(item -> Objects.equals(item.getProductStockStatus(), 1));
        salesLedger.setStockStatus(allStocked ? 2 : (hasStocked ? 1 : 0));
        salesLedgerMapper.updateById(salesLedger);
    }
    @Override
@@ -103,11 +159,11 @@
        for (StockInRecordExportData stockInRecordExportData : list) {
            if (stockInRecordExportData.getType().equals("0")) {
                stockInRecordExportData.setRecordType(EnumUtil.fromCode(StockOutQualifiedRecordTypeEnum.class, Integer.parseInt(stockInRecordExportData.getRecordType())).getValue());
            }else {
            } else {
                stockInRecordExportData.setRecordType(EnumUtil.fromCode(StockInUnQualifiedRecordTypeEnum.class, Integer.parseInt(stockInRecordExportData.getRecordType())).getValue());
            }
        }
        ExcelUtil<StockInRecordExportData> util = new ExcelUtil<>(StockInRecordExportData.class);
        util.exportExcel(response,list, "入库记录信息");
        util.exportExcel(response, list, "入库记录信息");
    }
}
src/main/java/com/ruoyi/stock/service/impl/StockInventoryServiceImpl.java
@@ -7,6 +7,7 @@
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ruoyi.common.enums.StockInQualifiedRecordTypeEnum;
import com.ruoyi.common.enums.StockOutQualifiedRecordTypeEnum;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.framework.web.domain.R;
import com.ruoyi.sales.mapper.SalesLedgerProductMapper;
@@ -42,10 +43,11 @@
@AllArgsConstructor
public class StockInventoryServiceImpl extends ServiceImpl<StockInventoryMapper, StockInventory> implements StockInventoryService {
    private  StockInventoryMapper stockInventoryMapper;
    private StockInventoryMapper stockInventoryMapper;
    private StockInRecordService stockInRecordService;
    private StockOutRecordService stockOutRecordService;
    private SalesLedgerProductMapper salesLedgerProductMapper;
    @Override
    public IPage<StockInventoryDto> pagestockInventory(Page page, StockInventoryDto stockInventoryDto) {
        return stockInventoryMapper.pagestockInventory(page, stockInventoryDto);
@@ -56,12 +58,22 @@
    @Transactional(rollbackFor = Exception.class)
    public Boolean addstockInventory(StockInventoryDto stockInventoryDto) {
        //新增入库记录再添加库存
        //  æ›´æ–°äº§å“å…¥åº“状态
        SalesLedgerProduct salesLedgerProduct = salesLedgerProductMapper.selectById(stockInventoryDto.getSalesLedgerProductId());
        if (salesLedgerProduct == null) {
            throw new ServiceException("入库失败,销售产品不存在");
        }
        salesLedgerProduct.setProductStockStatus(1);
        salesLedgerProductMapper.updateById(salesLedgerProduct);
        StockInRecordDto stockInRecordDto = new StockInRecordDto();
        stockInRecordDto.setRecordId(stockInventoryDto.getRecordId());
        stockInRecordDto.setRecordType(stockInventoryDto.getRecordType());
        stockInRecordDto.setStockInNum(stockInventoryDto.getQualitity());
        stockInRecordDto.setProductModelId(stockInventoryDto.getProductModelId());
        stockInRecordDto.setType("0");
        stockInRecordDto.setSalesLedgerId(stockInventoryDto.getSalesLedgerId());
        stockInRecordDto.setSalesLedgerProductId(stockInventoryDto.getSalesLedgerProductId());
        stockInRecordService.add(stockInRecordDto);
        //再进行新增库存数量库存
        //先查询库存表中的产品是否存在,不存在新增,存在更新
@@ -75,8 +87,8 @@
            newStockInventory.setLockedQuantity(stockInventoryDto.getLockedQuantity());
            newStockInventory.setWarnNum(stockInventoryDto.getWarnNum());
            stockInventoryMapper.insert(newStockInventory);
        }else {
             stockInventoryMapper.updateAddStockInventory(stockInventoryDto);
        } else {
            stockInventoryMapper.updateAddStockInventory(stockInventoryDto);
        }
        return true;
    }
@@ -92,6 +104,8 @@
        stockOutRecordDto.setStockOutNum(stockInventoryDto.getQualitity());
        stockOutRecordDto.setProductModelId(stockInventoryDto.getProductModelId());
        stockOutRecordDto.setType("0");
        stockOutRecordDto.setSalesLedgerId(stockInventoryDto.getSalesLedgerId());
        stockOutRecordDto.setSalesLedgerProductId(stockInventoryDto.getSalesLedgerProductId());
        stockOutRecordService.add(stockOutRecordDto);
        StockInventory oldStockInventory = stockInventoryMapper.selectOne(new QueryWrapper<StockInventory>().lambda().eq(StockInventory::getProductModelId, stockInventoryDto.getProductModelId()));
        if (ObjectUtils.isEmpty(oldStockInventory)) {
@@ -132,7 +146,7 @@
                        stockInventoryDto.setQualitity(dto.getQualitity());
                        stockInventoryDto.setRemark(dto.getRemark());
                        stockInventoryDto.setWarnNum(dto.getWarnNum());
                        if (ObjectUtils.isNotEmpty(dto.getLockedQuantity())&&dto.getLockedQuantity().compareTo(dto.getQualitity())>0) {
                        if (ObjectUtils.isNotEmpty(dto.getLockedQuantity()) && dto.getLockedQuantity().compareTo(dto.getQualitity()) > 0) {
                            throw new RuntimeException("冻结数量不能超过本次导入的库存数量");
                        }
                        stockInventoryDto.setLockedQuantity(dto.getLockedQuantity());
@@ -171,28 +185,28 @@
        List<StockInventoryExportData> list = stockInventoryMapper.listStockInventoryExportData(stockInventoryDto);
        ExcelUtil<StockInventoryExportData> util = new ExcelUtil<>(StockInventoryExportData.class);
        util.exportExcel(response,list, "库存信息");
        util.exportExcel(response, list, "库存信息");
    }
    @Override
    public IPage<StockInRecordDto> stockInventoryPage(StockInventoryDto stockInventoryDto, Page page) {
        return stockInventoryMapper.stockInventoryPage(stockInventoryDto,page);
        return stockInventoryMapper.stockInventoryPage(stockInventoryDto, page);
    }
    @Override
    public IPage<StockInventoryDto> stockInAndOutRecord(StockInventoryDto stockInventoryDto, Page page) {
        return stockInventoryMapper.stockInAndOutRecord(stockInventoryDto,page);
        return stockInventoryMapper.stockInAndOutRecord(stockInventoryDto, page);
    }
    @Override
    public Boolean frozenStock(StockInventoryDto stockInventoryDto) {
        StockInventory stockInventory = stockInventoryMapper.selectById(stockInventoryDto.getId());
        if (stockInventory.getQualitity().compareTo(stockInventoryDto.getLockedQuantity())<0) {
        if (stockInventory.getQualitity().compareTo(stockInventoryDto.getLockedQuantity()) < 0) {
            throw new RuntimeException("冻结数量不能超过库存数量");
        }
        if (ObjectUtils.isEmpty(stockInventory.getLockedQuantity())) {
            stockInventory.setLockedQuantity(stockInventoryDto.getLockedQuantity());
        }else {
        } else {
            stockInventory.setLockedQuantity(stockInventory.getLockedQuantity().add(stockInventoryDto.getLockedQuantity()));
        }
        return this.updateById(stockInventory);
@@ -201,7 +215,7 @@
    @Override
    public Boolean thawStock(StockInventoryDto stockInventoryDto) {
        StockInventory stockInventory = stockInventoryMapper.selectById(stockInventoryDto.getId());
        if (stockInventory.getLockedQuantity().compareTo(stockInventoryDto.getLockedQuantity())<0) {
        if (stockInventory.getLockedQuantity().compareTo(stockInventoryDto.getLockedQuantity()) < 0) {
            throw new RuntimeException("解冻数量不能超过冻结数量");
        }
        stockInventory.setLockedQuantity(stockInventory.getLockedQuantity().subtract(stockInventoryDto.getLockedQuantity()));
src/main/java/com/ruoyi/stock/service/impl/StockOutRecordServiceImpl.java
@@ -11,6 +11,8 @@
import com.ruoyi.common.utils.OrderUtils;
import com.ruoyi.common.utils.bean.BeanUtils;
import com.ruoyi.common.utils.poi.ExcelUtil;
import com.ruoyi.sales.mapper.SalesLedgerMapper;
import com.ruoyi.sales.pojo.SalesLedger;
import com.ruoyi.stock.dto.StockInventoryDto;
import com.ruoyi.stock.dto.StockOutRecordDto;
import com.ruoyi.stock.dto.StockUninventoryDto;
@@ -28,6 +30,7 @@
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Objects;
/**
 * <p>
@@ -43,6 +46,7 @@
    private StockOutRecordMapper stockOutRecordMapper;
    private StockInventoryMapper stockInventoryMapper;
    private StockUninventoryMapper stockUninventoryMapper;
    private SalesLedgerMapper salesLedgerMapper;
    @Override
    public IPage<StockOutRecordDto> listPage(Page page, StockOutRecordDto stockOutRecordDto) {
@@ -75,6 +79,7 @@
    public int batchDelete(List<Long> ids) {
        for (Long id : ids) {
            StockOutRecord stockOutRecord = stockOutRecordMapper.selectById(id);
            validateCanDeleteBySalesLedger(stockOutRecord);
            if (stockOutRecord.getType().equals("0")) {
                StockInventory stockInventory = stockInventoryMapper.selectOne(new LambdaQueryWrapper<StockInventory>().eq(StockInventory::getProductModelId, stockOutRecord.getProductModelId()));
                if (stockInventory == null) {
@@ -100,6 +105,16 @@
        return stockOutRecordMapper.deleteBatchIds(ids);
    }
    private void validateCanDeleteBySalesLedger(StockOutRecord stockOutRecord) {
        if (stockOutRecord == null || stockOutRecord.getSalesLedgerId() == null) {
            return;
        }
        SalesLedger salesLedger = salesLedgerMapper.selectById(stockOutRecord.getSalesLedgerId());
        if (salesLedger != null && Objects.equals(salesLedger.getDeliveryStatus(), 5)) {
            throw new BaseException("销售订单已发货,对应出库记录不允许删除");
        }
    }
    @Override
    public void exportStockOutRecord(HttpServletResponse response, StockOutRecordDto stockOutRecordDto) {
        List<StockOutRecordExportData> list = stockOutRecordMapper.listStockOutRecordExportData(stockOutRecordDto);
src/main/resources/mapper/sales/SalesLedgerMapper.xml
@@ -96,7 +96,7 @@
                AND T1.stock_status = #{salesLedgerDto.stockStatus}
            </if>
        </where>
        ORDER BY T1.entry_date DESC
        ORDER BY T1.entry_date DESC,T1.id DESC
    </select>
    <select id="selectIncomeStats" resultType="com.ruoyi.home.dto.IncomeExpenseAnalysisDto">
src/main/resources/mapper/stock/StockInventoryMapper.xml
@@ -51,6 +51,7 @@
        </set>
        where product_model_id = #{ew.productModelId} and qualitity >= #{ew.qualitity}
    </update>
    <select id="pagestockInventory" resultType="com.ruoyi.stock.dto.StockInventoryDto">
        select si.id,
        si.qualitity,
@@ -66,7 +67,7 @@
        pm.unit,
        p.product_name
        from stock_inventory si
        left join product_model pm on si. = pm.id
        left join product_model pm on si.product_model_id = pm.id
        left join product p on pm.product_id = p.id
        where 1 = 1
        <if test="ew.productName != null and ew.productName !=''">
@@ -76,6 +77,7 @@
            and si.product_model_id = #{ew.productModelId}
        </if>
    </select>
    <select id="listStockInventoryExportData" resultType="com.ruoyi.stock.execl.StockInventoryExportData">
        select si.qualitity,
        pm.model,
src/main/resources/mybatis/mybatis-config.xml
@@ -1,21 +1,21 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <!-- å…¨å±€å‚æ•° -->
    <settings>
        <!-- ä½¿å…¨å±€çš„æ˜ å°„器启用或禁用缓存 -->
        <setting name="cacheEnabled"             value="true"   />
        <setting name="cacheEnabled" value="true"/>
        <!-- å…è®¸JDBC æ”¯æŒè‡ªåŠ¨ç”Ÿæˆä¸»é”® -->
        <setting name="useGeneratedKeys"         value="true"   />
        <setting name="useGeneratedKeys" value="true"/>
        <!-- é…ç½®é»˜è®¤çš„æ‰§è¡Œå™¨.SIMPLE就是普通执行器;REUSE执行器会重用预处理语句(prepared statements);BATCH执行器将重用语句并执行批量更新 -->
        <setting name="defaultExecutorType"      value="SIMPLE" />
        <!-- æŒ‡å®š MyBatis æ‰€ç”¨æ—¥å¿—的具体实现 -->
        <setting name="logImpl"                  value="SLF4J"  />
<!--        <setting name="logImpl"                  value="org.apache.ibatis.logging.stdout.StdOutImpl"  />-->
        <setting name="defaultExecutorType" value="SIMPLE"/>
        <!-- æŒ‡å®š MyBatis æ‰€ç”¨æ—¥å¿—的具体实现 -->
        <!--        <setting name="logImpl"                  value="SLF4J"  />-->
        <setting name="logImpl" value="org.apache.ibatis.logging.stdout.StdOutImpl"/>
        <!-- ä½¿ç”¨é©¼å³°å‘½åæ³•转换字段 -->
        <!-- <setting name="mapUnderscoreToCamelCase" value="true"/> -->
    </settings>
        <!-- <setting name="mapUnderscoreToCamelCase" value="true"/> -->
    </settings>
</configuration>