feat(wms):复核详情增加合计数;库存分配新增通宇专用可分配库存查询(物料+箱号/卡板+Sheet Ref匹配

1. 复核详情(getInfo/getInfoReviewOrderNumber)头表回填totalReviewedQty/totalPlanQty/materialKindCount,
   口径与列表queryList聚合一致(计划量=Σifnull(material_plan_qty,pending+reviewed))
2. 新增 GET /materialInventoryApi/assignableList,按通宇账号分流(TongyuOrgUtil:组织ID=2830或组织名含"通宇"):
   - 通宇:启用新匹配。双模式入参——传outOrderId+materialDetailId(须成对)则匹配值全部后端自取出库单/明细;
     不传则按平铺参数(materialBaseInfoId/materialCode+boxPalletNo+sheetRefNo,多值串自动拆token OR-LIKE)。
     固定条件:del_flag=1且可分配数量(allocation_quantity)>0,不分页全量返回,不套用用户组织数据权限
   - 非通宇:保持原/list行为,内部直调list();进原查询前清除materialDetailId(新接口专用参数,防泄入
     原查询的a.material_detail_id=上架单明细ID条件导致查空)
3. autoAssign自动分配同步分流:通宇走token匹配,非通宇保持原eq精确匹配不变
4. 新增util/BatchNoTokenUtil(批次属性多值拆分)、util/TongyuOrgUtil;库存批次属性回填抽为
   fillBatchAttributes供/list与可分配查询复用,原逻辑行为不变
This commit is contained in:
rcx
2026-08-26 09:30:01 +08:00
parent 7a5e124f98
commit 7d8e1c3872
9 changed files with 355 additions and 13 deletions
@@ -3,6 +3,7 @@ package com.mhd.wms.application.service.materialInventory;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.nacos.common.utils.CollectionUtils;
import com.mhd.common.core.exception.ServiceException;
import com.mhd.common.core.utils.bean.BeanUtils;
import com.mhd.common.core.utils.StringUtils;
import com.mhd.common.core.web.domain.AjaxResult;
@@ -22,6 +23,11 @@ import com.mhd.wms.interfaces.dto.materialInventory.MaterialInventoryDTO;
import com.mhd.wms.domain.materialBarCode.repository.facade.IMaterialBarCodeService;
import com.mhd.wms.domain.materialBarCode.repository.po.MaterialBarCodePO;
import com.mhd.wms.domain.materialMoreDetail.repository.po.MaterialMoreDetailPO;
import com.mhd.wms.domain.outMaterialDetail.entity.OutMaterialDetail;
import com.mhd.wms.domain.outMaterialDetail.repository.mapper.OutMaterialDetailMapper;
import com.mhd.wms.domain.stockOutOrder.repository.facade.IStockOutOrderService;
import com.mhd.wms.domain.stockOutOrder.repository.po.StockOutOrderPO;
import com.mhd.wms.util.BatchNoTokenUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -49,6 +55,10 @@ public class MaterialInventoryApplicationService {
private MaterialInventoryMapper materialInventoryMapper;
@Autowired
private IMaterialBarCodeService materialBarCodeService;
@Autowired
private IStockOutOrderService stockOutOrderService;
@Autowired
private OutMaterialDetailMapper outMaterialDetailMapper;
/**
@@ -122,18 +132,26 @@ public class MaterialInventoryApplicationService {
*/
public List<MaterialInventoryPO> queryListWithBatchAttributes(MaterialInventoryDO materialInventoryDO) {
List<MaterialInventoryPO> list = queryList(materialInventoryDO);
fillBatchAttributes(list);
return list;
}
/**
* 批量回填批次属性(isDisplay=1):拉取批次配置并从库存表取值,避免N+1查询。
* 原为 queryListWithBatchAttributes 内部逻辑,抽出供可分配库存查询复用。
*/
private void fillBatchAttributes(List<MaterialInventoryPO> list) {
if (CollectionUtils.isEmpty(list)) {
return list;
return;
}
// 性能优化:批量获取批次属性,避免N+1查询问题
// 1. 收集所有唯一的materialBaseInfoId
Set<Long> materialBaseInfoIdSet = list.stream()
.map(MaterialInventoryPO::getMaterialBaseInfoId)
.filter(Objects::nonNull)
.collect(Collectors.toSet());
// 2. 批量查询批次属性(使用Map缓存,避免重复查询相同的materialBaseInfoId
Map<Long, List<BatchDetailFeignPO>> batchDetailMap = new HashMap<>();
for (Long materialBaseInfoId : materialBaseInfoIdSet) {
@@ -154,12 +172,88 @@ public class MaterialInventoryApplicationService {
log.warn("获取物料批次属性失败,物料基础信息ID:{},错误:{}", materialBaseInfoId, e.getMessage());
}
}
// 3. 为每个物料库存设置更多属性(从库存表中获取值)
setMaterialMoreDetailListFromInventory(list, batchDetailMap);
}
/**
* 出库单明细可分配库存查询(库存分配弹窗专用),双模式:
* 模式A(推荐):传 outOrderId + materialDetailId,匹配值全部后端从出库单/明细自取——
* 1) 物料编码必匹配(优先 materialBaseInfoId 精确,兜底 material_code);
* 2) 明细有箱号/卡板 → 同时匹配(多值拆 token,OR 命中);
* 3) 明细有 Sheet Ref NO's → 同时匹配(同上);
* 4) 货主、仓库取出库单 —— 替代前端 customerName 换算货主(客户≠货主时会误过滤)。
* 模式B(平铺参数):不传双 ID 时,按 materialBaseInfoId|materialCode + boxPalletNo + sheetRefNo
* (可选 batchRefNo、shipperId、warehouseId)查询,多值串后端自动拆 token;条件正确性由调用方负责。
* 两种模式均:只返回匹配到的库存行且可分配数量>0;不分页;不套用 queryList 的用户组织数据权限。
*/
public List<MaterialInventoryPO> queryAssignableList(Long outOrderId, Long materialDetailId, MaterialInventoryDTO flatQuery) {
MaterialInventoryDO query;
if (outOrderId != null || materialDetailId != null) {
if (outOrderId == null || materialDetailId == null) {
throw new ServiceException("outOrderId 与 materialDetailId 必须成对传入");
}
query = buildAssignableQueryByOutOrder(outOrderId, materialDetailId);
} else {
query = buildAssignableQueryByFlatParams(flatQuery);
}
List<MaterialInventoryPO> list = materialInventoryMapper.queryAssignableList(query);
fillBatchAttributes(list);
return list;
}
/**
* 模式A:按出库单+明细自取匹配条件
*/
private MaterialInventoryDO buildAssignableQueryByOutOrder(Long outOrderId, Long materialDetailId) {
StockOutOrderPO order = stockOutOrderService.getInfo(outOrderId);
if (order == null) {
throw new ServiceException("出库单不存在");
}
OutMaterialDetail detail = outMaterialDetailMapper.selectById(materialDetailId);
if (detail == null || !Integer.valueOf(1).equals(detail.getDelFlag())) {
throw new ServiceException("出库单物料明细不存在");
}
if (detail.getMaterialBaseInfoId() == null
&& StringUtils.isBlank(detail.getMaterialCode())
&& StringUtils.isBlank(detail.getMaterialNo())) {
throw new ServiceException("物料明细缺少物料信息,无法查询可分配库存");
}
MaterialInventoryDO query = new MaterialInventoryDO();
query.setShipperId(order.getShipperId());
query.setWarehouseId(detail.getWarehouseId() != null
? detail.getWarehouseId() : order.getWarehouseId());
query.setMaterialBaseInfoId(detail.getMaterialBaseInfoId());
if (detail.getMaterialBaseInfoId() == null) {
query.setMaterialCode(StringUtils.isNotBlank(detail.getMaterialCode())
? detail.getMaterialCode() : detail.getMaterialNo());
}
// 需求匹配键:物料 + 箱号/卡板 + Sheet Ref NO'sbatchRefNoList 默认不赋值(不参与匹配)
query.setBoxPalletNoList(BatchNoTokenUtil.splitTokens(detail.getBoxPalletNo()));
query.setSheetRefNoList(BatchNoTokenUtil.splitTokens(detail.getSheetRefNo()));
return query;
}
/**
* 模式B:平铺参数构造匹配条件(条件正确性由调用方负责;至少要有物料标识)
*/
private MaterialInventoryDO buildAssignableQueryByFlatParams(MaterialInventoryDTO flatQuery) {
if (flatQuery == null
|| (flatQuery.getMaterialBaseInfoId() == null && StringUtils.isBlank(flatQuery.getMaterialCode()))) {
throw new ServiceException("请传 outOrderId+materialDetailId,或至少传 materialBaseInfoId / materialCode");
}
MaterialInventoryDO query = new MaterialInventoryDO();
query.setShipperId(flatQuery.getShipperId());
query.setWarehouseId(flatQuery.getWarehouseId());
query.setMaterialBaseInfoId(flatQuery.getMaterialBaseInfoId());
query.setMaterialCode(flatQuery.getMaterialCode());
query.setBoxPalletNoList(BatchNoTokenUtil.splitTokens(flatQuery.getBoxPalletNo()));
query.setSheetRefNoList(BatchNoTokenUtil.splitTokens(flatQuery.getSheetRefNo()));
query.setBatchRefNoList(BatchNoTokenUtil.splitTokens(flatQuery.getBatchRefNo()));
return query;
}
/**
* 为物料库存设置更多属性(从库存表中获取值)
@@ -182,9 +182,11 @@ public class ReviewOrderApplicationService {
Map<Long, List<BatchDetailFeignPO>> batchDetailMap = loadDisplayBatchDetailMap(details);
fillDynamicBatchDisplayFields(details, batchDetailMap);
buildReviewMaterialMoreDetailListLikeShelf(details, batchDetailMap);
fillHeaderSummary(header, details);
header.setMaterialDetailList(details);
return header;
}
public ReviewOrderPO getDetailByReviewOrderNumber(String reviewOrderNumber) {
if (StringUtils.isEmpty(reviewOrderNumber)) {
@@ -199,6 +201,7 @@ public class ReviewOrderApplicationService {
Map<Long, List<BatchDetailFeignPO>> batchDetailMap = loadDisplayBatchDetailMap(details);
fillDynamicBatchDisplayFields(details, batchDetailMap);
buildReviewMaterialMoreDetailListLikeShelf(details, batchDetailMap);
fillHeaderSummary(header, details);
header.setMaterialDetailList(details);
return header;
}
@@ -854,6 +857,36 @@ public class ReviewOrderApplicationService {
return v == null ? BigDecimal.ZERO : v;
}
/**
* 详情头表回填合计。口径与列表 queryList 聚合(ReviewOrderMapper.xml)严格一致:
* totalPlanQty = Σ ifnull(material_plan_qty, ifnull(pending_review_qty,0) + ifnull(reviewed_qty,0))
* totalReviewedQty = Σ ifnull(reviewed_qty,0) —— 即「出库总数量(取已复核数量)」
* materialKindCount = count(distinct material_base_info_id)
*/
private void fillHeaderSummary(ReviewOrderPO header, List<ReviewMaterialDetailPO> details) {
BigDecimal totalPlan = BigDecimal.ZERO;
BigDecimal totalReviewed = BigDecimal.ZERO;
Set<Long> materialIdSet = new HashSet<>();
if (!CollectionUtils.isEmpty(details)) {
for (ReviewMaterialDetailPO d : details) {
if (d == null) {
continue;
}
BigDecimal plan = d.getMaterialPlanQty() != null
? d.getMaterialPlanQty()
: nz(d.getPendingReviewQty()).add(nz(d.getReviewedQty()));
totalPlan = totalPlan.add(plan);
totalReviewed = totalReviewed.add(nz(d.getReviewedQty()));
if (d.getMaterialBaseInfoId() != null) {
materialIdSet.add(d.getMaterialBaseInfoId());
}
}
}
header.setTotalPlanQty(totalPlan);
header.setTotalReviewedQty(totalReviewed);
header.setMaterialKindCount(materialIdSet.size());
}
/**
* 详情展示口径:
* reviewQtyEa 展示待复核数量,cancelQty 展示已复核数量。
@@ -37,7 +37,10 @@ import com.mhd.wms.domain.materialBaseInfo.repository.po.MaterialBaseInfoPO;
import com.mhd.wms.domain.materialInventory.entity.MaterialInventory;
import com.mhd.wms.domain.materialInventory.repository.mapper.MaterialInventoryMapper;
import com.mhd.wms.domain.materialInventory.repository.po.MaterialInventoryPO;
import com.mhd.wms.domain.materialInventory.repository.todo.MaterialInventoryDO;
import com.mhd.wms.domain.materialInventory.service.MaterialInventoryDomainService;
import com.mhd.wms.util.BatchNoTokenUtil;
import com.mhd.wms.util.TongyuOrgUtil;
import com.mhd.wms.domain.materialMoreDetail.repository.po.MaterialMoreDetailPO;
import com.mhd.wms.domain.outMaterialDetail.entity.OutMaterialDetail;
import com.mhd.wms.domain.outMaterialDetail.repository.facade.IOutMaterialDetailService;
@@ -1005,24 +1008,46 @@ public class StockOutOrderApplicationService {
.eq(OutMaterialDetail::getOutOrderNumber, stockOutOrderDb.getOutOrderNumber()));
List<OutMaterialDetailDO> materialDetailList = cn.hutool.core.bean.BeanUtil.copyToList(outMaterialDetailList, OutMaterialDetailDO.class);
List<OutMaterialDetailDO> materialDetailList2 = new ArrayList<>();
// 仅通宇账号启用与库存分配弹窗同口径的新匹配物料+箱号/卡板+Sheet Ref 多值拆 token
// 其他账号保持原 eq 精确匹配行为不变
boolean tongyuAssign = TongyuOrgUtil.isTongyu(SecurityUtils.getLoginUser());
for (OutMaterialDetailDO detail : materialDetailList) {
String batchRefNo = detail.getBatchRefNo();
String sheetRefNo = detail.getSheetRefNo();
String boxPalletNo = detail.getBoxPalletNo();
Long materialBaseInfoId = detail.getMaterialBaseInfoId();
Long warehouseId = detail.getWarehouseId();
List<MaterialInventory> materialInventories = materialInventoryMapper.selectList(new QueryWrapper<MaterialInventory>().lambda()
.eq(MaterialInventory::getBatchRefNo, batchRefNo)
.eq(MaterialInventory::getSheetRefNo, sheetRefNo)
.eq(MaterialInventory::getBoxPalletNo, boxPalletNo)
.eq(MaterialInventory::getWarehouseId, warehouseId)
.eq(MaterialInventory::getMaterialBaseInfoId, materialBaseInfoId));
List<MaterialInventoryPO> materialInventories;
if (tongyuAssign) {
MaterialInventoryDO assignQuery = new MaterialInventoryDO();
assignQuery.setShipperId(stockOutOrderDb.getShipperId());
assignQuery.setWarehouseId(warehouseId != null ? warehouseId : stockOutOrderDb.getWarehouseId());
assignQuery.setMaterialBaseInfoId(materialBaseInfoId);
assignQuery.setBoxPalletNoList(BatchNoTokenUtil.splitTokens(boxPalletNo));
assignQuery.setSheetRefNoList(BatchNoTokenUtil.splitTokens(sheetRefNo));
materialInventories = materialInventoryMapper.queryAssignableList(assignQuery);
} else {
List<MaterialInventory> legacyInventories = materialInventoryMapper.selectList(new QueryWrapper<MaterialInventory>().lambda()
.eq(MaterialInventory::getBatchRefNo, batchRefNo)
.eq(MaterialInventory::getSheetRefNo, sheetRefNo)
.eq(MaterialInventory::getBoxPalletNo, boxPalletNo)
.eq(MaterialInventory::getWarehouseId, warehouseId)
.eq(MaterialInventory::getMaterialBaseInfoId, materialBaseInfoId));
materialInventories = new ArrayList<>();
if (legacyInventories != null) {
for (MaterialInventory mi : legacyInventories) {
MaterialInventoryPO po = new MaterialInventoryPO();
cn.hutool.core.bean.BeanUtil.copyProperties(mi, po);
materialInventories.add(po);
}
}
}
if (materialInventories == null || materialInventories.isEmpty()) {
throw new ServiceException("库存不存在:" + batchRefNo + " " + sheetRefNo + " " + boxPalletNo);
}
BigDecimal remainingQuantity = detail.getQuantity(); // 计划数量
for (MaterialInventory materialInventory : materialInventories) {
for (MaterialInventoryPO materialInventory : materialInventories) {
if (remainingQuantity.compareTo(BigDecimal.ZERO) <= 0) {
break;
}
@@ -41,6 +41,14 @@ public interface MaterialInventoryMapper extends BaseMapper<MaterialInventory>
//查物料库存列表-按货主+物料+仓库库存查询第三个页签update_time 取合并后最大值
public List<MaterialInventoryPO> queryListByHzWlUnit(MaterialInventoryDO materialInventoryDO);
/**
* 出库单明细可分配库存查询库存分配弹窗专用
* 物料必匹配materialBaseInfoId 精确 / material_code 兜底
* 箱号/卡板Sheet Ref NO's及可选 Batch Ref NO's token 列表 OR-LIKE 同时匹配明细多值拆分后传入
* 货主/仓库由调用方取自出库单仅返回 del_flag=1 且可分配数量(allocation_quantity)>0 的库存行
*/
public List<MaterialInventoryPO> queryAssignableList(MaterialInventoryDO materialInventoryDO);
/**
* @description 批量增加库存
* @author ZhouGY
@@ -262,4 +262,13 @@ public class MaterialInventoryDO extends MaterialBaseDO {
private String updateTimeStart;
private String updateTimeEnd;
@ApiModelProperty("库存分配匹配:箱号/卡板号 token 列表(明细多值拆分后,OR 匹配;空则不参与匹配)")
private List<String> boxPalletNoList;
@ApiModelProperty("库存分配匹配:Sheet Ref NO's token 列表(明细多值拆分后,OR 匹配;空则不参与匹配)")
private List<String> sheetRefNoList;
@ApiModelProperty("库存分配匹配:Batch Ref NO's token 列表(默认不启用,仅显式赋值时参与匹配)")
private List<String> batchRefNoList;
}
@@ -8,6 +8,7 @@ import com.mhd.common.core.utils.StringUtils;
import com.mhd.common.core.web.controller.BaseController;
import com.mhd.common.core.web.domain.AjaxResult;
import com.mhd.common.core.web.page.TableDataInfo;
import com.mhd.common.security.utils.SecurityUtils;
import com.mhd.system.api.UserServiceFeign;
import com.mhd.wms.application.service.materialInventory.MaterialInventoryApplicationService;
import com.mhd.wms.domain.materialInventory.repository.po.MaterialInventoryPO;
@@ -17,6 +18,7 @@ import com.mhd.wms.domain.materialInventory.repository.todo.MaterialInventoryQue
import com.mhd.wms.interfaces.assember.materialInventory.MaterialInventoryAssembler;
import com.mhd.wms.interfaces.dto.materialInventory.MaterialInventoryDTO;
import com.mhd.wms.interfaces.dto.materialInventory.MaterialInventoryQueryListDTO;
import com.mhd.wms.util.TongyuOrgUtil;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
@@ -138,6 +140,36 @@ public class MaterialInventoryApi extends BaseController {
return tableDataInfo;
}
/**
* 出库单明细可分配库存库存分配弹窗专用按通宇账号分流
* 通宇账号组织ID=2830 组织名含通宇启用需求三新逻辑双模式入参
* 模式A推荐 outOrderId + materialDetailId物料/箱号/卡板/Sheet Ref/货主/仓库 全部后端自取
* 模式B平铺参数与旧 /list 传参风格一致不传双 ID materialBaseInfoId|materialCode
* + boxPalletNo + sheetRefNo可选 batchRefNoshipperIdwarehouseId查询多值串后端自动拆分
* 两种模式均仅返回可分配数量>0 的匹配行不分页
* 非通宇账号保持原行为内部按原 /list 逻辑查询分页customerName 换算等与库存查询页完全一致
*/
@ApiOperation("出库单明细可分配库存列表(仅通宇账号启用新匹配逻辑,其他账号按原 /list 逻辑查询)")
@GetMapping("/assignableList")
public TableDataInfo assignableList(MaterialInventoryDTO materialInventoryDTO,
@RequestParam(value = "outOrderId", required = false) Long outOrderId,
@RequestParam(value = "materialDetailId", required = false) Long materialDetailId,
@RequestParam(value = "customerName", required = false) String customerName,
@RequestParam(value = "excludeZeroInventoryQuantity", required = false) Boolean excludeZeroInventoryQuantity,
@RequestParam(value = "expiryDateStart", required = false) String expiryDateStart,
@RequestParam(value = "expiryDateEnd", required = false) String expiryDateEnd,
@RequestParam(value = "orderByExpiryDate", required = false) Boolean orderByExpiryDate) {
// 仅通宇账号启用需求三新逻辑物料+箱号/卡板+Sheet Ref 匹配可分配>0不分页其他账号保持原 /list 行为
if (TongyuOrgUtil.isTongyu(SecurityUtils.getLoginUser())) {
List<MaterialInventoryPO> list = materialInventoryApplicationService.queryAssignableList(outOrderId, materialDetailId, materialInventoryDTO);
return getDataTable(list);
}
// materialDetailId 是新接口专用参数出库单明细ID库存 DTO 的同名字段语义是上架单明细ID
// 泄入原查询会生成错误的 a.material_detail_id 条件导致查空进原查询前显式清除
materialInventoryDTO.setMaterialDetailId(null);
return list(materialInventoryDTO, customerName, excludeZeroInventoryQuantity, expiryDateStart, expiryDateEnd, orderByExpiryDate);
}
@ApiOperation("查询物料库存列表不分页;queryRule=hz 时按货主+物料分组(同一物料在不同货主各占一行)")
@GetMapping("/listAll")
public TableDataInfo listAll(MaterialInventoryDTO materialInventoryDTO)
@@ -0,0 +1,40 @@
package com.mhd.wms.util;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
/**
* 出库分配批次属性多值拆分工具
* 出库明细的箱号/卡板号Sheet Ref NO'sBatch Ref NO's 可能是多个值拼接的字符串
* Excel 导入单元格原样入库而库存表每行通常只有一个或多个拼接的
* 直接整串 LIKE 匹配不到任何行可分配库存不完整的主要根因
*
* @author rcx
*/
public final class BatchNoTokenUtil {
/** 英文/中文逗号、分号、顿号、斜杠、空白 */
private static final String SEPARATOR_REGEX = "[,;;、/\\s]+";
private BatchNoTokenUtil() {
}
/**
* 按常见分隔符拆分trim去空去重
*
* @param value 明细上的批次属性原始值
* @return token 列表无可拆内容时返回 null表示不参与匹配
*/
public static List<String> splitTokens(String value) {
if (value == null || value.trim().isEmpty()) {
return null;
}
List<String> tokens = Arrays.stream(value.split(SEPARATOR_REGEX))
.map(String::trim)
.filter(s -> !s.isEmpty())
.distinct()
.collect(Collectors.toList());
return tokens.isEmpty() ? null : tokens;
}
}
@@ -0,0 +1,44 @@
package com.mhd.wms.util;
import com.mhd.common.core.utils.StringUtils;
import com.mhd.system.api.model.LoginUser;
/**
* 通宇组织/账号判断工具
* 口径来源既有代码约定通宇组织ID=2830 HandoverTaskOrderDomainService/StockOutOrderApplicationService 注释
* 由于测试/生产环境组织 ID 可能不一致仓库 ID 已知存在差异同时按组织名称兜底
*
* @author rcx
*/
public final class TongyuOrgUtil {
/** 通宇组织ID(生产口径,见既有代码注释) */
public static final Long TONGYU_ORGANIZATION_ID = 2830L;
/** 组织名称关键字 */
private static final String TONGYU_KEYWORD = "通宇";
private TongyuOrgUtil() {
}
/**
* 当前登录账号是否属于通宇组织
*/
public static boolean isTongyu(LoginUser loginUser) {
if (loginUser == null || loginUser.getUserPo() == null) {
return false;
}
if (TONGYU_ORGANIZATION_ID.equals(loginUser.getUserPo().getOrganizationId())) {
return true;
}
return StringUtils.isNotBlank(loginUser.getUserPo().getOrganizationName())
&& loginUser.getUserPo().getOrganizationName().contains(TONGYU_KEYWORD);
}
/**
* 按组织ID判断是否通宇单据维度兜底用
*/
public static boolean isTongyuOrganizationId(Long organizationId) {
return TONGYU_ORGANIZATION_ID.equals(organizationId);
}
}
@@ -396,6 +396,63 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
group by a.MATERIAL_INVENTORY_ID order by sort_order, a.update_time desc
</select>
<!-- ============ 出库单明细可分配库存(库存分配弹窗专用) ============
列复用通用片段;条件独立成段,不改动 selectMaterialInventoryPo1,库存查询页零影响。
与 /list 的三点差异:
1) 多值 token OR-LIKE(出库明细的箱号/卡板、Sheet Ref NO's 可能是多值拼接串,整串 LIKE 匹配不到行)
2) 只按出库单货主+仓库过滤,不走 customerName 换算、不叠加 b.shipper_id、不强制用户组织
3) 可分配数量(allocation_quantity=可用数量)>0 才返回,比排除 inventory_quantity=0 更准 -->
<select id="queryAssignableList" parameterType="com.mhd.wms.domain.materialInventory.repository.todo.MaterialInventoryDO"
resultMap="MaterialInventoryResult">
select
<include refid="selectMaterialInventoryPo"/>
<include refid="com.mhd.wms.domain.materialBaseInfo.repository.mapper.MaterialBaseInfoMapper.JoinMaterialBaseInfoPo"/>
from material_inventory a
left join material_base_info b on a.material_base_info_id = b.material_base_info_id
<where>
a.del_flag = 1
and IFNULL(a.allocation_quantity, 0) &gt; 0
<if test="shipperId != null">
and a.shipper_id = #{shipperId}
</if>
<if test="warehouseId != null">
and a.warehouse_id = #{warehouseId}
</if>
<if test="materialBaseInfoId != null">
and a.material_base_info_id = #{materialBaseInfoId}
</if>
<if test="materialCode != null and materialCode != ''">
and b.material_code = #{materialCode}
</if>
<!-- 有箱号/卡板则同时匹配:任一 token 命中即保留(LIKE 兼容库存列本身也是多值串的情况) -->
<if test="boxPalletNoList != null and boxPalletNoList.size() > 0">
and (
<foreach collection="boxPalletNoList" item="token" separator=" or ">
a.BOX_PALLET_NO like concat('%', #{token}, '%')
</foreach>
)
</if>
<!-- 有 Sheet Ref NO's 则同时匹配 -->
<if test="sheetRefNoList != null and sheetRefNoList.size() > 0">
and (
<foreach collection="sheetRefNoList" item="token" separator=" or ">
a.SHEET_REF_NO like concat('%', #{token}, '%')
</foreach>
)
</if>
<!-- Batch Ref NO's:默认不启用(需求只要求 物料+箱号卡板+SheetRef),需要时由服务层显式赋值 -->
<if test="batchRefNoList != null and batchRefNoList.size() > 0">
and (
<foreach collection="batchRefNoList" item="token" separator=" or ">
a.BATCH_REF_NO like concat('%', #{token}, '%')
</foreach>
)
</if>
</where>
group by a.MATERIAL_INVENTORY_ID
order by sort_order, a.update_time desc
</select>
<select id="queryListByWlKw" parameterType="com.mhd.wms.domain.materialInventory.repository.todo.MaterialInventoryDO" resultMap="MaterialInventoryResult">
select
<include refid="selectMaterialInventoryPo"/>