package cn.iocoder.yudao.module.mes.dal.mysql.wm.materialstock; import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX; import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX; import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockListReqVO; import cn.iocoder.yudao.module.mes.controller.admin.wm.materialstock.vo.MesWmMaterialStockPageReqVO; import cn.iocoder.yudao.module.mes.dal.dataobject.wm.materialstock.MesWmMaterialStockDO; import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper; import org.apache.ibatis.annotations.Mapper; import java.math.BigDecimal; import java.util.Collection; import java.util.List; /** * MES 库存台账 Mapper */ @Mapper public interface MesWmMaterialStockMapper extends BaseMapperX { default PageResult selectPage(MesWmMaterialStockPageReqVO reqVO, Collection itemTypeIds, Collection itemIds, Long virtualWarehouseId) { LambdaQueryWrapperX wrapper = new LambdaQueryWrapperX() .inIfPresent(MesWmMaterialStockDO::getItemTypeId, itemTypeIds) .inIfPresent(MesWmMaterialStockDO::getItemId, itemIds) .likeIfPresent(MesWmMaterialStockDO::getBatchCode, reqVO.getBatchCode()) .eqIfPresent(MesWmMaterialStockDO::getBatchId, reqVO.getBatchId()) .eqIfPresent(MesWmMaterialStockDO::getWarehouseId, reqVO.getWarehouseId()) .eqIfPresent(MesWmMaterialStockDO::getLocationId, reqVO.getLocationId()) .eqIfPresent(MesWmMaterialStockDO::getAreaId, reqVO.getAreaId()) .eqIfPresent(MesWmMaterialStockDO::getVendorId, reqVO.getVendorId()) .eqIfPresent(MesWmMaterialStockDO::getFrozen, reqVO.getFrozen()); wrapper.ne(MesWmMaterialStockDO::getQuantity, BigDecimal.ZERO) .orderByAsc(MesWmMaterialStockDO::getReceiptTime); // 虚拟仓过滤(Service 层已将 virtualFilter 解析为 virtualWarehouseId) if (virtualWarehouseId != null) { if (MesWmMaterialStockPageReqVO.VIRTUAL_FILTER_ONLY.equals(reqVO.getVirtualFilter())) { wrapper.eq(MesWmMaterialStockDO::getWarehouseId, virtualWarehouseId); } else if (MesWmMaterialStockPageReqVO.VIRTUAL_FILTER_EXCLUDE.equals(reqVO.getVirtualFilter())) { wrapper.ne(MesWmMaterialStockDO::getWarehouseId, virtualWarehouseId); } } return selectPage(reqVO, wrapper); } default Long selectCountByWarehouseId(Long warehouseId) { return selectCount(MesWmMaterialStockDO::getWarehouseId, warehouseId); } default Long selectCountByLocationId(Long locationId) { return selectCount(MesWmMaterialStockDO::getLocationId, locationId); } default Long selectCountByAreaId(Long areaId) { return selectCount(MesWmMaterialStockDO::getAreaId, areaId); } default List selectListByIds(Collection ids) { return selectByIds(ids); } default void updateByIds(Collection ids, MesWmMaterialStockDO updateObj) { update(updateObj, new LambdaUpdateWrapper() .in(MesWmMaterialStockDO::getId, ids)); } /** * 增量更新库存数量 * * @param id 库存记录编号 * @param count 变动数量(正数=增加,负数=扣减) * @param checkFlag 是否校验库存充足(为 true 时扣减不允许变为负数) * @return 影响行数 */ default int updateQuantity(Long id, BigDecimal count, boolean checkFlag) { LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper() .eq(MesWmMaterialStockDO::getId, id) .setSql("quantity = quantity + " + count); if (checkFlag && count.compareTo(BigDecimal.ZERO) < 0) { updateWrapper.ge(MesWmMaterialStockDO::getQuantity, count.abs()); // CAS 防负库存 } return update(null, updateWrapper); } /** * 增量更新库存占用量 * * @param id 库存记录编号 * @param count 变动数量(正数=增加占用,负数=减少占用) * @param checkFlag 是否校验可用量充足(为 true 时占用不允许超过可用量) * @return 影响行数 */ default int updateReservedQuantity(Long id, BigDecimal count, boolean checkFlag) { LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper() .eq(MesWmMaterialStockDO::getId, id) .setSql("reserved_quantity = reserved_quantity + " + count); if (checkFlag && count.compareTo(BigDecimal.ZERO) > 0) { // 校验可用量充足:quantity - frozen_quantity - reserved_quantity >= count updateWrapper.apply("quantity - IFNULL(frozen_quantity, 0) - IFNULL(reserved_quantity, 0) >= {0}", count); } return update(null, updateWrapper); } /** * 增量更新库存在途量 * * @param id 库存记录编号 * @param count 变动数量(正数=增加在途,负数=减少在途) * @return 影响行数 */ default int updateInTransitQuantity(Long id, BigDecimal count) { LambdaUpdateWrapper updateWrapper = new LambdaUpdateWrapper() .eq(MesWmMaterialStockDO::getId, id) .setSql("in_transit_quantity = in_transit_quantity + " + count); return update(null, updateWrapper); } /** * 按组合键查询库存记录 * * 唯一键:(itemId, warehouseId, locationId, areaId, batchId, vendorId) * 同一物料同一库位,不同供应商/批次的库存分开管理 */ default MesWmMaterialStockDO selectByCompositeKey(Long itemId, Long warehouseId, Long locationId, Long areaId, Long batchId, Long vendorId) { LambdaQueryWrapperX wrapper = new LambdaQueryWrapperX() .eqIfPresent(MesWmMaterialStockDO::getItemId, itemId) .eqIfPresent(MesWmMaterialStockDO::getWarehouseId, warehouseId) .eqIfPresent(MesWmMaterialStockDO::getLocationId, locationId) .eqIfPresent(MesWmMaterialStockDO::getAreaId, areaId); // batchId=null 时精确匹配 is null,避免 eqIfPresent 跳过条件导致匹配到其他批次 if (batchId != null) { wrapper.eq(MesWmMaterialStockDO::getBatchId, batchId); } else { wrapper.isNull(MesWmMaterialStockDO::getBatchId); } // vendorId=null 时精确匹配 is null if (vendorId != null) { wrapper.eq(MesWmMaterialStockDO::getVendorId, vendorId); } else { wrapper.isNull(MesWmMaterialStockDO::getVendorId); } return selectOne(wrapper); } /** * 按组合键查询库存记录(忽略供应商维度) * * 用于移库场景:移库时将库存合并到目标库位已有库存,不区分供应商 */ default MesWmMaterialStockDO selectByCompositeKeyIgnoreVendor(Long itemId, Long warehouseId, Long locationId, Long areaId, Long batchId) { LambdaQueryWrapperX wrapper = new LambdaQueryWrapperX() .eq(MesWmMaterialStockDO::getItemId, itemId) .eq(MesWmMaterialStockDO::getWarehouseId, warehouseId) .eq(MesWmMaterialStockDO::getLocationId, locationId) .eq(MesWmMaterialStockDO::getAreaId, areaId); // batchId=null 时精确匹配 is null if (batchId != null) { wrapper.eq(MesWmMaterialStockDO::getBatchId, batchId); } else { wrapper.isNull(MesWmMaterialStockDO::getBatchId); } wrapper.last("LIMIT 1"); return selectOne(wrapper); } default List selectList(MesWmMaterialStockListReqVO reqVO) { return selectList(new LambdaQueryWrapperX() .eqIfPresent(MesWmMaterialStockDO::getWarehouseId, reqVO.getWarehouseId()) .eqIfPresent(MesWmMaterialStockDO::getLocationId, reqVO.getLocationId()) .eqIfPresent(MesWmMaterialStockDO::getAreaId, reqVO.getAreaId()) .eqIfPresent(MesWmMaterialStockDO::getItemId, reqVO.getItemId()) .eqIfPresent(MesWmMaterialStockDO::getBatchId, reqVO.getBatchId()) .eqIfPresent(MesWmMaterialStockDO::getVendorId, reqVO.getVendorId()) .likeIfPresent(MesWmMaterialStockDO::getBatchCode, reqVO.getBatchCode()) .geIfPresent(MesWmMaterialStockDO::getUpdateTime, reqVO.getStartTime()) .leIfPresent(MesWmMaterialStockDO::getUpdateTime, reqVO.getEndTime()) .ne(MesWmMaterialStockDO::getQuantity, BigDecimal.ZERO) .orderByAsc(MesWmMaterialStockDO::getReceiptTime)); } }