Merge branch 'dev' into feature/dev-0729

# Conflicts:
#	mhd_bms/src/main/resources/bootstrap.yml
This commit is contained in:
王奎兴
2026-08-08 11:39:21 +08:00
52 changed files with 2552 additions and 963 deletions
@@ -25,6 +25,7 @@ import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;
@@ -127,6 +128,7 @@ public class StatementStatisticsService {
}
}
List<ImmediateInventoryPO> immediateInventoryPOS = materialInventoryDomainService.queryImmediateInventoryList(immediateInventoryDO);
// 性能优化:批量获取批次属性,避免N+1查询问题
// 1. 收集所有唯一的materialBaseInfoId
Set<Long> materialBaseInfoIdSet = immediateInventoryPOS.stream()
@@ -161,6 +163,19 @@ public class StatementStatisticsService {
return immediateInventoryPOS;
}
/**
* 获取库存数量合计
* @param immediateInventoryDO 查询参数
* @return 库存数量合计
*/
public BigDecimal sumImmediateInventoryQuantity(ImmediateInventoryDO immediateInventoryDO) {
BigDecimal totalInventoryQuantity = materialInventoryDomainService.sumImmediateInventoryQuantity(immediateInventoryDO);
if (totalInventoryQuantity == null) {
totalInventoryQuantity = BigDecimal.ZERO;
}
return totalInventoryQuantity;
}
/**
* 为物料库存设置更多属性(从库存表中获取值)
* @param materialInventoryPOList 物料库存列表
@@ -2222,24 +2222,31 @@ public class StockReceiptOrderApplicationService {
}
/**
* PDA 抄码收货不采集毛重、体积、面积:在装配前将对应请求字段置 0,避免 getInfo 带回的累计展示值被当作本次增量。
* PDA 抄码收货不采集毛重、体积、面积:在装配前将对应请求字段置 null
* 利用 MyBatis-Plus NOT_NULL 策略跳过这些字段,避免覆盖已有累计数据。
* @param lines 收货明细列表
*/
private static void normalizePdaCopyReceiptGrossVolumeAreaToZero(List<ReceiptMaterialDetailDO> lines) {
// 没有明细时,直接返回
if (CollectionUtils.isEmpty(lines)) {
return;
}
// 有明细时,遍历
for (ReceiptMaterialDetailDO line : lines) {
// 跳过 line 为 null
if (line == null) {
continue;
}
// 在装配之前将字段置为 null
if (isPdaCopyReceiptLine(line)) {
line.setReceiptGrossWeight(BigDecimal.ZERO);
line.setTotalGrossWeight(BigDecimal.ZERO);
line.setReceiptVolume(BigDecimal.ZERO);
line.setTotalVolume(BigDecimal.ZERO);
line.setReceiptArea(BigDecimal.ZERO);
line.setTotalArea(BigDecimal.ZERO);
line.setReceiptGrossWeight(null);
line.setTotalGrossWeight(null);
line.setReceiptVolume(null);
line.setTotalVolume(null);
line.setReceiptArea(null);
line.setTotalArea(null);
}
// 递归,确保每一个子行都会独立通过 isPdaCopyReceiptLine 判断是否需要清字段
normalizePdaCopyReceiptGrossVolumeAreaToZero(line.getChildren());
}
}
@@ -1,15 +1,21 @@
package com.mhd.wms.domain.inventoryAdjustmentRecord.service;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.aliyun.oss.ServiceException;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.mhd.common.core.constant.SnowFlakeConstants;
import com.mhd.common.core.domain.po.UserPo;
import com.mhd.common.core.domain.po.WarehousePO;
import com.mhd.common.core.utils.OrderSequence;
import com.mhd.common.core.utils.uuid.IdGenerator;
import com.mhd.common.core.utils.StringUtils;
import com.mhd.common.core.web.domain.AjaxResult;
import com.mhd.common.core.web.domain.BaseVOEntity;
import com.mhd.common.security.utils.SecurityUtils;
import com.mhd.system.api.OmsServiceFeign;
import com.mhd.system.api.SystemServiceFeign;
import com.mhd.system.api.domain.*;
import com.mhd.system.api.model.LoginUser;
import com.mhd.wms.domain.inventoryAdjustmentRecord.repository.facade.IInventoryAdjustmentRecordService;
@@ -56,6 +62,8 @@ public class InventoryAdjustmentRecordDomainService {
private IdGenerator idGenerator;
@Autowired
private OmsServiceFeign omsServiceFeign;
@Autowired
private SystemServiceFeign systemServiceFeign;
@@ -106,6 +114,15 @@ public class InventoryAdjustmentRecordDomainService {
*/
@Transactional
public Boolean inventoryAdjust(InventoryAdjustmentRecordDO inventoryAdjustmentRecordDO) {
// 根据仓库ID获取仓库信息,用于后续库存调整的仓库判断
AjaxResult warehouseInfoByWarehouseId = systemServiceFeign.getWarehouseInfoByWarehouseId(inventoryAdjustmentRecordDO.getWarehouseId());
if (warehouseInfoByWarehouseId == null) {
throw new ServiceException("仓库不存在");
} else if (!warehouseInfoByWarehouseId.get("code").equals(200)) {
throw new ServiceException("网络错误请重试 --- " + warehouseInfoByWarehouseId.get("msg"));
}
// 获取仓库信息
WarehousePO warehousePO = JSON.parseObject(JSONObject.toJSONString(warehouseInfoByWarehouseId.get("data")), WarehousePO.class);
InventoryAdjustmentRecordDO inventoryAdjustmentRecord = new InventoryAdjustmentRecordDO();
inventoryAdjustmentRecord.setAdjustAction("库存调整");
LoginUser loginUser = SecurityUtils.getLoginUser();
@@ -115,6 +132,17 @@ public class InventoryAdjustmentRecordDomainService {
inventoryAdjustmentRecord.setCreateBy(loginUser.getUserid());
inventoryAdjustmentRecord.setCreateByName(loginUser.getUsername());
inventoryAdjustmentRecord.setCreateTime(new Date());
if (inventoryAdjustmentRecordDO.getAdjustType() == null) {
throw new ServiceException("调整类型不能为空");
}
if (inventoryAdjustmentRecordDO.getAdjustType() == 1
&& inventoryAdjustmentRecordDO.getMaterialInventoryId() == null) {
throw new ServiceException("请选择要调整的库存");
}
if (inventoryAdjustmentRecordDO.getAdjustQuantity() == null
|| inventoryAdjustmentRecordDO.getAdjustQuantity().compareTo(BigDecimal.ZERO) == 0) {
throw new ServiceException("调整数量不能为空且不能为0");
}
MaterialInventory materialInventory = null;
//根据调整类型判断,数量调整只调整当前库存记录数量,状态调整减少当前原物料状态库存数量和可用数量,增加到现状态库存数量和可用数量
if (inventoryAdjustmentRecordDO.getAdjustType() != null && inventoryAdjustmentRecordDO.getAdjustType() == 1) {
@@ -180,8 +208,8 @@ public class InventoryAdjustmentRecordDomainService {
.eq(MaterialInventory::getStorageSectionId,inventoryAdjustmentRecordDO.getStorageSectionId())
.eq(MaterialInventory::getStorageLocationId,inventoryAdjustmentRecordDO.getStorageLocationId())
.eq(MaterialInventory::getMaterialStatusCode,inventoryAdjustmentRecordDO.getAdjustBeforeStatusCode())
.eq(MaterialInventory::getBatchNumber,inventoryAdjustmentRecordDO.getBatchNumber())
.eq(MaterialInventory::getContainerId,inventoryAdjustmentRecordDO.getContainerId())
.eq(StringUtils.isNotBlank(inventoryAdjustmentRecordDO.getBatchNumber()),MaterialInventory::getBatchNumber,inventoryAdjustmentRecordDO.getBatchNumber())
.eq(inventoryAdjustmentRecordDO.getContainerId() != null, MaterialInventory::getContainerId, inventoryAdjustmentRecordDO.getContainerId())
.eq(BaseVOEntity::getDelFlag, 1));
if (ObjectUtil.isNotNull(materialInventory)) {
BeanUtils.copyProperties(materialInventory, inventoryAdjustmentRecord);
@@ -218,6 +246,8 @@ public class InventoryAdjustmentRecordDomainService {
inventoryAdjustmentRecord.setAdjustedGrossWeight(materialInventory.getGrossWeight());
inventoryAdjustmentRecord.setAdjustedVolume(materialInventory.getVolume());
inventoryAdjustmentRecord.setAdjustedArea(materialInventory.getArea());
// ===== 新增:原状态库存扣减后立即落库,避免依赖末尾统一更新 =====
materialInventoryService.updateById(materialInventory);
} else {
throw new ServiceException("根据原物料状态查询不到物料库存信息!");
}
@@ -228,8 +258,8 @@ public class InventoryAdjustmentRecordDomainService {
.eq(MaterialInventory::getStorageSectionId,inventoryAdjustmentRecordDO.getStorageSectionId())
.eq(MaterialInventory::getStorageLocationId,inventoryAdjustmentRecordDO.getStorageLocationId())
.eq(MaterialInventory::getMaterialStatusCode,inventoryAdjustmentRecordDO.getAdjustAfterStatusCode())
.eq(MaterialInventory::getBatchNumber,inventoryAdjustmentRecordDO.getBatchNumber())
.eq(MaterialInventory::getContainerId,inventoryAdjustmentRecordDO.getContainerId())
.eq(StringUtils.isNotBlank(inventoryAdjustmentRecordDO.getBatchNumber()),MaterialInventory::getBatchNumber,inventoryAdjustmentRecordDO.getBatchNumber())
.eq(inventoryAdjustmentRecordDO.getContainerId() != null,MaterialInventory::getContainerId,inventoryAdjustmentRecordDO.getContainerId())
.eq(BaseVOEntity::getDelFlag, 1));
if (ObjectUtil.isNotNull(materialInventory1)) {
materialInventory1.setInventoryQuantity(materialInventory1.getInventoryQuantity().add(inventoryAdjustmentRecordDO.getAdjustQuantity()));
@@ -245,21 +275,49 @@ public class InventoryAdjustmentRecordDomainService {
inventoryAdjustmentRecord.setAdjustAfterStatusCode(inventoryAdjustmentRecordDO.getAdjustAfterStatusCode());
inventoryAdjustmentRecord.setAdjustAfterStatusName(inventoryAdjustmentRecordDO.getAdjustAfterStatusName());
}
// ===== 新增:adjustType 合法性兜底,避免异常类型导致 materialInventory 为 null 静默走完流程 =====
if (ObjectUtil.isNull(materialInventory)) {
throw new ServiceException("不支持的调整类型:" + inventoryAdjustmentRecordDO.getAdjustType());
}
//生成库存调整追溯记录
if (ObjectUtil.isNotNull(materialInventory)){
genInventoryStandingDetail(materialInventory, inventoryAdjustmentRecordDO.getAdjustQuantity());
}
materialInventoryService.updateById(materialInventory);
// ===== 修复:末尾更新加 null 保护 =====
if (ObjectUtil.isNotNull(materialInventory)) {
materialInventoryService.updateById(materialInventory);
}
Boolean insert = inventoryAdjustmentRecordService.insert(inventoryAdjustmentRecord);
//推送oms库存调整记录
pushOms(materialInventory, inventoryAdjustmentRecordDO);
try{
// 当仓库启用 oms 才进行推送
if (warehousePO.getIsEnable() == 1) {
Boolean pushSuccess = pushOms(materialInventory, inventoryAdjustmentRecordDO);
if (!pushSuccess) {
throw new ServiceException("库存调整推送OMS失败,请稍后重试");
}
}
}catch (Exception e){
log.error("推送OMS库存调整记录异常,materialBaseInfoId={}, adjustDirection={}",
inventoryAdjustmentRecordDO.getMaterialBaseInfoId(),
inventoryAdjustmentRecordDO.getAdjustDirection());
throw new ServiceException("库存调整推送OMS失败,请稍后重试");
}
System.out.println("库存调整时间结束 ----" + System.currentTimeMillis());
return insert;
}
private void pushOms(MaterialInventory materialInventory,InventoryAdjustmentRecordDO inventoryAdjustmentRecordDO) {
/**
* 推送库存调整信息至OMS系统
* <p>
* 根据调整方向(1=增加库存,2=减少库存)分别构造入库调整单或出库调整单,
* 并通过Feign接口推送至OMS系统,同时推送对应的物料明细信息。
*
* @param materialInventory 调整涉及的物料库存信息,包含仓库、库区、库位、货主等上下文数据
* @param inventoryAdjustmentRecordDO 库存调整记录,包含调整方向、调整数量、物料编码等数据
*/
private Boolean pushOms(MaterialInventory materialInventory,InventoryAdjustmentRecordDO inventoryAdjustmentRecordDO) {
LoginUser loginUser = SecurityUtils.getLoginUser();
UserPo userPo = loginUser.getUserPo();
MaterialBaseInfo materialBaseInfo = materialBaseInfoService.getById(materialInventory.getMaterialBaseInfoId());
@@ -327,8 +385,16 @@ public class InventoryAdjustmentRecordDomainService {
inMaterialDetail.setStorageLocationCode(materialInventory.getStorageLocationCode());
inMaterialDetail.setStorageLocationName(materialInventory.getStorageLocationName());
inMaterialDetail.setSingleGrossWeight(materialBaseInfo.getWeightLimit());
omsServiceFeign.pushInOrder(stockInOrder);
omsServiceFeign.pushInOrderDetail(inMaterialDetail);
AjaxResult inOrderResult = omsServiceFeign.pushInOrder(stockInOrder);
AjaxResult inOrderDetailResult = omsServiceFeign.pushInOrderDetail(inMaterialDetail);
if (inOrderResult == null || inOrderDetailResult == null
|| !"200".equals(String.valueOf(inOrderResult.get("code")))
|| !"200".equals(String.valueOf(inOrderDetailResult.get("code")))
) {
log.error("推送OMS入库调整单失败,pushInOrder={}, pushInOrderDetail={}",
inOrderResult, inOrderDetailResult);
return false;
}
} else {
StockOutOrderTZPD stockOutOrder = new StockOutOrderTZPD();
stockOutOrder.setOrganizationId(loginUser.getUserPo().getOrganizationId());
@@ -391,9 +457,18 @@ public class InventoryAdjustmentRecordDomainService {
outMaterialDetail.setStorageLocationCode(materialInventory.getStorageLocationCode());
outMaterialDetail.setStorageLocationName(materialInventory.getStorageLocationName());
outMaterialDetail.setSingleGrossWeight(materialBaseInfo.getWeightLimit());
omsServiceFeign.pushOutOrder(stockOutOrder);
omsServiceFeign.pushOutOrderDetail(outMaterialDetail);
AjaxResult inOrderResult = omsServiceFeign.pushOutOrder(stockOutOrder);
AjaxResult inOrderDetailResult = omsServiceFeign.pushOutOrderDetail(outMaterialDetail);
if (inOrderResult == null || inOrderDetailResult == null
|| !"200".equals(String.valueOf(inOrderResult.get("code")))
|| !"200".equals(String.valueOf(inOrderDetailResult.get("code")))
) {
log.error("推送OMS入库调整单失败,pushInOrder={}, pushInOrderDetail={}",
inOrderResult, inOrderDetailResult);
return false;
}
}
return true;
}
/**
@@ -71,6 +71,12 @@ public interface IMaterialInventoryService extends IService<MaterialInventory>
*/
public List<ImmediateInventoryPO> queryImmediateInventoryList(ImmediateInventoryDO immediateInventoryDO);
/**
* 查询即时库存合计数量
*/
public BigDecimal sumImmediateInventoryQuantity(ImmediateInventoryDO immediateInventoryDO);
/**
* @description 增加指定库存
* @author ZhouGY
@@ -38,6 +38,8 @@ public interface MaterialInventoryMapper extends BaseMapper<MaterialInventory>
public List<MaterialInventoryPO> queryListByHz(MaterialInventoryDO materialInventoryDO);
//查物料库存列表-货主+物料同一物料在不同货主下各一行
public List<MaterialInventoryPO> queryListByHzWl(MaterialInventoryDO materialInventoryDO);
//查物料库存列表-按货主+物料+仓库库存查询第三个页签update_time 取合并后最大值
public List<MaterialInventoryPO> queryListByHzWlUnit(MaterialInventoryDO materialInventoryDO);
/**
* @description 批量增加库存
@@ -91,6 +93,12 @@ public interface MaterialInventoryMapper extends BaseMapper<MaterialInventory>
*/
public List<ImmediateInventoryPO> queryImmediateInventoryList(ImmediateInventoryDO immediateInventoryDO);
/**
* 查询即时库存合计数量与列表相同筛选条件返回库存数量总和
*/
public BigDecimal sumImmediateInventoryQuantity(ImmediateInventoryDO immediateInventoryDO);
@Select("SELECT SUM(inventory_quantity) 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 b.shipper_id = #{shipperId} AND b.material_base_info_id = #{materialBaseInfoId}")
public BigDecimal sumInventoryQuantityByShipperAndMaterialCode(@Param("shipperId") Long shipperId, @Param("materialBaseInfoId") Long materialBaseInfoId);
@@ -77,17 +77,19 @@ public class MaterialInventoryImpl extends ServiceImpl<MaterialInventoryMapper,
String queryRule = materialInventoryDO.getQueryRule();
if ("hz".equals(queryRule)) {
return materialInventoryMapper.queryListByHz(materialInventoryDO);
} else if ("hzwl".equals(queryRule)) {
} else if ("hzwl".equals(queryRule)) { // 货主查询
return materialInventoryMapper.queryListByHzWl(materialInventoryDO);
} else if ("wl".equals(queryRule)) {
} else if ("wl".equals(queryRule)) { // 物料查询
return materialInventoryMapper.queryListByWl(materialInventoryDO);
} else if ("kw".equals(queryRule)) {
return materialInventoryMapper.queryListByKw(materialInventoryDO);
} else if ("wlkw".equals(queryRule)) {
} else if ("wlkw".equals(queryRule)) { // 物料/库位查询
return materialInventoryMapper.queryListByWlKw(materialInventoryDO);
} else if ("wlExpiry".equals(queryRule)) {
} else if ("wlExpiry".equals(queryRule)) { // 物料/过期日期查询
return materialInventoryMapper.queryListByWlExpiry(materialInventoryDO);
} else if ("all".equals(queryRule)) {
} else if("hzwlunit".equals(queryRule)){ // 货主/物料查询
return materialInventoryMapper.queryListByHzWlUnit(materialInventoryDO);
}else if ("all".equals(queryRule)) { // 全部查询
return materialInventoryMapper.queryList(materialInventoryDO);
} else {
//不传返回全部
@@ -464,11 +466,29 @@ public class MaterialInventoryImpl extends ServiceImpl<MaterialInventoryMapper,
}
}
/**
* 分页查询即时库存列表
*
* @param immediateInventoryDO 即时库存查询条件含组织权限货主物料仓库数量区间等筛选条件
* @return 即时库存列表
*/
@Override
public List<ImmediateInventoryPO> queryImmediateInventoryList(ImmediateInventoryDO immediateInventoryDO) {
return materialInventoryMapper.queryImmediateInventoryList(immediateInventoryDO);
}
/**
* 查询即时库存合计数量
* <p>与列表查询使用相同筛选条件但不分页统计筛选条件下所有库存数量之和</p>
*
* @param immediateInventoryDO 即时库存查询条件与列表查询保持一致保证合计口径一致
* @return 库存数量合计值无数据时为 0
*/
@Override
public BigDecimal sumImmediateInventoryQuantity(ImmediateInventoryDO immediateInventoryDO) {
return materialInventoryMapper.sumImmediateInventoryQuantity(immediateInventoryDO);
}
/**
* @description 增加指定库存
* @author ZhouGY
@@ -103,6 +103,20 @@ public class MaterialInventoryDomainService {
return materialInventoryService.queryImmediateInventoryList(immediateInventoryDO);
}
/**
* 查询即时库存合计数量
*/
public BigDecimal sumImmediateInventoryQuantity(ImmediateInventoryDO immediateInventoryDO) {
return materialInventoryService.sumImmediateInventoryQuantity(immediateInventoryDO);
}
/**
* 根据查询条件获取物料库存信息
* <p>按货主组织物料仓库库位等条件查询返回汇总后的库存信息含库存数量合计</p>
*
* @param materialInventoryDO 物料库存查询条件含货主顶级组织物料基础信息仓库库位等
* @return 匹配条件的物料库存信息无匹配数据时返回 null
*/
public MaterialInventoryPO selectOneByWhere(MaterialInventoryDO materialInventoryDO) {
return materialInventoryService.selectOneByWhere(materialInventoryDO);
}
@@ -459,6 +459,7 @@ public class ReceiptMaterialDetailImpl extends ServiceImpl<ReceiptMaterialDetail
ReceiptMaterialDetail receiptMaterialDetailChild = new ReceiptMaterialDetail();
BeanUtils.copyProperties(receiptMaterialDetailDOChild, receiptMaterialDetailChild);
alignPersistedReceiptQuantityToCumulative(receiptMaterialDetailDOChild, receiptMaterialDetailChild);
normalizeZeroMetricsToNull(receiptMaterialDetailChild);
receiptMaterialDetailChild.setCreateBy(loginUser.getUserid());
receiptMaterialDetailChild.setCreateByName(loginUser.getUsername());
receiptMaterialDetailChild.setCreateTime(new Date());
@@ -474,9 +475,12 @@ public class ReceiptMaterialDetailImpl extends ServiceImpl<ReceiptMaterialDetail
}
}
}
ReceiptMaterialDetail receiptMaterialDetail = new ReceiptMaterialDetail();
BeanUtils.copyProperties(receiptMaterialDetailDO, receiptMaterialDetail);
alignPersistedReceiptQuantityToCumulative(receiptMaterialDetailDO, receiptMaterialDetail);
// total* 字段为 0 或空字符串时置为 null避免 MyBatis-Plus NOT_NULL 策略下覆盖已有数据
normalizeZeroMetricsToNull(receiptMaterialDetail);
receiptMaterialDetail.setUpdateBy(loginUser.getUserid());
receiptMaterialDetail.setUpdateByName(loginUser.getUsername());
receiptMaterialDetail.setUpdateTime(new Date());
@@ -488,23 +492,25 @@ public class ReceiptMaterialDetailImpl extends ServiceImpl<ReceiptMaterialDetail
}
//保存物料明细信息
saveOrUpdateBatch(receiptMaterialDetailList);
//批量新增/更新物料更多属性保留已有值仅更新有值的属性不再先删后插
mergeMaterialMoreDetail(materialMoreDetailList, stockReceiptOrderDO, receiptMaterialDetailDOList);
//批量新增/更新物料更多属性先删除该收货单下所有明细的旧批次属性再插入新值避免重复插入导致更新失效
if (!CollectionUtils.isEmpty(materialMoreDetailList)){
String receiptOrderNumber = stockReceiptOrderDO.getReceiptOrderNumber();
if (StringUtils.isBlank(receiptOrderNumber) && !CollectionUtils.isEmpty(receiptMaterialDetailDOList)) {
receiptOrderNumber = receiptMaterialDetailDOList.get(0).getReceiptOrderNumber();
}
if (StringUtils.isNotBlank(receiptOrderNumber)) {
java.util.Set<Long> uniqueIds = collectReceiptDetailUniqueIds(receiptMaterialDetailDOList);
if (!uniqueIds.isEmpty()) {
IMaterialMoreDetailService.remove(new QueryWrapper<MaterialMoreDetail>()
.eq("order_number", receiptOrderNumber)
.in("material_detail_unique_id", uniqueIds)
.eq("del_flag", 1));
}
}
IMaterialMoreDetailService.saveBatch(materialMoreDetailList);
}
// if (!CollectionUtils.isEmpty(materialMoreDetailList)){
// String receiptOrderNumber = stockReceiptOrderDO.getReceiptOrderNumber();
// if (StringUtils.isBlank(receiptOrderNumber) && !CollectionUtils.isEmpty(receiptMaterialDetailDOList)) {
// receiptOrderNumber = receiptMaterialDetailDOList.get(0).getReceiptOrderNumber();
// }
// if (StringUtils.isNotBlank(receiptOrderNumber)) {
// java.util.Set<Long> uniqueIds = collectReceiptDetailUniqueIds(receiptMaterialDetailDOList);
// if (!uniqueIds.isEmpty()) {
// IMaterialMoreDetailService.remove(new QueryWrapper<MaterialMoreDetail>()
// .eq("order_number", receiptOrderNumber)
// .in("material_detail_unique_id", uniqueIds)
// .eq("del_flag", 1));
// }
// }
// IMaterialMoreDetailService.saveBatch(materialMoreDetailList);
// }
//批量新增序列号
if (!CollectionUtils.isEmpty(materialDetailSerialNumberList)){
inMaterialDetailSerialNumberService.saveBatch(materialDetailSerialNumberList);
@@ -513,6 +519,144 @@ public class ReceiptMaterialDetailImpl extends ServiceImpl<ReceiptMaterialDetail
updateInMaterialDetailFromAttributeOption(receiptMaterialDetailDOList);
}
/**
* 批量合并物料更多属性有值则更新无值跳过保留旧值不存在则新增
* 替代原先 DELETE 全部再 INSERT的策略避免未填写字段丢失已有数据
* @param materialMoreDetailList 本次收货提交的批次属性列表
* @param stockReceiptOrderDO 收货单信息用于获取收货单号
* @param receiptMaterialDetailDOList 收货明细列表用于提取 uniqueId 集合
*/
private void mergeMaterialMoreDetail(List<MaterialMoreDetail> materialMoreDetailList,
StockReceiptOrderDO stockReceiptOrderDO,
List<ReceiptMaterialDetailDO> receiptMaterialDetailDOList) {
// 无批次属性则直接返回
if (CollectionUtils.isEmpty(materialMoreDetailList)) {
return;
}
// 无收货单号无法做增量更新退回全量插入
String receiptOrderNumber = stockReceiptOrderDO.getReceiptOrderNumber();
if (StringUtils.isBlank(receiptOrderNumber) && !CollectionUtils.isEmpty(receiptMaterialDetailDOList)) {
receiptOrderNumber = receiptMaterialDetailDOList.get(0).getReceiptOrderNumber();
}
// 无收货单号无法做增量更新退回全量插入
if (StringUtils.isBlank(receiptOrderNumber)) {
IMaterialMoreDetailService.saveBatch(materialMoreDetailList);
return;
}
// 无明细唯一ID无法做增量更新退回全量插入
java.util.Set<Long> uniqueIds = collectReceiptDetailUniqueIds(receiptMaterialDetailDOList);
if (uniqueIds.isEmpty()) {
IMaterialMoreDetailService.saveBatch(materialMoreDetailList);
return;
}
// 查询已存在的批次属性记录
List<MaterialMoreDetail> existingList = IMaterialMoreDetailService.list(
new QueryWrapper<MaterialMoreDetail>()
.eq("order_number", receiptOrderNumber) // 收货单号
.in("material_detail_unique_id", uniqueIds) // 明细唯一ID
.eq("del_flag", 1)); // 删除标志
// materialDetailUniqueId + batchDetailId 构建索引
Map<String, MaterialMoreDetail> existingMap = new HashMap<>();
for (MaterialMoreDetail existing : existingList) {
String key = buildMaterialMoreDetailKey(existing.getMaterialDetailUniqueId(), existing.getBatchDetailId());
existingMap.put(key, existing);
}
// 分离需要更新的 以及 需要新增的跳过空值保留旧数据
List<MaterialMoreDetail> toUpdate = new ArrayList<>();
List<MaterialMoreDetail> toInsert = new ArrayList<>();
for (MaterialMoreDetail incoming : materialMoreDetailList) {
// attributeValue 为空/空白时跳过不覆盖已有数据
if (StringUtils.isBlank(incoming.getAttributeValue())) {
continue;
}
// materialDetailUniqueId + batchDetailId 构建索引
String key = buildMaterialMoreDetailKey(incoming.getMaterialDetailUniqueId(), incoming.getBatchDetailId());
// 已存在的批次属性记录
MaterialMoreDetail existing = existingMap.get(key);
// 存在则更新 不存在则新增
if (existing != null) {
// 设置主键走 update保留已有记录的 id
incoming.setMaterialMoreDetailId(existing.getMaterialMoreDetailId());
// 更新现有记录
toUpdate.add(incoming);
} else {
// 插入新的记录
toInsert.add(incoming);
}
}
// 判断需更新的记录是否存在存在则更新
if (!toUpdate.isEmpty()) {
IMaterialMoreDetailService.updateBatchById(toUpdate);
}
// 判断是否存在需新增的记录存在则批量插入
if (!toInsert.isEmpty()) {
IMaterialMoreDetailService.saveBatch(toInsert);
}
}
/**
* 构建批次属性索引
* @param materialDetailUniqueId 明细唯一ID
* @param batchDetailId 批次属性ID
* @return 批次属性索引
*/
private static String buildMaterialMoreDetailKey(Long materialDetailUniqueId, Long batchDetailId) {
return (materialDetailUniqueId != null ? materialDetailUniqueId : "null") + "_"
+ (batchDetailId != null ? batchDetailId : "null");
}
/**
* total* 指标字段中值为 0 的置为 null
* MyBatis-Plus 默认 NOT_NULL 策略下null 不参与 SET 子句已有数据得以保留
* 注意仅对未填写场景生效用户确实需要填 0 的极端场景不受影响因前端通常传 null 表示未填
* @param receiptMaterialDetail 收货明细
* 需保证 total* 字段已赋值
* 需保证 alreadyReceipt* 字段已赋值
* 静态方法修改 receiptMaterialDetail 参数
**/
private static void normalizeZeroMetricsToNull(ReceiptMaterialDetail receiptMaterialDetail) {
// entity null 时直接返回
if (receiptMaterialDetail == null) {
return;
}
// receiptMaterialDetail totalNetWeight 字段为 0 时置为 null
if (isZeroBigDecimal(receiptMaterialDetail.getTotalNetWeight())) {
receiptMaterialDetail.setTotalNetWeight(null);
}
// receiptMaterialDetail totalGrossWeight 字段为 0 时置为 null
if (isZeroBigDecimal(receiptMaterialDetail.getTotalGrossWeight())) {
receiptMaterialDetail.setTotalGrossWeight(null);
}
// receiptMaterialDetail totalVolume 字段为 0 时置为 null
if (isZeroBigDecimal(receiptMaterialDetail.getTotalVolume())) {
receiptMaterialDetail.setTotalVolume(null);
}
// receiptMaterialDetail totalArea 字段为 0 时置为 null
if (isZeroBigDecimal(receiptMaterialDetail.getTotalArea())) {
receiptMaterialDetail.setTotalArea(null);
}
// receiptMaterialDetail alreadyReceiptNetWeight 字段为 0 时置为 null
if (isZeroBigDecimal(receiptMaterialDetail.getAlreadyReceiptNetWeight())) {
receiptMaterialDetail.setAlreadyReceiptNetWeight(null);
}
// receiptMaterialDetail alreadyReceiptGrossWeight 字段为 0 时置为 null
if (isZeroBigDecimal(receiptMaterialDetail.getAlreadyReceiptGrossWeight())) {
receiptMaterialDetail.setAlreadyReceiptGrossWeight(null);
}
// receiptMaterialDetail alreadyReceiptVolume 字段为 0 时置为 null
if (isZeroBigDecimal(receiptMaterialDetail.getAlreadyReceiptVolume())) {
receiptMaterialDetail.setAlreadyReceiptVolume(null);
}
// receiptMaterialDetail alreadyReceiptArea 字段为 0 时置为 null
if (isZeroBigDecimal(receiptMaterialDetail.getAlreadyReceiptArea())) {
receiptMaterialDetail.setAlreadyReceiptArea(null);
}
}
private static boolean isZeroBigDecimal(BigDecimal val) {
return val != null && val.compareTo(BigDecimal.ZERO) == 0;
}
private void setMore(ReceiptMaterialDetailDO receiptMaterialDetailDO) {
List<MaterialMoreDetailDO> materialMoreDetailList = receiptMaterialDetailDO.getMaterialMoreDetailList();
if (!CollectionUtils.isEmpty(materialMoreDetailList)) {
@@ -2,6 +2,8 @@ package com.mhd.wms.domain.reviewOrder.repository.po;
import com.mhd.common.core.web.domain.BaseVOEntity;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
@@ -18,24 +20,28 @@ import java.util.List;
@ApiModel(value = "复核单主表", description = "复核单主表展示")
public class ReviewOrderPO extends BaseVOEntity {
@JsonSerialize(using = ToStringSerializer.class)
@ApiModelProperty("复核单主键")
private Long reviewOrderId;
@ApiModelProperty("复核单号")
private String reviewOrderNumber;
@JsonSerialize(using = ToStringSerializer.class)
@ApiModelProperty("出库单ID")
private Long outOrderId;
@ApiModelProperty("出库单号")
private String outOrderNumber;
@JsonSerialize(using = ToStringSerializer.class)
@ApiModelProperty("组织ID")
private Long organizationId;
@ApiModelProperty("组织名称")
private String organizationName;
@JsonSerialize(using = ToStringSerializer.class)
@ApiModelProperty("一级组织ID")
private Long topOrganizationId;
@@ -50,6 +56,7 @@ public class ReviewOrderPO extends BaseVOEntity {
@ApiModelProperty("复核下发时间")
private Date issuedTime;
@JsonSerialize(using = ToStringSerializer.class)
@ApiModelProperty("仓库ID")
private Long warehouseId;
@@ -59,6 +66,7 @@ public class ReviewOrderPO extends BaseVOEntity {
@ApiModelProperty("仓库名称")
private String warehouseName;
@JsonSerialize(using = ToStringSerializer.class)
@ApiModelProperty("客户ID")
private Long customerId;
@@ -68,6 +76,7 @@ public class ReviewOrderPO extends BaseVOEntity {
@ApiModelProperty("客户名称")
private String customerName;
@JsonSerialize(using = ToStringSerializer.class)
@ApiModelProperty("货主ID")
private Long shipperId;
@@ -42,6 +42,10 @@ public class ImmediateInventoryPO {
@Excel(name = "物料条形码")
private String barCode;
@ApiModelProperty("规格型号")
@Excel(name = "规格型号")
private String specificationModel;
@ApiModelProperty("库存数量")
@Excel(name = "库存数量")
private BigDecimal inventoryQuantity;
@@ -44,6 +44,10 @@ public class ImmediateInventoryDO extends BaseVOEntity {
@Excel(name = "物料条形码")
private String barCode;
@ApiModelProperty("规格型号")
@Excel(name = "规格型号")
private String specificationModel;
@ApiModelProperty("仓库id")
@Excel(name = "仓库id")
private Long warehouseId;
@@ -45,6 +45,10 @@ public class ImmediateInventoryDTO {
@Excel(name = "物料条形码")
private String barCode;
@ApiModelProperty("规格型号")
@Excel(name = "规格型号")
private String specificationModel;
@ApiModelProperty("仓库id")
@Excel(name = "仓库id")
private Long warehouseId;
@@ -23,6 +23,8 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
/**
@@ -48,13 +50,14 @@ public class StatementStatisticsApi {
*/
@ApiOperation("查询即时库存列表")
@GetMapping("/queryImmediateInventoryList")
public TableDataInfo queryImmediateInventoryList(ImmediateInventoryDTO immediateInventoryDTO)
public HashMap<String, Object> queryImmediateInventoryList(ImmediateInventoryDTO immediateInventoryDTO)
{
//转换实体
ImmediateInventoryDO immediateInventoryDO = immediateInventoryAssembler.toDO(immediateInventoryDTO);
startPage();
List<ImmediateInventoryPO> list = statementStatisticsService.queryImmediateInventoryList(immediateInventoryDO);
return getDataTable(list);
BigDecimal bigDecimal = statementStatisticsService.sumImmediateInventoryQuantity(immediateInventoryDO);
return getDataTableWarehouse(list,bigDecimal);
}
/**
* 分页查询入库日报表列表
@@ -129,4 +132,18 @@ public class StatementStatisticsApi {
rspData.setTotal(new PageInfo(list).getTotal());
return rspData;
}
/**
* 响应请求分页仓库数量 数据
*/
protected HashMap<String, Object> getDataTableWarehouse(List<?> list,BigDecimal bigDecimal)
{
HashMap<String, Object> stringObjectHashMap = new HashMap<>();
stringObjectHashMap.put("data",list);
stringObjectHashMap.put("total",new PageInfo(list).getTotal());
stringObjectHashMap.put("code",HttpStatus.SUCCESS);
stringObjectHashMap.put("msg","查询成功");
stringObjectHashMap.put("totalInventoryQuantity",bigDecimal);
return stringObjectHashMap;
}
}