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:
+96
-2
@@ -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,11 +132,19 @@ public class MaterialInventoryApplicationService {
|
||||
*/
|
||||
public List<MaterialInventoryPO> queryListWithBatchAttributes(MaterialInventoryDO materialInventoryDO) {
|
||||
List<MaterialInventoryPO> list = queryList(materialInventoryDO);
|
||||
|
||||
if (CollectionUtils.isEmpty(list)) {
|
||||
fillBatchAttributes(list);
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量回填批次属性(isDisplay=1):拉取批次配置并从库存表取值,避免N+1查询。
|
||||
* 原为 queryListWithBatchAttributes 内部逻辑,抽出供可分配库存查询复用。
|
||||
*/
|
||||
private void fillBatchAttributes(List<MaterialInventoryPO> list) {
|
||||
if (CollectionUtils.isEmpty(list)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 性能优化:批量获取批次属性,避免N+1查询问题
|
||||
// 1. 收集所有唯一的materialBaseInfoId
|
||||
Set<Long> materialBaseInfoIdSet = list.stream()
|
||||
@@ -157,10 +175,86 @@ public class MaterialInventoryApplicationService {
|
||||
|
||||
// 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's;batchRefNoList 默认不赋值(不参与匹配)
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 为物料库存设置更多属性(从库存表中获取值)
|
||||
* @param materialInventoryPOList 物料库存列表
|
||||
|
||||
+33
@@ -182,10 +182,12 @@ 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)) {
|
||||
throw new ServiceException("复核单号不能为空");
|
||||
@@ -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 展示已复核数量。
|
||||
|
||||
+27
-2
@@ -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()
|
||||
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;
|
||||
}
|
||||
|
||||
+8
@@ -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
|
||||
|
||||
+9
@@ -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;
|
||||
}
|
||||
+32
@@ -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(可选 batchRefNo、shipperId、warehouseId)查询,多值串后端自动拆分。
|
||||
* 两种模式均:仅返回可分配数量>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's、Batch 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) > 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"/>
|
||||
|
||||
Reference in New Issue
Block a user