昨天 3e5e22f5358156ff7430ee117546123ffe042611
src/main/java/com/ruoyi/stock/service/impl/StockOutRecordServiceImpl.java
@@ -23,6 +23,11 @@
import com.ruoyi.outsourcing.mapper.OutsourcingOrderProductMapper;
import com.ruoyi.outsourcing.pojo.OutsourcingOrder;
import com.ruoyi.outsourcing.pojo.OutsourcingOrderProduct;
import com.ruoyi.sales.dto.SalesLedgerDto;
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 java.time.LocalDateTime;
import com.ruoyi.stock.dto.OilOutAvailableDto;
@@ -64,6 +69,21 @@
     */
    private static final String OUT_CATEGORY_SALE = "销售";
    /**
     * 出库类别:代储。客户把自己的油寄存在我们的罐里,提走只是记录一笔,不扣库存、不进发货台账
     */
    private static final String OUT_CATEGORY_DEPOSIT = "代储";
    /**
     * 销售台账的销售类型:代储(卖存储位置)。这类台账没有产品明细,只有油库+储罐,见 SalesLedger.ledgerType
     */
    private static final String LEDGER_TYPE_DEPOSIT = "代储";
    /**
     * 销售台账产品明细的行类型:销售。见 sales_ledger_product.type
     */
    private static final Integer LEDGER_PRODUCT_TYPE_SALE = 1;
    private final StockOutRecordMapper stockOutRecordMapper;
    private final IVehicleService vehicleService;
    private final StockInventoryMapper stockInventoryMapper;
@@ -72,6 +92,8 @@
    private final AccountInvoiceApplicationMapper accountInvoiceApplicationMapper;
    private final OutsourcingOrderProductMapper outsourcingOrderProductMapper;
    private final OutsourcingOrderMapper outsourcingOrderMapper;
    private final SalesLedgerMapper salesLedgerMapper;
    private final SalesLedgerProductMapper salesLedgerProductMapper;
    @Override
    public IPage<StockOutRecordDto> listPage(Page page, StockOutRecordDto stockOutRecordDto) {
@@ -80,6 +102,7 @@
    @Override
    public int add(StockOutRecordDto stockOutRecordDto) {
        resolveSalesLedgerBinding(stockOutRecordDto);
        if (OUT_CATEGORY_SALE.equals(stockOutRecordDto.getOutCategory())) {
            // 销售类油品出库审批通过时要按批次扣减库存,批次不能为空
            if (StringUtils.isEmpty(stockOutRecordDto.getBatchNo())) {
@@ -109,9 +132,53 @@
            throw new BaseException("该出库记录不存在,无法更新!!!");
        }
        resolveSalesLedgerBinding(stockOutRecordDto);
        String[] ignoreProperties = {"id", "outbound_batches"};//排除id属性
        BeanUtils.copyProperties(stockOutRecordDto, stockOutRecord, ignoreProperties);
        return stockOutRecordMapper.updateById(stockOutRecord);
    }
    /**
     * 绑定销售台账:客户一律以台账为准覆盖,避免出库记录与台账的客户对不上;出库类别按台账的销售类型自动定,
     * 免得出现「绑了卖油台账却按代储不扣库存」这类矛盾数据。
     * <ul>
     *     <li>卖油(含 ledgerType 为空):出库类别置「销售」,并校验所选规格确实在该台账的销售明细里</li>
     *     <li>代储:出库类别置「代储」,带入台账的油库/储罐,跳过产品校验 ——
     *         代储台账本身就是卖存储位置,没有产品明细</li>
     * </ul>
     * salesLedgerId 为空时整体跳过,不绑台账的出库行为与改动前完全一致
     */
    private void resolveSalesLedgerBinding(StockOutRecordDto stockOutRecordDto) {
        if (stockOutRecordDto.getSalesLedgerId() == null) {
            return;
        }
        SalesLedger salesLedger = salesLedgerMapper.selectById(stockOutRecordDto.getSalesLedgerId());
        if (salesLedger == null) {
            throw new BaseException("所选销售台账不存在,销售台账id:" + stockOutRecordDto.getSalesLedgerId());
        }
        stockOutRecordDto.setCustomerId(salesLedger.getCustomerId());
        stockOutRecordDto.setCustomerName(salesLedger.getCustomerName());
        if (LEDGER_TYPE_DEPOSIT.equals(salesLedger.getLedgerType())) {
            stockOutRecordDto.setOutCategory(OUT_CATEGORY_DEPOSIT);
            stockOutRecordDto.setOilDepotId(salesLedger.getOilDepotId());
            stockOutRecordDto.setOilDepotName(salesLedger.getOilDepotName());
            stockOutRecordDto.setTankId(salesLedger.getTankId());
            stockOutRecordDto.setTankNo(salesLedger.getTankNo());
            return;
        }
        stockOutRecordDto.setOutCategory(OUT_CATEGORY_SALE);
        if (stockOutRecordDto.getProductModelId() == null) {
            throw new BaseException("绑定销售台账时必须选择产品规格,销售合同号:" + salesLedger.getSalesContractNo());
        }
        boolean belongsToLedger = salesLedgerProductMapper.selectList(
                        Wrappers.<SalesLedgerProduct>lambdaQuery()
                                .eq(SalesLedgerProduct::getSalesLedgerId, stockOutRecordDto.getSalesLedgerId())
                                .eq(SalesLedgerProduct::getType, LEDGER_PRODUCT_TYPE_SALE))
                .stream()
                .anyMatch(item -> stockOutRecordDto.getProductModelId().equals(item.getProductModelId()));
        if (!belongsToLedger) {
            throw new BaseException("所选产品不在该销售台账明细中,销售合同号:" + salesLedger.getSalesContractNo());
        }
    }
    @Override
@@ -520,6 +587,15 @@
    }
    @Override
    public IPage<SalesLedger> listBindableSalesLedger(Page page, SalesLedgerDto salesLedgerDto) {
        // 该查询用 /*data_scope*/ 跳过数据权限,而 MP 默认会把 count 语句优化成「SELECT COUNT(*) FROM sales_ledger
        // WHERE ...」,优化后标记丢失,count 反而被追加权限条件,total 会比实际记录少。关掉 count 优化后
        // count 退化成「SELECT COUNT(*) FROM (原句) TOTAL」,标记原样保留
        page.setOptimizeCountSql(false);
        return stockOutRecordMapper.bindableSalesLedgerPage(page, salesLedgerDto);
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int releaseByRecordIds(List<Long> recordIds, String recordType) {
        List<StockOutRecord> records = listByRecordIds(recordIds, recordType);