Merge branch 'dev' into dev-bms-260826
# Conflicts: # mhd-api/mhd-api-system/src/main/java/com/mhd/system/api/BmsServiceFeign.java # mhd_oms/src/main/java/com/mhd/oms/domain/reservationStockInOrder/repository/facade/IReservationStockInOrderService.java # mhd_oms/src/main/java/com/mhd/oms/domain/reservationStockInOrder/repository/mapper/ReservationStockInOrderMapper.java # mhd_oms/src/main/resources/mapper/reservationStockInOrder/ReservationStockInOrderMapper.xml # mhd_wms/src/main/java/com/mhd/wms/domain/materialInventory/repository/po/MaterialInventoryPO.java # mhd_wms/src/main/java/com/mhd/wms/domain/materialInventory/repository/todo/MaterialInventoryDO.java # mhd_wms/src/main/java/com/mhd/wms/interfaces/dto/materialInventory/MaterialInventoryDTO.java # mhd_wms/src/main/resources/mapper/materialInventory/MaterialInventoryMapper.xml
This commit is contained in:
+76
@@ -0,0 +1,76 @@
|
||||
package com.mhd.wms.application.service.inboundRank;
|
||||
|
||||
import com.mhd.common.core.exception.ServiceException;
|
||||
import com.mhd.common.core.utils.StringUtils;
|
||||
import com.mhd.common.security.utils.SecurityUtils;
|
||||
import com.mhd.system.api.domain.cache.AssociationWarehouseCacheDO;
|
||||
import com.mhd.system.api.domain.cache.SystemServiceCacheUtil;
|
||||
import com.mhd.system.api.model.LoginUser;
|
||||
import com.mhd.wms.domain.inboundRank.repository.po.InboundMaterialRankPO;
|
||||
import com.mhd.wms.domain.inboundRank.repository.po.InboundRankTotalPO;
|
||||
import com.mhd.wms.domain.inboundRank.repository.todo.InboundRankDO;
|
||||
import com.mhd.wms.domain.inboundRank.service.InboundRankDomainService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 入库排名统计应用服务
|
||||
*
|
||||
* <p>负责登录用户组织隔离注入、日期区间校验,查询逻辑在 InboundRankDomainService → InboundRankMapper.xml</p>
|
||||
*
|
||||
* @author rcx
|
||||
* @date 2026-08-31
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class InboundRankApplicationService {
|
||||
|
||||
@Autowired
|
||||
private InboundRankDomainService inboundRankDomainService;
|
||||
|
||||
/**
|
||||
* 分页查询商品入库排名列表(仓单+货品汇总,按件数降序)
|
||||
*/
|
||||
public List<InboundMaterialRankPO> queryMaterialRankList(InboundRankDO inboundRankDO) {
|
||||
fillLoginContext(inboundRankDO);
|
||||
return inboundRankDomainService.queryMaterialRankList(inboundRankDO);
|
||||
}
|
||||
|
||||
/**
|
||||
* 商品入库排名合计(当前筛选条件全量,不分页)
|
||||
*/
|
||||
public InboundRankTotalPO queryMaterialRankTotal(InboundRankDO inboundRankDO) {
|
||||
return inboundRankDomainService.queryMaterialRankTotal(inboundRankDO);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出商品入库排名(不分页全量)
|
||||
*/
|
||||
public List<InboundMaterialRankPO> exportMaterialRank(InboundRankDO inboundRankDO) {
|
||||
fillLoginContext(inboundRankDO);
|
||||
return inboundRankDomainService.queryMaterialRankList(inboundRankDO);
|
||||
}
|
||||
|
||||
/**
|
||||
* 注入登录用户组织隔离与关联仓库,并校验入仓日期区间必填
|
||||
*/
|
||||
private void fillLoginContext(InboundRankDO inboundRankDO) {
|
||||
if (StringUtils.isEmpty(inboundRankDO.getWarehouseDateStart()) || StringUtils.isEmpty(inboundRankDO.getWarehouseDateEnd())) {
|
||||
throw new ServiceException("请选择统计日期区间");
|
||||
}
|
||||
LoginUser loginUser = SecurityUtils.getLoginUser();
|
||||
if (loginUser != null && loginUser.getUserPo() != null) {
|
||||
Long topOrganizationId = loginUser.getUserPo().getTopOrganizationId();
|
||||
if (topOrganizationId != null && topOrganizationId != 1) {
|
||||
inboundRankDO.setTopOrganizationId(topOrganizationId);
|
||||
}
|
||||
AssociationWarehouseCacheDO associationWarehouseCacheDO = SystemServiceCacheUtil.getAssociationWarehouseCache(loginUser.getUserid());
|
||||
if (associationWarehouseCacheDO != null && associationWarehouseCacheDO.getWarehouseId() != null) {
|
||||
inboundRankDO.setWarehouseId(associationWarehouseCacheDO.getWarehouseId());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+100
@@ -0,0 +1,100 @@
|
||||
package com.mhd.wms.application.service.outboundRank;
|
||||
|
||||
import com.mhd.common.core.utils.StringUtils;
|
||||
import com.mhd.common.core.exception.ServiceException;
|
||||
import com.mhd.common.security.utils.SecurityUtils;
|
||||
import com.mhd.system.api.domain.cache.AssociationWarehouseCacheDO;
|
||||
import com.mhd.system.api.domain.cache.SystemServiceCacheUtil;
|
||||
import com.mhd.system.api.model.LoginUser;
|
||||
import com.mhd.wms.domain.outboundRank.repository.po.OutboundDetailRankTotalPO;
|
||||
import com.mhd.wms.domain.outboundRank.repository.po.OutboundLineRankPO;
|
||||
import com.mhd.wms.domain.outboundRank.repository.po.OutboundMaterialRankPO;
|
||||
import com.mhd.wms.domain.outboundRank.repository.todo.OutboundRankDO;
|
||||
import com.mhd.wms.domain.outboundRank.service.OutboundRankDomainService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 出库排名统计应用服务
|
||||
*
|
||||
* <p>负责登录用户组织隔离注入、日期区间校验,查询逻辑在 OutboundRankDomainService → OutboundRankMapper.xml</p>
|
||||
*
|
||||
* @author rcx
|
||||
* @date 2026-08-31
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class OutboundRankApplicationService {
|
||||
|
||||
@Autowired
|
||||
private OutboundRankDomainService outboundRankDomainService;
|
||||
|
||||
/**
|
||||
* 分页查询商品出库排名列表(货品聚合)
|
||||
*/
|
||||
public List<OutboundMaterialRankPO> queryMaterialRankList(OutboundRankDO outboundRankDO) {
|
||||
fillLoginContext(outboundRankDO);
|
||||
return outboundRankDomainService.queryMaterialRankList(outboundRankDO);
|
||||
}
|
||||
|
||||
/**
|
||||
* 商品出库排名合计(当前筛选条件全量,不分页)
|
||||
*/
|
||||
public OutboundDetailRankTotalPO queryMaterialRankTotal(OutboundRankDO outboundRankDO) {
|
||||
return outboundRankDomainService.queryMaterialRankTotal(outboundRankDO);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出商品出库排名(不分页全量)
|
||||
*/
|
||||
public List<OutboundMaterialRankPO> exportMaterialRankList(OutboundRankDO outboundRankDO) {
|
||||
fillLoginContext(outboundRankDO);
|
||||
return outboundRankDomainService.queryMaterialRankList(outboundRankDO);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询线路出库排名列表(线路×货品聚合)
|
||||
*/
|
||||
public List<OutboundLineRankPO> queryLineRankList(OutboundRankDO outboundRankDO) {
|
||||
fillLoginContext(outboundRankDO);
|
||||
return outboundRankDomainService.queryLineRankList(outboundRankDO);
|
||||
}
|
||||
|
||||
/**
|
||||
* 线路出库排名合计(当前筛选条件全量,不分页)
|
||||
*/
|
||||
public OutboundDetailRankTotalPO queryLineRankTotal(OutboundRankDO outboundRankDO) {
|
||||
return outboundRankDomainService.queryLineRankTotal(outboundRankDO);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出线路出库排名(不分页全量)
|
||||
*/
|
||||
public List<OutboundLineRankPO> exportLineRankList(OutboundRankDO outboundRankDO) {
|
||||
fillLoginContext(outboundRankDO);
|
||||
return outboundRankDomainService.queryLineRankList(outboundRankDO);
|
||||
}
|
||||
|
||||
/**
|
||||
* 注入登录用户组织隔离与关联仓库,并校验日期区间必填
|
||||
*/
|
||||
private void fillLoginContext(OutboundRankDO outboundRankDO) {
|
||||
if (StringUtils.isEmpty(outboundRankDO.getCreateTimeStart()) || StringUtils.isEmpty(outboundRankDO.getCreateTimeEnd())) {
|
||||
throw new ServiceException("请选择统计日期区间");
|
||||
}
|
||||
LoginUser loginUser = SecurityUtils.getLoginUser();
|
||||
if (loginUser != null && loginUser.getUserPo() != null) {
|
||||
Long topOrganizationId = loginUser.getUserPo().getTopOrganizationId();
|
||||
if (topOrganizationId != null && topOrganizationId != 1) {
|
||||
outboundRankDO.setTopOrganizationId(topOrganizationId);
|
||||
}
|
||||
AssociationWarehouseCacheDO associationWarehouseCacheDO = SystemServiceCacheUtil.getAssociationWarehouseCache(loginUser.getUserid());
|
||||
if (associationWarehouseCacheDO != null && associationWarehouseCacheDO.getWarehouseId() != null) {
|
||||
outboundRankDO.setWarehouseId(associationWarehouseCacheDO.getWarehouseId());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
-16
@@ -1827,8 +1827,6 @@ public class StockInOrderApplicationService {
|
||||
.collect(Collectors.groupingBy(r -> StringUtils.isBlank(r.getConsignmentNo()) ? "__EMPTY_CONSIGNMENT__" : r.getConsignmentNo()));
|
||||
|
||||
List<StockInOrderDO> orderList = new ArrayList<>();
|
||||
// 收集"料号与规格型号/SKU码不一致"的错误行,最后统一抛出,避免用户修一行导一次
|
||||
List<String> consistencyErrors = new ArrayList<>();
|
||||
for (Map.Entry<String, List<StockInOrderImportRowDTO>> entry : groupMap.entrySet()) {
|
||||
List<StockInOrderImportRowDTO> groupRows = entry.getValue();
|
||||
StockInOrderImportRowDTO h = groupRows.get(0);
|
||||
@@ -2047,20 +2045,21 @@ public class StockInOrderApplicationService {
|
||||
log.error(errorMsg);
|
||||
throw new ServiceException(errorMsg);
|
||||
}
|
||||
// 校验料号与规格型号/SKU码的一致性:档案有值就必须一致(Excel留空视为不一致);档案为空则跳过该项
|
||||
// 校验料号与规格型号/SKU码一致性:按料号查到档案后逐项比对,任何一项不符直接报对应错误
|
||||
// 双方(trim后)必须完全一致:Excel留空而档案有值、或Excel填了值而档案为空,均视为不一致报错
|
||||
String excelSpec = StringUtils.trimToEmpty(r.getSpecificationModel());
|
||||
if (StringUtils.isNotBlank(materialBaseInfoPO.getSpecificationModel())
|
||||
&& !excelSpec.equals(materialBaseInfoPO.getSpecificationModel().trim())) {
|
||||
consistencyErrors.add(String.format("料号[%s](商品名称:%s)规格型号与物料档案不一致(Excel:%s / 档案:%s)",
|
||||
String dbSpec = StringUtils.trimToEmpty(materialBaseInfoPO.getSpecificationModel());
|
||||
if (!excelSpec.equals(dbSpec)) {
|
||||
throw new ServiceException(String.format("导入失败:料号[%s](商品名称:%s)规格型号与物料档案不一致(Excel:%s / 档案:%s)",
|
||||
r.getMaterialCode(), r.getMaterialName(),
|
||||
excelSpec.isEmpty() ? "空" : excelSpec, materialBaseInfoPO.getSpecificationModel().trim()));
|
||||
excelSpec.isEmpty() ? "空" : excelSpec, dbSpec.isEmpty() ? "空" : dbSpec));
|
||||
}
|
||||
String excelSku = StringUtils.trimToEmpty(r.getSkuCode());
|
||||
if (StringUtils.isNotBlank(materialBaseInfoPO.getBarCode())
|
||||
&& !excelSku.equals(materialBaseInfoPO.getBarCode().trim())) {
|
||||
consistencyErrors.add(String.format("料号[%s](商品名称:%s)SKU码与物料档案不一致(Excel:%s / 档案:%s)",
|
||||
String dbSku = StringUtils.trimToEmpty(materialBaseInfoPO.getBarCode());
|
||||
if (!excelSku.equals(dbSku)) {
|
||||
throw new ServiceException(String.format("导入失败:料号[%s](商品名称:%s)SKU码与物料档案不一致(Excel:%s / 档案:%s)",
|
||||
r.getMaterialCode(), r.getMaterialName(),
|
||||
excelSku.isEmpty() ? "空" : excelSku, materialBaseInfoPO.getBarCode().trim()));
|
||||
excelSku.isEmpty() ? "空" : excelSku, dbSku.isEmpty() ? "空" : dbSku));
|
||||
}
|
||||
|
||||
// 数量已在前面检查过,这里直接使用
|
||||
@@ -2203,11 +2202,6 @@ public class StockInOrderApplicationService {
|
||||
if (orderList.isEmpty()) {
|
||||
throw new ServiceException("导入失败:所有入库单的明细行都因数据不完整(数量为空或物料基础信息缺失)被跳过,请检查Excel数据");
|
||||
}
|
||||
// 存在料号与规格型号/SKU码不一致的明细行时,拒绝导入并一次性提示全部问题行
|
||||
if (!consistencyErrors.isEmpty()) {
|
||||
throw new ServiceException("导入失败,以下明细行的规格型号/SKU码与物料档案不一致,请修正后重新导入:\n"
|
||||
+ String.join("\n", consistencyErrors));
|
||||
}
|
||||
|
||||
return stockInOrderDomainService.batchInsert(orderList);
|
||||
|
||||
|
||||
+118
-6
@@ -1005,7 +1005,8 @@ public class StockOutOrderApplicationService {
|
||||
}
|
||||
BeanUtils.copyProperties(stockOutOrderDb, stockOutOrderD);
|
||||
List<OutMaterialDetail> outMaterialDetailList = outMaterialDetailService.list(new QueryWrapper<OutMaterialDetail>().lambda()
|
||||
.eq(OutMaterialDetail::getOutOrderNumber, stockOutOrderDb.getOutOrderNumber()));
|
||||
.eq(OutMaterialDetail::getOutOrderNumber, stockOutOrderDb.getOutOrderNumber())
|
||||
.eq(OutMaterialDetail::getDelFlag,1));
|
||||
List<OutMaterialDetailDO> materialDetailList = cn.hutool.core.bean.BeanUtil.copyToList(outMaterialDetailList, OutMaterialDetailDO.class);
|
||||
List<OutMaterialDetailDO> materialDetailList2 = new ArrayList<>();
|
||||
// 仅通宇账号启用与库存分配弹窗同口径的新匹配(物料+箱号/卡板+Sheet Ref 多值拆 token);
|
||||
@@ -1103,7 +1104,8 @@ public class StockOutOrderApplicationService {
|
||||
}
|
||||
BeanUtils.copyProperties(stockOutOrderDb, stockOutOrderD);
|
||||
List<OutMaterialDetail> outMaterialDetailList = outMaterialDetailService.list(new QueryWrapper<OutMaterialDetail>().lambda()
|
||||
.eq(OutMaterialDetail::getOutOrderNumber, stockOutOrderDb.getOutOrderNumber()));
|
||||
.eq(OutMaterialDetail::getOutOrderNumber, stockOutOrderDb.getOutOrderNumber())
|
||||
.eq(OutMaterialDetail::getDelFlag, 1));
|
||||
List<OutMaterialDetailDO> materialDetailList = cn.hutool.core.bean.BeanUtil.copyToList(outMaterialDetailList, OutMaterialDetailDO.class);
|
||||
List<OutMaterialDetailDO> materialDetailList2 = new ArrayList<>();
|
||||
for (OutMaterialDetailDO detail : materialDetailList) {
|
||||
@@ -1122,8 +1124,20 @@ public class StockOutOrderApplicationService {
|
||||
// throw new ServiceException("库存不存在:" + batchRefNo + " " + sheetRefNo + " " + boxPalletNo);
|
||||
// }
|
||||
Long materialInventoryId = detail.getMaterialInventoryId();
|
||||
String materialDesc = detail.getMaterialCode() != null ? detail.getMaterialCode()
|
||||
: (detail.getMaterialName() != null ? detail.getMaterialName() : String.valueOf(detail.getUniqueId()));
|
||||
//OMS推送的库存ID缺失或在WMS不存在时明确报错(此前直接解引用空指针,异常被Feign降级吞掉后单据卡死)
|
||||
if (materialInventoryId == null || materialInventoryId <= 0) {
|
||||
throw new ServiceException("出库单[" + outOrderNumber + "]物料[" + materialDesc + "]未关联库存,无法自动分配");
|
||||
}
|
||||
MaterialInventory materialInventory = materialInventoryMapper.selectById(materialInventoryId);
|
||||
if (materialInventory == null) {
|
||||
throw new ServiceException("出库单[" + outOrderNumber + "]物料[" + materialDesc + "]库存不存在,库存ID=" + materialInventoryId + ",无法自动分配");
|
||||
}
|
||||
BigDecimal remainingQuantity = detail.getQuantity(); // 计划数量
|
||||
if (remainingQuantity == null || remainingQuantity.compareTo(BigDecimal.ZERO) <= 0) {
|
||||
throw new ServiceException("出库单[" + outOrderNumber + "]物料[" + materialDesc + "]计划数量为0,无法自动分配");
|
||||
}
|
||||
|
||||
// 当前物料的可用库存
|
||||
BigDecimal availableStock = materialInventory.getAllocationQuantity();
|
||||
@@ -1132,9 +1146,9 @@ public class StockOutOrderApplicationService {
|
||||
continue;
|
||||
}
|
||||
if (availableStock.compareTo(remainingQuantity) < 0) {
|
||||
throw new RuntimeException(
|
||||
String.format("可用库存不足,计划数量:%s,当前可用库存:%s",
|
||||
remainingQuantity, availableStock)
|
||||
throw new ServiceException(
|
||||
String.format("出库单[%s]物料[%s]可用库存不足,计划数量:%s,当前可用库存:%s",
|
||||
outOrderNumber, materialDesc, remainingQuantity, availableStock)
|
||||
);
|
||||
}
|
||||
// detail.setMaterialInventoryId(materialInventory.getMaterialInventoryId());
|
||||
@@ -1148,6 +1162,10 @@ public class StockOutOrderApplicationService {
|
||||
detail.setAllocationQuantity(remainingQuantity);
|
||||
materialDetailList2.add(detail);
|
||||
}
|
||||
//全部明细因可用库存为0被跳过时明确报错(此前空明细落入batchAssignUpdate抛出笼统的"物料明细不能为空",难定位)
|
||||
if (materialDetailList2.isEmpty()) {
|
||||
throw new ServiceException("出库单[" + stockOutOrderDb.getOutOrderNumber() + "]所有物料明细的可用库存为0,无法自动分配");
|
||||
}
|
||||
stockOutOrderD.setMaterialDetailList(materialDetailList2);
|
||||
StockOutOrderDO assembleStockOutOrderDO = assembleParamByOutOrder(stockOutOrderD);
|
||||
Boolean assignResult = stockOutOrderDomainService.autoAssign(assembleStockOutOrderDO);
|
||||
@@ -1158,6 +1176,98 @@ public class StockOutOrderApplicationService {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* OMS下发前库存校验:按库存ID聚合各明细计划数量,逐一比对WMS可用库存,
|
||||
* 全部比对完成后汇总所有不足项一次性抛错。用于OMS在下发推送前拦截
|
||||
* (此前单据先落库、分配才失败,会在WMS残留"已审核"状态的垃圾单)
|
||||
*/
|
||||
public void checkOmsAssignInventory(List<OutMaterialDetail> outMaterialDetails) {
|
||||
if (CollectionUtils.isEmpty(outMaterialDetails)) {
|
||||
return;
|
||||
}
|
||||
//重复下发保护:该单号在WMS已存在活动单据时直接拦截(继续下发会删改已分配明细、
|
||||
//失败补偿还会误删正在拣货的单和拣货单)。历史残留单据需先在OMS取消下发后再重试
|
||||
String outOrderNumber = outMaterialDetails.get(0).getOutOrderNumber();
|
||||
if (outOrderNumber != null && !outOrderNumber.isEmpty()) {
|
||||
StockOutOrder existOrder = stockOutOrderService.getOne(new QueryWrapper<StockOutOrder>().lambda()
|
||||
.eq(StockOutOrder::getOutOrderNumber, outOrderNumber)
|
||||
.eq(StockOutOrder::getDelFlag, 1), false);
|
||||
if (existOrder != null) {
|
||||
throw new ServiceException("WMS已存在该出库单(当前状态:" + stockOutOrderStatusName(existOrder.getStatus())
|
||||
+ "),请勿重复下发;若为历史残留单据,请先取消下发后重试");
|
||||
}
|
||||
}
|
||||
//同一库存被多条明细引用时聚合需求量再比较(单条比会漏判)
|
||||
Map<Long, BigDecimal> needByInventoryId = new LinkedHashMap<>();
|
||||
Map<Long, String> materialDescByInventoryId = new HashMap<>();
|
||||
for (OutMaterialDetail detail : outMaterialDetails) {
|
||||
if (detail.getMaterialInventoryId() == null) {
|
||||
continue;
|
||||
}
|
||||
BigDecimal need = detail.getQuantity() == null ? BigDecimal.ZERO : detail.getQuantity();
|
||||
needByInventoryId.merge(detail.getMaterialInventoryId(), need, BigDecimal::add);
|
||||
materialDescByInventoryId.putIfAbsent(detail.getMaterialInventoryId(), buildMaterialDesc(detail));
|
||||
}
|
||||
List<String> errors = new ArrayList<>();
|
||||
for (Map.Entry<Long, BigDecimal> entry : needByInventoryId.entrySet()) {
|
||||
Long materialInventoryId = entry.getKey();
|
||||
BigDecimal need = entry.getValue();
|
||||
String materialDesc = materialDescByInventoryId.getOrDefault(materialInventoryId, "库存ID=" + materialInventoryId);
|
||||
if (materialInventoryId <= 0) {
|
||||
errors.add("物料[" + materialDesc + "]未关联库存,合计需求数量:" + need.stripTrailingZeros().toPlainString());
|
||||
continue;
|
||||
}
|
||||
MaterialInventory materialInventory = materialInventoryMapper.selectById(materialInventoryId);
|
||||
if (materialInventory == null) {
|
||||
errors.add("物料[" + materialDesc + "]库存不存在,库存ID=" + materialInventoryId);
|
||||
continue;
|
||||
}
|
||||
BigDecimal available = materialInventory.getAllocationQuantity() == null
|
||||
? BigDecimal.ZERO : materialInventory.getAllocationQuantity();
|
||||
if (available.compareTo(need) < 0) {
|
||||
errors.add(String.format("物料[%s]可用库存不足:需要%s,当前可用%s",
|
||||
materialDesc, need.stripTrailingZeros().toPlainString(), available.stripTrailingZeros().toPlainString()));
|
||||
}
|
||||
}
|
||||
if (!errors.isEmpty()) {
|
||||
throw new ServiceException("下发前库存校验未通过(共" + errors.size() + "项):" + String.join(";", errors));
|
||||
}
|
||||
}
|
||||
|
||||
private String buildMaterialDesc(OutMaterialDetail detail) {
|
||||
if (detail.getMaterialCode() != null) {
|
||||
return detail.getMaterialCode() + (detail.getMaterialName() != null ? "-" + detail.getMaterialName() : "");
|
||||
}
|
||||
if (detail.getMaterialName() != null) {
|
||||
return detail.getMaterialName();
|
||||
}
|
||||
return "未知物料";
|
||||
}
|
||||
|
||||
/**
|
||||
* 出库单状态码转名称(用于校验提示),未知状态码原样返回
|
||||
*/
|
||||
private String stockOutOrderStatusName(Integer status) {
|
||||
if (status == null) {
|
||||
return "未知";
|
||||
}
|
||||
switch (status) {
|
||||
case 1: return "已创建";
|
||||
case 2: return "已审核";
|
||||
case 3: return "部分分配";
|
||||
case 4: return "已分配";
|
||||
case 5: return "波次中";
|
||||
case 6: return "拣货中";
|
||||
case 7: return "拣货完成";
|
||||
case 8: return "复核中";
|
||||
case 9: return "已出库";
|
||||
case 10: return "取消";
|
||||
case 11: return "关闭";
|
||||
case 12: return "已复核";
|
||||
default: return "状态码" + status;
|
||||
}
|
||||
}
|
||||
|
||||
/*public Boolean autoAssign(StockOutOrderDO stockOutOrderDO){
|
||||
StockOutOrderDO assembleStockOutOrderDO = assembleParamByOutOrder(stockOutOrderDO);
|
||||
return stockOutOrderDomainService.autoAssign(assembleStockOutOrderDO);
|
||||
@@ -1425,7 +1535,9 @@ public class StockOutOrderApplicationService {
|
||||
List<OutMaterialDetailDO> returnOutMaterialDetailDOList = new ArrayList<>();
|
||||
for (OutMaterialDetailDO outMaterialDetailDO : stockOutOrderDO.getMaterialDetailList()){
|
||||
Long uniqueId = outMaterialDetailDO.getUniqueId();
|
||||
OutMaterialDetail outMaterialDetail = outMaterialDetailService.getOne(new LambdaQueryWrapper<OutMaterialDetail>().eq(OutMaterialDetail::getUniqueId, uniqueId));
|
||||
OutMaterialDetail outMaterialDetail = outMaterialDetailService.getOne(new LambdaQueryWrapper<OutMaterialDetail>()
|
||||
.eq(OutMaterialDetail::getUniqueId, uniqueId)
|
||||
.eq(OutMaterialDetail::getDelFlag,1));
|
||||
if (outMaterialDetail == null){
|
||||
throw new ServiceException("出库明细不存在");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.mhd.wms.config;
|
||||
|
||||
import com.fasterxml.jackson.databind.Module;
|
||||
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||
import com.mhd.common.core.jackson.FlexibleDateDeserializer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* JSON 日期反序列化兼容配置:Date 字段兼容 yyyy-MM-dd(纯日期)等格式。
|
||||
*
|
||||
* 背景:库存查询日期只保留年月日后,前端回传纯日期(如 createTime=2026-07-06)时,
|
||||
* 实体/DTO 上 @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss") 严格格式反序列化报
|
||||
* InvalidFormatException。注册 FlexibleDateDeserializer 后优先按字段 @JsonFormat
|
||||
* 严格解析,失败时兼容纯日期等常见格式(与 OMS 库存查询一致)。
|
||||
*
|
||||
* Spring Boot 会自动把容器中的 Module Bean 注册进 MVC 使用的 ObjectMapper。
|
||||
*
|
||||
* @author rcx
|
||||
* @date 2026-09-05
|
||||
*/
|
||||
@Configuration
|
||||
public class DateCompatibilityConfig {
|
||||
|
||||
@Bean
|
||||
public Module flexibleDateModule() {
|
||||
SimpleModule module = new SimpleModule("wms-flexible-date-module");
|
||||
module.addDeserializer(Date.class, new FlexibleDateDeserializer());
|
||||
return module;
|
||||
}
|
||||
}
|
||||
+3
-2
@@ -120,7 +120,8 @@ public class DeliveTaskImpl extends ServiceImpl<DeliveTaskMapper, DeliveTask> im
|
||||
String orderNumber = handoverTaskOrder.getOrderNumber();//出库单号
|
||||
// 已复核数量、出库单信息:直接从出库单获取(需在物料统计前获取,用于判断是否需要复核)
|
||||
StockOutOrder stockOutOrder = stockOutOrderService.getOne(new LambdaQueryWrapper<StockOutOrder>()
|
||||
.eq(StockOutOrder::getOutOrderNumber, orderNumber));
|
||||
.eq(StockOutOrder::getOutOrderNumber, orderNumber)
|
||||
.eq(StockOutOrder::getDelFlag,1));
|
||||
if (stockOutOrder != null) {
|
||||
deliveTaskPO.setOutOrderNumber(stockOutOrder.getOutOrderNumber());
|
||||
deliveTaskPO.setOutOrderStatus(stockOutOrder.getStatus());
|
||||
@@ -297,4 +298,4 @@ public class DeliveTaskImpl extends ServiceImpl<DeliveTaskMapper, DeliveTask> im
|
||||
public DeliveTaskPO querySum(DeliveTaskDO deliveTaskDO) {
|
||||
return deliveTaskMapper.querySum(deliveTaskDO);
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
@@ -415,6 +415,7 @@ public class HandoverTaskOrderDomainService {
|
||||
//交接完成节点修改库存
|
||||
String orderNumber = handoverTaskOrder.getOrderNumber();
|
||||
StockOutOrder stockOutOrder = stockOutOrderMapper.selectOne(new QueryWrapper<StockOutOrder>().lambda()
|
||||
.eq(StockOutOrder::getDelFlag,1)
|
||||
.eq(StockOutOrder::getOutOrderNumber, orderNumber));
|
||||
if (stockOutOrder == null) {
|
||||
continue;
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package com.mhd.wms.domain.inboundRank.repository.facade;
|
||||
|
||||
import com.mhd.wms.domain.inboundRank.repository.po.InboundMaterialRankPO;
|
||||
import com.mhd.wms.domain.inboundRank.repository.po.InboundRankTotalPO;
|
||||
import com.mhd.wms.domain.inboundRank.repository.todo.InboundRankDO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 入库排名统计Service接口
|
||||
*
|
||||
* @author rcx
|
||||
* @date 2026-08-31
|
||||
*/
|
||||
public interface IInboundRankService {
|
||||
|
||||
/**
|
||||
* 商品入库排名列表(仓单+货品汇总,按件数降序)
|
||||
*/
|
||||
List<InboundMaterialRankPO> queryMaterialRankList(InboundRankDO inboundRankDO);
|
||||
|
||||
/**
|
||||
* 商品入库排名合计(不分页)
|
||||
*/
|
||||
InboundRankTotalPO queryMaterialRankTotal(InboundRankDO inboundRankDO);
|
||||
}
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
package com.mhd.wms.domain.inboundRank.repository.mapper;
|
||||
|
||||
import com.mhd.wms.domain.inboundRank.repository.po.InboundMaterialRankPO;
|
||||
import com.mhd.wms.domain.inboundRank.repository.po.InboundRankTotalPO;
|
||||
import com.mhd.wms.domain.inboundRank.repository.todo.InboundRankDO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 入库排名统计Mapper接口
|
||||
*
|
||||
* @author rcx
|
||||
* @date 2026-08-31
|
||||
*/
|
||||
public interface InboundRankMapper {
|
||||
|
||||
/**
|
||||
* 商品入库排名列表(按物料编码合并,按件数降序,过滤0件行)
|
||||
*/
|
||||
List<InboundMaterialRankPO> queryMaterialRankList(InboundRankDO inboundRankDO);
|
||||
|
||||
/**
|
||||
* 商品入库排名合计(不分页,当前筛选条件全量合计)
|
||||
*/
|
||||
InboundRankTotalPO queryMaterialRankTotal(InboundRankDO inboundRankDO);
|
||||
}
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
package com.mhd.wms.domain.inboundRank.repository.persistence;
|
||||
|
||||
import com.mhd.wms.domain.inboundRank.repository.facade.IInboundRankService;
|
||||
import com.mhd.wms.domain.inboundRank.repository.mapper.InboundRankMapper;
|
||||
import com.mhd.wms.domain.inboundRank.repository.po.InboundMaterialRankPO;
|
||||
import com.mhd.wms.domain.inboundRank.repository.po.InboundRankTotalPO;
|
||||
import com.mhd.wms.domain.inboundRank.repository.todo.InboundRankDO;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 入库排名统计Service业务层处理
|
||||
*
|
||||
* @author rcx
|
||||
* @date 2026-08-31
|
||||
*/
|
||||
@Service
|
||||
public class InboundRankImpl implements IInboundRankService {
|
||||
|
||||
@Autowired
|
||||
private InboundRankMapper inboundRankMapper;
|
||||
|
||||
@Override
|
||||
public List<InboundMaterialRankPO> queryMaterialRankList(InboundRankDO inboundRankDO) {
|
||||
return inboundRankMapper.queryMaterialRankList(inboundRankDO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public InboundRankTotalPO queryMaterialRankTotal(InboundRankDO inboundRankDO) {
|
||||
return inboundRankMapper.queryMaterialRankTotal(inboundRankDO);
|
||||
}
|
||||
}
|
||||
+58
@@ -0,0 +1,58 @@
|
||||
package com.mhd.wms.domain.inboundRank.repository.po;
|
||||
|
||||
import com.mhd.common.core.annotation.Excel;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 入库排名统计PO(一行 = 一个物料的合计(按物料编码合并,查询区间内全部已入库仓单),按件数降序排名)
|
||||
*
|
||||
* <p>字段口径:件数=实际上架量(SHELVES_QUANTITY)合计;毛重(吨)=明细总毛重KG/1000;体积=明细合计;
|
||||
* 投保总额=货品档案保额(material_base_info.insure_amount,物料维度单一值取MAX,不跨仓单累加);
|
||||
* 仓单编号/客户编号/存货人/入仓日期为单据级字段,按物料合并后单值失真,仅作查询条件不返回</p>
|
||||
*
|
||||
* @author rcx
|
||||
* @date 2026-08-31
|
||||
*/
|
||||
@Data
|
||||
@ApiModel(value = "入库排名统计对象", description = "入库排名统计响应对象")
|
||||
public class InboundMaterialRankPO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ApiModelProperty("物料编码(合并依据)")
|
||||
@Excel(name = "物料编码")
|
||||
private String materialCode;
|
||||
|
||||
@ApiModelProperty("货名/商品名称")
|
||||
@Excel(name = "货名")
|
||||
private String materialName;
|
||||
|
||||
@ApiModelProperty("规格型号")
|
||||
@Excel(name = "规格型号")
|
||||
private String specificationModel;
|
||||
|
||||
@ApiModelProperty("单位")
|
||||
@Excel(name = "单位")
|
||||
private String unitName;
|
||||
|
||||
@ApiModelProperty("件数(该物料实际上架量合计 SHELVES_QUANTITY,排名依据)")
|
||||
@Excel(name = "件数")
|
||||
private BigDecimal pieceCount;
|
||||
|
||||
@ApiModelProperty("毛重(吨)(该物料合计,KG/1000)")
|
||||
@Excel(name = "毛重(吨)")
|
||||
private BigDecimal grossWeightTon;
|
||||
|
||||
@ApiModelProperty("投保总额(货品档案保额,物料维度单一值)")
|
||||
@Excel(name = "投保总额")
|
||||
private BigDecimal insureAmount;
|
||||
|
||||
@ApiModelProperty("体积(CBM)(该物料合计)")
|
||||
@Excel(name = "体积(CBM)")
|
||||
private BigDecimal totalVolume;
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
package com.mhd.wms.domain.inboundRank.repository.po;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 入库排名统计合计PO
|
||||
*
|
||||
* <p>当前筛选条件下不分页的全量合计,随分页列表一起返回
|
||||
* (totalPieceCount/totalGrossWeightTon/totalInsureAmount/totalVolume/totalOrderCount)</p>
|
||||
*
|
||||
* @author rcx
|
||||
* @date 2026-08-31
|
||||
*/
|
||||
@Data
|
||||
@ApiModel(value = "入库排名统计合计对象", description = "入库排名统计合计响应对象")
|
||||
public class InboundRankTotalPO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ApiModelProperty("件数合计(实际上架量)")
|
||||
private BigDecimal totalPieceCount;
|
||||
|
||||
@ApiModelProperty("毛重(吨)合计")
|
||||
private BigDecimal totalGrossWeightTon;
|
||||
|
||||
@ApiModelProperty("投保总额合计(各物料保额之和,每物料计一次)")
|
||||
private BigDecimal totalInsureAmount;
|
||||
|
||||
@ApiModelProperty("体积(CBM)合计")
|
||||
private BigDecimal totalVolume;
|
||||
|
||||
@ApiModelProperty("涉及仓单数(当前筛选条件下去重统计)")
|
||||
private Long totalOrderCount;
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
package com.mhd.wms.domain.inboundRank.repository.todo;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 入库排名统计查询DO
|
||||
*
|
||||
* <p>topOrganizationId / warehouseId 由服务端按登录用户注入,前端不传</p>
|
||||
*
|
||||
* @author rcx
|
||||
* @date 2026-08-31
|
||||
*/
|
||||
@Data
|
||||
public class InboundRankDO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ApiModelProperty("入仓日期-开始 yyyy-MM-dd(必填)")
|
||||
private String warehouseDateStart;
|
||||
|
||||
@ApiModelProperty("入仓日期-结束 yyyy-MM-dd(必填)")
|
||||
private String warehouseDateEnd;
|
||||
|
||||
@ApiModelProperty("仓单编号/入库单号(模糊)")
|
||||
private String inOrderNumber;
|
||||
|
||||
@ApiModelProperty("客户编号(模糊)")
|
||||
private String shipperCode;
|
||||
|
||||
@ApiModelProperty("存货人/客户名称(模糊)")
|
||||
private String shipperName;
|
||||
|
||||
@ApiModelProperty("商品货号(模糊)")
|
||||
private String materialCode;
|
||||
|
||||
@ApiModelProperty("货名/商品名称(模糊)")
|
||||
private String materialName;
|
||||
|
||||
@ApiModelProperty("仓库名称(模糊)")
|
||||
private String warehouseName;
|
||||
|
||||
@ApiModelProperty("一级组织表ID(登录用户隔离,非1时注入)")
|
||||
private Long topOrganizationId;
|
||||
|
||||
@ApiModelProperty("仓库id(按用户关联仓库注入)")
|
||||
private Long warehouseId;
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
package com.mhd.wms.domain.inboundRank.service;
|
||||
|
||||
import com.mhd.wms.domain.inboundRank.repository.facade.IInboundRankService;
|
||||
import com.mhd.wms.domain.inboundRank.repository.po.InboundMaterialRankPO;
|
||||
import com.mhd.wms.domain.inboundRank.repository.po.InboundRankTotalPO;
|
||||
import com.mhd.wms.domain.inboundRank.repository.todo.InboundRankDO;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 入库排名统计领域服务
|
||||
*
|
||||
* @author rcx
|
||||
* @date 2026-08-31
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class InboundRankDomainService {
|
||||
|
||||
@Autowired
|
||||
private IInboundRankService inboundRankService;
|
||||
|
||||
/**
|
||||
* 商品入库排名列表(仓单+货品汇总,按件数降序)
|
||||
*/
|
||||
public List<InboundMaterialRankPO> queryMaterialRankList(InboundRankDO inboundRankDO) {
|
||||
return inboundRankService.queryMaterialRankList(inboundRankDO);
|
||||
}
|
||||
|
||||
/**
|
||||
* 商品入库排名合计(不分页)
|
||||
*/
|
||||
public InboundRankTotalPO queryMaterialRankTotal(InboundRankDO inboundRankDO) {
|
||||
return inboundRankService.queryMaterialRankTotal(inboundRankDO);
|
||||
}
|
||||
}
|
||||
+6
@@ -210,6 +210,12 @@ public class MaterialInventory extends BaseVOEntity {
|
||||
@Excel(name = "存货日期", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date inventoryDate;
|
||||
|
||||
@ApiModelProperty("进货日期")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@Excel(name = "进货日期", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date purchaseDate;
|
||||
|
||||
@ApiModelProperty("ExtAttr3")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
|
||||
+1
@@ -880,6 +880,7 @@ public class MaterialInventoryImpl extends ServiceImpl<MaterialInventoryMapper,
|
||||
materialInventory.setExtAttr4(materialInventoryParamDO.getExtAttr4());
|
||||
materialInventory.setExpiryDate(materialInventoryParamDO.getExpiryDate());
|
||||
materialInventory.setInventoryDate(materialInventoryParamDO.getInventoryDate());
|
||||
materialInventory.setPurchaseDate(materialInventoryParamDO.getPurchaseDate());
|
||||
materialInventory.setBatchNumber(materialInventoryParamDO.getBatchNumber());
|
||||
materialInventory.setUnit(materialBaseInfo.getUnitCode());
|
||||
materialInventory.setUnitName(materialBaseInfo.getUnitName());
|
||||
|
||||
+33
-11
@@ -176,34 +176,41 @@ public class MaterialInventoryPO extends MaterialBasePO {
|
||||
@Excel(name = "扩展字段2")
|
||||
private String extAttr2;
|
||||
|
||||
// 以下业务日期字段只保留年月日:导出复用 /list 接口,前端取 JSON 值直接进 Excel,去掉时分秒(与 OMS 库存查询一致)
|
||||
@ApiModelProperty("生产日期")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@Excel(name = "生产日期", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
|
||||
@Excel(name = "生产日期", width = 30, dateFormat = "yyyy-MM-dd")
|
||||
private Date productionDate;
|
||||
|
||||
@ApiModelProperty("过期日期")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@Excel(name = "过期日期", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
|
||||
@Excel(name = "过期日期", width = 30, dateFormat = "yyyy-MM-dd")
|
||||
private Date expiryDate;
|
||||
|
||||
@ApiModelProperty("存货日期")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@Excel(name = "存货日期", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
|
||||
@Excel(name = "存货日期", width = 30, dateFormat = "yyyy-MM-dd")
|
||||
private Date inventoryDate;
|
||||
|
||||
@ApiModelProperty("ExtAttr3")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
@ApiModelProperty("进货日期")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@Excel(name = "ExtAttr3", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
|
||||
@Excel(name = "进货日期", width = 30, dateFormat = "yyyy-MM-dd")
|
||||
private Date purchaseDate;
|
||||
|
||||
@ApiModelProperty("ExtAttr3")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@Excel(name = "ExtAttr3", width = 30, dateFormat = "yyyy-MM-dd")
|
||||
private Date extAttr3;
|
||||
|
||||
@ApiModelProperty("ExtAttr4")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@Excel(name = "ExtAttr4", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
|
||||
@Excel(name = "ExtAttr4", width = 30, dateFormat = "yyyy-MM-dd")
|
||||
private Date extAttr4;
|
||||
|
||||
@ApiModelProperty("物料更多属性列表(批次属性)")
|
||||
@@ -234,6 +241,21 @@ public class MaterialInventoryPO extends MaterialBasePO {
|
||||
@Excel(name = "规格型号")
|
||||
private String specificationModel;
|
||||
|
||||
// 入库时间(createTime)/更新时间(updateTime)继承自 BaseVOEntity,默认带时分秒;
|
||||
// 库存查询导出复用 /list 接口,前端取 JSON 值直接进 Excel,这里覆盖 getter 只保留年月日。
|
||||
// 不改 BaseVOEntity(全系统基类,其他模块时间列仍需时分秒),仅收窄本 PO 的序列化格式(与 OMS 库存查询一致)
|
||||
@Override
|
||||
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
|
||||
public Date getCreateTime() {
|
||||
return super.getCreateTime();
|
||||
}
|
||||
|
||||
@Override
|
||||
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
|
||||
public Date getUpdateTime() {
|
||||
return super.getUpdateTime();
|
||||
}
|
||||
|
||||
@ApiModelProperty("上次计费时间")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
|
||||
+19
@@ -218,6 +218,12 @@ public class MaterialInventoryDO extends MaterialBaseDO {
|
||||
@Excel(name = "存货日期", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date inventoryDate;
|
||||
|
||||
@ApiModelProperty("进货日期")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@Excel(name = "进货日期", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date purchaseDate;
|
||||
|
||||
@ApiModelProperty("ExtAttr3")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@@ -250,9 +256,12 @@ public class MaterialInventoryDO extends MaterialBaseDO {
|
||||
|
||||
/** 为 true 时 SQL 排除库存数量为 0(含 null 视为 0) */
|
||||
private Boolean excludeZeroInventoryQuantity;
|
||||
/** 为 true 时 SQL 排除可用数量为 0(含 null 视为 0),出库选库存可用 */
|
||||
private Boolean excludeZeroAllocationQuantity;
|
||||
private String expiryDateStr;
|
||||
private String productionDateStr;
|
||||
private String updateTimeStr;
|
||||
private String purchaseDateStr;
|
||||
|
||||
private String expiryDateStart;
|
||||
private String expiryDateEnd;
|
||||
@@ -263,6 +272,13 @@ public class MaterialInventoryDO extends MaterialBaseDO {
|
||||
private String updateTimeStart;
|
||||
private String updateTimeEnd;
|
||||
|
||||
private String purchaseDateStart;
|
||||
private String purchaseDateEnd;
|
||||
|
||||
/** 入库日期(库存行创建时间)区间查询 */
|
||||
private String createTimeStart;
|
||||
private String createTimeEnd;
|
||||
|
||||
@ApiModelProperty("库存分配匹配:箱号/卡板号 token 列表(明细多值拆分后,OR 匹配;空则不参与匹配)")
|
||||
private List<String> boxPalletNoList;
|
||||
|
||||
@@ -280,4 +296,7 @@ public class MaterialInventoryDO extends MaterialBaseDO {
|
||||
|
||||
private String lastBillingTimeStart;
|
||||
private String lastBillingTimeEnd;
|
||||
|
||||
@ApiModelProperty("导出标识:导出与查询共用 /list,true-本次为导出请求,启用导出融合排序(到期日倒序优先→同到期日按物料编码升序→0库存靠后→更新时间倒序);不传-保持原有排序")
|
||||
private Boolean isExport;
|
||||
}
|
||||
+2
@@ -88,6 +88,8 @@ public class MaterialInventoryParamDO extends MaterialBaseDO {
|
||||
private Date expiryDate;
|
||||
//库存日期
|
||||
private Date inventoryDate;
|
||||
//进货日期
|
||||
private Date purchaseDate;
|
||||
//扩展字段3
|
||||
private Date extAttr3;
|
||||
//扩展字段4
|
||||
|
||||
+14
-4
@@ -551,7 +551,9 @@ public class OutMaterialDetailImpl extends ServiceImpl<OutMaterialDetailMapper,
|
||||
}
|
||||
|
||||
public synchronized void xgkc(List<OutMaterialDetail> outMaterialDetailList,String outOrderNumber,LoginUser loginUser) {
|
||||
StockOutOrder stockOutOrder = stockOutOrderMapper.selectOne(new QueryWrapper<StockOutOrder>().lambda().eq(StockOutOrder::getOutOrderNumber, outOrderNumber));
|
||||
StockOutOrder stockOutOrder = stockOutOrderMapper.selectOne(new QueryWrapper<StockOutOrder>().lambda()
|
||||
.eq(StockOutOrder::getOutOrderNumber, outOrderNumber)
|
||||
.eq(StockOutOrder::getDelFlag, 1));
|
||||
for (OutMaterialDetail outMaterialDetail : outMaterialDetailList) {
|
||||
BigDecimal nowAllocationQuantity = outMaterialDetail.getNowAllocationQuantity();
|
||||
if (nowAllocationQuantity == null || nowAllocationQuantity.compareTo(BigDecimal.ZERO) <= 0) {
|
||||
@@ -700,7 +702,9 @@ public class OutMaterialDetailImpl extends ServiceImpl<OutMaterialDetailMapper,
|
||||
}
|
||||
|
||||
public synchronized void childrenxgkc(List<OutMaterialDetail> outMaterialDetailList,String outOrderNumber,LoginUser loginUser) {
|
||||
StockOutOrder stockOutOrder = stockOutOrderMapper.selectOne(new QueryWrapper<StockOutOrder>().lambda().eq(StockOutOrder::getOutOrderNumber, outOrderNumber));
|
||||
StockOutOrder stockOutOrder = stockOutOrderMapper.selectOne(new QueryWrapper<StockOutOrder>().lambda()
|
||||
.eq(StockOutOrder::getOutOrderNumber, outOrderNumber)
|
||||
.eq(StockOutOrder::getDelFlag,1));
|
||||
for (OutMaterialDetail outMaterialDetail : outMaterialDetailList) {
|
||||
BigDecimal nowAllocationQuantity = outMaterialDetail.getNowAllocationQuantity();
|
||||
if (nowAllocationQuantity == null || nowAllocationQuantity.compareTo(BigDecimal.ZERO) <= 0) {
|
||||
@@ -995,7 +999,9 @@ public class OutMaterialDetailImpl extends ServiceImpl<OutMaterialDetailMapper,
|
||||
}
|
||||
|
||||
private synchronized void qxfp(List<OutMaterialDetailDO> outMaterialDetailList,String outOrderNumber,LoginUser loginUser) {
|
||||
StockOutOrder stockOutOrder = stockOutOrderMapper.selectOne(new QueryWrapper<StockOutOrder>().lambda().eq(StockOutOrder::getOutOrderNumber, outOrderNumber));
|
||||
StockOutOrder stockOutOrder = stockOutOrderMapper.selectOne(new QueryWrapper<StockOutOrder>().lambda()
|
||||
.eq(StockOutOrder::getDelFlag,1)
|
||||
.eq(StockOutOrder::getOutOrderNumber, outOrderNumber));
|
||||
for (OutMaterialDetailDO outMaterialDetail : outMaterialDetailList) {
|
||||
Long materialInventoryId = outMaterialDetail.getMaterialInventoryId();
|
||||
BigDecimal allocationQuantity = outMaterialDetail.getActualQuantity();
|
||||
@@ -1105,7 +1111,9 @@ public class OutMaterialDetailImpl extends ServiceImpl<OutMaterialDetailMapper,
|
||||
|
||||
|
||||
private synchronized void childrenqxfp(List<OutMaterialDetailDO> outMaterialDetailList,String outOrderNumber,LoginUser loginUser) {
|
||||
StockOutOrder stockOutOrder = stockOutOrderMapper.selectOne(new QueryWrapper<StockOutOrder>().lambda().eq(StockOutOrder::getOutOrderNumber, outOrderNumber));
|
||||
StockOutOrder stockOutOrder = stockOutOrderMapper.selectOne(new QueryWrapper<StockOutOrder>().lambda()
|
||||
.eq(StockOutOrder::getDelFlag,1)
|
||||
.eq(StockOutOrder::getOutOrderNumber, outOrderNumber));
|
||||
for (OutMaterialDetailDO outMaterialDetail : outMaterialDetailList) {
|
||||
Long materialInventoryId = outMaterialDetail.getMaterialInventoryId();
|
||||
BigDecimal allocationQuantity = outMaterialDetail.getActualQuantity();
|
||||
@@ -1241,11 +1249,13 @@ public class OutMaterialDetailImpl extends ServiceImpl<OutMaterialDetailMapper,
|
||||
if (StringUtils.isNotBlank(stockOutOrderDO.getBarCode())){
|
||||
outMaterialDetailDb = outMaterialDetailMapper.selectOne(new QueryWrapper<OutMaterialDetail>().lambda()
|
||||
.eq(OutMaterialDetail::getOutOrderNumber, stockOutOrderDO.getOutOrderNumber())
|
||||
.eq(OutMaterialDetail::getDelFlag,1)
|
||||
.eq(OutMaterialDetail::getBarCode, stockOutOrderDO.getBarCode()));
|
||||
}else {
|
||||
OutMaterialDetailSerialNumber outMaterialDetailSerialNumber = outMaterialDetailSerialNumberService.getOne(new QueryWrapper<OutMaterialDetailSerialNumber>().lambda()
|
||||
.eq(OutMaterialDetailSerialNumber::getSerialNumber, stockOutOrderDO.getSerialNumber()));
|
||||
outMaterialDetailDb = outMaterialDetailMapper.selectOne(new QueryWrapper<OutMaterialDetail>().lambda()
|
||||
.eq(OutMaterialDetail::getDelFlag,1)
|
||||
.eq(OutMaterialDetail::getUniqueId, outMaterialDetailSerialNumber.getMaterialDetailUniqueId()));
|
||||
}
|
||||
if(outMaterialDetailDb == null){
|
||||
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package com.mhd.wms.domain.outboundRank.repository.facade;
|
||||
|
||||
import com.mhd.wms.domain.outboundRank.repository.po.OutboundDetailRankTotalPO;
|
||||
import com.mhd.wms.domain.outboundRank.repository.po.OutboundLineRankPO;
|
||||
import com.mhd.wms.domain.outboundRank.repository.po.OutboundMaterialRankPO;
|
||||
import com.mhd.wms.domain.outboundRank.repository.todo.OutboundRankDO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 出库排名统计Service接口
|
||||
*
|
||||
* @author rcx
|
||||
* @date 2026-08-31
|
||||
*/
|
||||
public interface IOutboundRankService {
|
||||
|
||||
/**
|
||||
* 商品出库排名列表(货品聚合)
|
||||
*/
|
||||
List<OutboundMaterialRankPO> queryMaterialRankList(OutboundRankDO outboundRankDO);
|
||||
|
||||
/**
|
||||
* 商品出库排名合计(不分页)
|
||||
*/
|
||||
OutboundDetailRankTotalPO queryMaterialRankTotal(OutboundRankDO outboundRankDO);
|
||||
|
||||
/**
|
||||
* 线路出库排名列表(线路×货品聚合)
|
||||
*/
|
||||
List<OutboundLineRankPO> queryLineRankList(OutboundRankDO outboundRankDO);
|
||||
|
||||
/**
|
||||
* 线路出库排名合计(不分页)
|
||||
*/
|
||||
OutboundDetailRankTotalPO queryLineRankTotal(OutboundRankDO outboundRankDO);
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
package com.mhd.wms.domain.outboundRank.repository.mapper;
|
||||
|
||||
import com.mhd.wms.domain.outboundRank.repository.po.OutboundDetailRankTotalPO;
|
||||
import com.mhd.wms.domain.outboundRank.repository.po.OutboundLineRankPO;
|
||||
import com.mhd.wms.domain.outboundRank.repository.po.OutboundMaterialRankPO;
|
||||
import com.mhd.wms.domain.outboundRank.repository.todo.OutboundRankDO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 出库排名统计Mapper接口
|
||||
*
|
||||
* @author rcx
|
||||
* @date 2026-08-31
|
||||
*/
|
||||
public interface OutboundRankMapper {
|
||||
|
||||
/**
|
||||
* 商品出库排名列表(一行=一个货品,跨单汇总,按实际出库量降序)
|
||||
*/
|
||||
List<OutboundMaterialRankPO> queryMaterialRankList(OutboundRankDO outboundRankDO);
|
||||
|
||||
/**
|
||||
* 商品出库排名合计(不分页,当前筛选条件全量合计)
|
||||
*/
|
||||
OutboundDetailRankTotalPO queryMaterialRankTotal(OutboundRankDO outboundRankDO);
|
||||
|
||||
/**
|
||||
* 线路出库排名列表(一行=线路×货品,按实际出库量降序,仅统计带线路的单)
|
||||
*/
|
||||
List<OutboundLineRankPO> queryLineRankList(OutboundRankDO outboundRankDO);
|
||||
|
||||
/**
|
||||
* 线路出库排名合计(不分页,当前筛选条件全量合计)
|
||||
*/
|
||||
OutboundDetailRankTotalPO queryLineRankTotal(OutboundRankDO outboundRankDO);
|
||||
}
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
package com.mhd.wms.domain.outboundRank.repository.persistence;
|
||||
|
||||
import com.mhd.wms.domain.outboundRank.repository.facade.IOutboundRankService;
|
||||
import com.mhd.wms.domain.outboundRank.repository.mapper.OutboundRankMapper;
|
||||
import com.mhd.wms.domain.outboundRank.repository.po.OutboundDetailRankTotalPO;
|
||||
import com.mhd.wms.domain.outboundRank.repository.po.OutboundLineRankPO;
|
||||
import com.mhd.wms.domain.outboundRank.repository.po.OutboundMaterialRankPO;
|
||||
import com.mhd.wms.domain.outboundRank.repository.todo.OutboundRankDO;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 出库排名统计Service业务层处理
|
||||
*
|
||||
* @author rcx
|
||||
* @date 2026-08-31
|
||||
*/
|
||||
@Service
|
||||
public class OutboundRankImpl implements IOutboundRankService {
|
||||
|
||||
@Autowired
|
||||
private OutboundRankMapper outboundRankMapper;
|
||||
|
||||
@Override
|
||||
public List<OutboundMaterialRankPO> queryMaterialRankList(OutboundRankDO outboundRankDO) {
|
||||
return outboundRankMapper.queryMaterialRankList(outboundRankDO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutboundDetailRankTotalPO queryMaterialRankTotal(OutboundRankDO outboundRankDO) {
|
||||
return outboundRankMapper.queryMaterialRankTotal(outboundRankDO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<OutboundLineRankPO> queryLineRankList(OutboundRankDO outboundRankDO) {
|
||||
return outboundRankMapper.queryLineRankList(outboundRankDO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutboundDetailRankTotalPO queryLineRankTotal(OutboundRankDO outboundRankDO) {
|
||||
return outboundRankMapper.queryLineRankTotal(outboundRankDO);
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
package com.mhd.wms.domain.outboundRank.repository.po;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 出库排名统计(明细)合计PO
|
||||
*
|
||||
* <p>当前筛选条件下不分页的全量合计,随分页列表一起返回
|
||||
* (totalPieceCount/totalGrossWeightTon/totalVolume/totalOrderCount)</p>
|
||||
*
|
||||
* @author rcx
|
||||
* @date 2026-08-31
|
||||
*/
|
||||
@Data
|
||||
@ApiModel(value = "出库排名统计明细合计对象", description = "出库排名统计明细合计响应对象")
|
||||
public class OutboundDetailRankTotalPO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ApiModelProperty("件数合计")
|
||||
private BigDecimal totalPieceCount;
|
||||
|
||||
@ApiModelProperty("毛重(吨)合计")
|
||||
private BigDecimal totalGrossWeightTon;
|
||||
|
||||
@ApiModelProperty("体积(CBM)合计")
|
||||
private BigDecimal totalVolume;
|
||||
|
||||
@ApiModelProperty("仓单数合计(去重出库单数)")
|
||||
private Long totalOrderCount;
|
||||
|
||||
@ApiModelProperty("线路数合计(去重线路数,线路排名使用)")
|
||||
private Long totalLineCount;
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
package com.mhd.wms.domain.outboundRank.repository.po;
|
||||
|
||||
import com.mhd.common.core.annotation.Excel;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 线路出库排名PO(一行 = 线路×货品,日期区间内汇总)
|
||||
*
|
||||
* <p>按线路+物料编码合并:多张出库单合并为一行,单据级字段(种类/仓单编号/入库单号/客户编号/收货人/出仓日期)不提供;
|
||||
* 仅统计带线路的出库单(line_code 为 2026-08-20 新增冗余字段,历史单为空,不参与线路排名);
|
||||
* 件数 = SUM(CHECK_QUANTITY) 复核确认的实际出库量(与入库排名的实际上架量对称);
|
||||
* 退保总额为占位字段,后端暂无对应数据来源,恒为 null</p>
|
||||
*
|
||||
* @author rcx
|
||||
* @date 2026-08-31
|
||||
*/
|
||||
@Data
|
||||
@ApiModel(value = "线路出库排名对象", description = "线路出库排名响应对象")
|
||||
public class OutboundLineRankPO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ApiModelProperty("线路编码")
|
||||
@Excel(name = "线路编码")
|
||||
private String lineCode;
|
||||
|
||||
@ApiModelProperty("线路")
|
||||
@Excel(name = "线路")
|
||||
private String lineName;
|
||||
|
||||
@ApiModelProperty("商品货号")
|
||||
@Excel(name = "商品货号")
|
||||
private String materialCode;
|
||||
|
||||
@ApiModelProperty("货名")
|
||||
@Excel(name = "货名")
|
||||
private String materialName;
|
||||
|
||||
@ApiModelProperty("件数(复核确认的实际出库量合计,与入库排名的实际上架量对称)")
|
||||
@Excel(name = "件数")
|
||||
private BigDecimal pieceCount;
|
||||
|
||||
@ApiModelProperty("毛重(吨)")
|
||||
@Excel(name = "毛重(吨)")
|
||||
private BigDecimal grossWeightTon;
|
||||
|
||||
@ApiModelProperty("体积(CBM)")
|
||||
@Excel(name = "体积(CBM)")
|
||||
private BigDecimal totalVolume;
|
||||
|
||||
@ApiModelProperty("退保总额(占位字段,后端暂无数据来源,恒为 null)")
|
||||
@Excel(name = "退保总额")
|
||||
private BigDecimal depositRefundAmount;
|
||||
}
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
package com.mhd.wms.domain.outboundRank.repository.po;
|
||||
|
||||
import com.mhd.common.core.annotation.Excel;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 商品出库排名PO(一行 = 一个货品,日期区间内跨出库单汇总)
|
||||
*
|
||||
* <p>按物料编码合并:一个货品会走多条线路/多张单,单据级字段(种类/仓单编号/入库单号/客户编号/收货人/出仓日期)与
|
||||
* 线路字段均无单值可返,不提供;件数 = SUM(CHECK_QUANTITY) 复核确认的实际出库量(与入库排名的实际上架量对称);
|
||||
* 退保总额为占位字段,后端暂无对应数据来源,恒为 null</p>
|
||||
*
|
||||
* @author rcx
|
||||
* @date 2026-08-31
|
||||
*/
|
||||
@Data
|
||||
@ApiModel(value = "商品出库排名对象", description = "商品出库排名响应对象")
|
||||
public class OutboundMaterialRankPO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ApiModelProperty("商品货号")
|
||||
@Excel(name = "商品货号")
|
||||
private String materialCode;
|
||||
|
||||
@ApiModelProperty("货名")
|
||||
@Excel(name = "货名")
|
||||
private String materialName;
|
||||
|
||||
@ApiModelProperty("件数(复核确认的实际出库量合计,与入库排名的实际上架量对称)")
|
||||
@Excel(name = "件数")
|
||||
private BigDecimal pieceCount;
|
||||
|
||||
@ApiModelProperty("毛重(吨)")
|
||||
@Excel(name = "毛重(吨)")
|
||||
private BigDecimal grossWeightTon;
|
||||
|
||||
@ApiModelProperty("体积(CBM)")
|
||||
@Excel(name = "体积(CBM)")
|
||||
private BigDecimal totalVolume;
|
||||
|
||||
@ApiModelProperty("退保总额(占位字段,后端暂无数据来源,恒为 null)")
|
||||
@Excel(name = "退保总额")
|
||||
private BigDecimal depositRefundAmount;
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
package com.mhd.wms.domain.outboundRank.repository.todo;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 出库排名统计(明细)查询DO
|
||||
*
|
||||
* <p>topOrganizationId / warehouseId 由服务端按登录用户注入,前端不传</p>
|
||||
*
|
||||
* @author rcx
|
||||
* @date 2026-08-31
|
||||
*/
|
||||
@Data
|
||||
public class OutboundRankDO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ApiModelProperty("出库日期-开始 yyyy-MM-dd(必填)")
|
||||
private String createTimeStart;
|
||||
|
||||
@ApiModelProperty("出库日期-结束 yyyy-MM-dd(必填)")
|
||||
private String createTimeEnd;
|
||||
|
||||
@ApiModelProperty("仓单编号/出库单号(模糊)")
|
||||
private String outOrderNumber;
|
||||
|
||||
@ApiModelProperty("入库单号(模糊)")
|
||||
private String inOrderNumber;
|
||||
|
||||
@ApiModelProperty("商品货号(模糊)")
|
||||
private String materialCode;
|
||||
|
||||
@ApiModelProperty("货名/商品名称(模糊)")
|
||||
private String materialName;
|
||||
|
||||
@ApiModelProperty("线路编码(模糊)")
|
||||
private String lineCode;
|
||||
|
||||
@ApiModelProperty("线路名称(模糊)")
|
||||
private String lineName;
|
||||
|
||||
@ApiModelProperty("仓库名称(模糊)")
|
||||
private String warehouseName;
|
||||
|
||||
@ApiModelProperty("客户名称(模糊)")
|
||||
private String customerName;
|
||||
|
||||
@ApiModelProperty("货主名称(模糊)")
|
||||
private String shipperName;
|
||||
|
||||
@ApiModelProperty("一级组织表ID(登录用户隔离,非1时注入)")
|
||||
private Long topOrganizationId;
|
||||
|
||||
@ApiModelProperty("仓库id(按用户关联仓库注入)")
|
||||
private Long warehouseId;
|
||||
}
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
package com.mhd.wms.domain.outboundRank.service;
|
||||
|
||||
import com.mhd.wms.domain.outboundRank.repository.facade.IOutboundRankService;
|
||||
import com.mhd.wms.domain.outboundRank.repository.po.OutboundDetailRankTotalPO;
|
||||
import com.mhd.wms.domain.outboundRank.repository.po.OutboundLineRankPO;
|
||||
import com.mhd.wms.domain.outboundRank.repository.po.OutboundMaterialRankPO;
|
||||
import com.mhd.wms.domain.outboundRank.repository.todo.OutboundRankDO;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 出库排名统计领域服务
|
||||
*
|
||||
* @author rcx
|
||||
* @date 2026-08-31
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class OutboundRankDomainService {
|
||||
|
||||
@Autowired
|
||||
private IOutboundRankService outboundRankService;
|
||||
|
||||
/**
|
||||
* 商品出库排名列表(货品聚合)
|
||||
*/
|
||||
public List<OutboundMaterialRankPO> queryMaterialRankList(OutboundRankDO outboundRankDO) {
|
||||
return outboundRankService.queryMaterialRankList(outboundRankDO);
|
||||
}
|
||||
|
||||
/**
|
||||
* 商品出库排名合计(不分页)
|
||||
*/
|
||||
public OutboundDetailRankTotalPO queryMaterialRankTotal(OutboundRankDO outboundRankDO) {
|
||||
return outboundRankService.queryMaterialRankTotal(outboundRankDO);
|
||||
}
|
||||
|
||||
/**
|
||||
* 线路出库排名列表(线路×货品聚合)
|
||||
*/
|
||||
public List<OutboundLineRankPO> queryLineRankList(OutboundRankDO outboundRankDO) {
|
||||
return outboundRankService.queryLineRankList(outboundRankDO);
|
||||
}
|
||||
|
||||
/**
|
||||
* 线路出库排名合计(不分页)
|
||||
*/
|
||||
public OutboundDetailRankTotalPO queryLineRankTotal(OutboundRankDO outboundRankDO) {
|
||||
return outboundRankService.queryLineRankTotal(outboundRankDO);
|
||||
}
|
||||
}
|
||||
+8
-4
@@ -401,7 +401,8 @@ public class PickingOrderDomainService {
|
||||
// 拣货提交(/pickingOrderApi/picking)一次拣满也会完成拣货,此前仅 completePicking 会生成复核单,此处对齐
|
||||
if (Boolean.TRUE.equals(updated) && Integer.valueOf(1).equals(pickingOrderPODb.getType())) {
|
||||
StockOutOrder stockOutOrder = stockOutOrderService.getOne(new LambdaQueryWrapper<StockOutOrder>()
|
||||
.eq(StockOutOrder::getOutOrderNumber, pickingOrderPODb.getOrderNumber()));
|
||||
.eq(StockOutOrder::getOutOrderNumber, pickingOrderPODb.getOrderNumber())
|
||||
.eq(StockOutOrder::getDelFlag,1));
|
||||
if (stockOutOrder != null) {
|
||||
Long newReviewId = reviewOrderDomainService.tryGenerateReviewOrderAfterPickingComplete(pickingOrderPODb, stockOutOrder);
|
||||
if (newReviewId != null) {
|
||||
@@ -493,7 +494,8 @@ public class PickingOrderDomainService {
|
||||
int status = 6;
|
||||
//不需要复核的单子 标记出库单完成
|
||||
StockOutOrder stockOutOrderDb = stockOutOrderService.getOne(new QueryWrapper<StockOutOrder>().lambda()
|
||||
.eq(StockOutOrder::getOutOrderNumber, pickingOrderPODb.getOrderNumber()));
|
||||
.eq(StockOutOrder::getOutOrderNumber, pickingOrderPODb.getOrderNumber())
|
||||
.eq(StockOutOrder::getDelFlag,1));
|
||||
// 与下发拣货数量比较:只下发部分时用拣货计划数量,否则用出库单总数量
|
||||
List<PickingOrder> allPickingOrders = pickingOrderService.list(new QueryWrapper<PickingOrder>().lambda()
|
||||
.eq(PickingOrder::getDelFlag, 1)
|
||||
@@ -522,7 +524,9 @@ public class PickingOrderDomainService {
|
||||
List<PickingMaterialDetail> list = pickingMaterialDetailService.list(new QueryWrapper<PickingMaterialDetail>().lambda().eq(PickingMaterialDetail::getPickingOrderNumber, pickingOrder.getPickingOrderNumber()));
|
||||
|
||||
for (PickingMaterialDetail pickingMaterialDetail :list){
|
||||
OutMaterialDetail outMaterialDetail = outMaterialDetailMapper.selectOne(new QueryWrapper<OutMaterialDetail>().lambda().eq(OutMaterialDetail::getUniqueId, pickingMaterialDetail.getOutUniqueId()));
|
||||
OutMaterialDetail outMaterialDetail = outMaterialDetailMapper.selectOne(new QueryWrapper<OutMaterialDetail>().lambda()
|
||||
.eq(OutMaterialDetail::getUniqueId, pickingMaterialDetail.getOutUniqueId())
|
||||
.eq(OutMaterialDetail::getDelFlag,1));
|
||||
outMaterialDetail.setPickingQuantity(pickingMaterialDetail.getPickingQuantity());
|
||||
outMaterialDetailMapper.updateById(outMaterialDetail);
|
||||
}
|
||||
@@ -734,7 +738,7 @@ public class PickingOrderDomainService {
|
||||
throw new ServiceException("拣货单不存在");
|
||||
}
|
||||
LambdaQueryWrapper<StockOutOrder> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.eq(StockOutOrder::getOutOrderNumber, pickingOrderPO.getOrderNumber());
|
||||
queryWrapper.eq(StockOutOrder::getDelFlag,1).eq(StockOutOrder::getOutOrderNumber, pickingOrderPO.getOrderNumber());
|
||||
StockOutOrder stockOutOrder = stockOutOrderService.getOne(queryWrapper);
|
||||
if(null == stockOutOrder){
|
||||
throw new ServiceException("出库单不存在");
|
||||
|
||||
+2
-1
@@ -260,7 +260,8 @@ public class ReviewOrderDomainService {
|
||||
.eq(OutMaterialDetail::getDelFlag, 1));
|
||||
if (outMd == null) {
|
||||
outMd = outMaterialDetailMapper.selectOne(new LambdaQueryWrapper<OutMaterialDetail>()
|
||||
.eq(OutMaterialDetail::getUniqueId, line.getOutUniqueId()));
|
||||
.eq(OutMaterialDetail::getUniqueId, line.getOutUniqueId())
|
||||
.eq(OutMaterialDetail::getDelFlag, 1));
|
||||
}
|
||||
if (outMd != null) {
|
||||
d.setMaterialDetailId(outMd.getMaterialDetailId());
|
||||
|
||||
@@ -48,7 +48,7 @@ public class PushSyncBmsDomainService {
|
||||
public void pushInShelfOrder(String inOrderNumber) {
|
||||
// 根据入库单号,查询入库单信息,并拼接推送所需参数
|
||||
LambdaQueryWrapper<StockInOrder> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.eq(StockInOrder::getInOrderNumber, inOrderNumber);
|
||||
queryWrapper.eq(StockInOrder::getInOrderNumber, inOrderNumber).eq(StockInOrder::getDelFlag,1);
|
||||
StockInOrder stockInOrder = iStockInOrderService.getOne(queryWrapper);
|
||||
if(null == stockInOrder){
|
||||
throw new ServiceException("入库单信息未找到");
|
||||
@@ -96,7 +96,7 @@ public class PushSyncBmsDomainService {
|
||||
*/
|
||||
public void pushOutOrder(String outOrderNumber) {
|
||||
LambdaQueryWrapper<StockOutOrder> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.eq(StockOutOrder::getOutOrderNumber, outOrderNumber);
|
||||
queryWrapper.eq(StockOutOrder::getOutOrderNumber, outOrderNumber).eq(StockOutOrder::getDelFlag,1);
|
||||
StockOutOrder stockOutOrder = iStockOutOrderService.getOne(queryWrapper);
|
||||
if(null == stockOutOrder){
|
||||
throw new ServiceException("出库单信息未找到");
|
||||
@@ -153,4 +153,4 @@ public class PushSyncBmsDomainService {
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
+5
@@ -286,6 +286,11 @@ public class ReceiptMaterialDetail extends BaseVOEntity {
|
||||
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
|
||||
private Date inventoryDate;
|
||||
|
||||
@ApiModelProperty("进货日期")
|
||||
@Excel(name = "进货日期", width = 30, dateFormat = "yyyy-MM-dd")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
|
||||
private Date purchaseDate;
|
||||
|
||||
@ApiModelProperty("扩展属性1")
|
||||
@Excel(name = "扩展属性1")
|
||||
@TableField("ext_attr_1")
|
||||
|
||||
+31
-8
@@ -743,14 +743,19 @@ public class ReceiptMaterialDetailImpl extends ServiceImpl<ReceiptMaterialDetail
|
||||
}
|
||||
//receiptMaterialDetailDO.setExtAttr4(date);
|
||||
} else if ("饮用日期".equals(batchLabels)) {
|
||||
// SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
// Date date = null;
|
||||
// try {
|
||||
// date = sdf.parse(attributeValue);
|
||||
// } catch (ParseException e) {
|
||||
// throw new RuntimeException(e);
|
||||
// }
|
||||
// receiptMaterialDetailDO.setInventoryDate(date);
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
|
||||
Date date = null;
|
||||
try {
|
||||
date = sdf.parse(attributeValue);
|
||||
} catch (ParseException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
receiptMaterialDetailDO.setDrinkDate(date);
|
||||
// 过期日期未单独填写时,饮用日期兜底作为过期日期(与收货单生成时的转换逻辑保持一致),
|
||||
// 避免只填饮用日期导致库存过期日期为空不回显
|
||||
if (receiptMaterialDetailDO.getExpiryDate() == null) {
|
||||
receiptMaterialDetailDO.setExpiryDate(date);
|
||||
}
|
||||
} else if ("扩展属性2".equals(batchLabels)) {
|
||||
receiptMaterialDetailDO.setExtAttr2(attributeValue);
|
||||
} else if ("扩展属性1".equals(batchLabels)) {
|
||||
@@ -770,6 +775,15 @@ public class ReceiptMaterialDetailImpl extends ServiceImpl<ReceiptMaterialDetail
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
receiptMaterialDetailDO.setInventoryDate(date);
|
||||
} else if ("进货日期".equals(batchLabels)) {
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
|
||||
Date date = null;
|
||||
try {
|
||||
date = sdf.parse(attributeValue);
|
||||
} catch (ParseException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
receiptMaterialDetailDO.setPurchaseDate(date);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1274,6 +1288,15 @@ public class ReceiptMaterialDetailImpl extends ServiceImpl<ReceiptMaterialDetail
|
||||
log.warn("库存日期格式转换失败,物料:{},原始值:{}", receiptMaterialDetailDO.getMaterialName(), attributeValue);
|
||||
}
|
||||
break;
|
||||
case "进货日期":
|
||||
try {
|
||||
if (attributeValue.matches("\\d{4}-\\d{2}-\\d{2}.*")) {
|
||||
receiptMaterialDetailDO.setPurchaseDate(DateUtils.parseDate(attributeValue));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.warn("进货日期格式转换失败,物料:{},原始值:{}", receiptMaterialDetailDO.getMaterialName(), attributeValue);
|
||||
}
|
||||
break;
|
||||
case "总净重":
|
||||
case "净重(KG)":
|
||||
case "净重":
|
||||
|
||||
+5
@@ -316,6 +316,11 @@ public class ReceiptMaterialDetailPO extends BaseVOEntity {
|
||||
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
|
||||
private Date inventoryDate;
|
||||
|
||||
@ApiModelProperty("进货日期")
|
||||
@Excel(name = "进货日期", width = 30, dateFormat = "yyyy-MM-dd")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
|
||||
private Date purchaseDate;
|
||||
|
||||
@ApiModelProperty("扩展属性1")
|
||||
@Excel(name = "扩展属性1")
|
||||
private String extAttr1;
|
||||
|
||||
+5
@@ -300,6 +300,11 @@ public class ReceiptMaterialDetailDO extends BaseVOEntity {
|
||||
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
|
||||
private Date inventoryDate;
|
||||
|
||||
@ApiModelProperty("进货日期")
|
||||
@Excel(name = "进货日期", width = 30, dateFormat = "yyyy-MM-dd")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
|
||||
private Date purchaseDate;
|
||||
|
||||
@ApiModelProperty("扩展属性1")
|
||||
@Excel(name = "扩展属性1")
|
||||
private String extAttr1;
|
||||
|
||||
+7
@@ -301,6 +301,13 @@ public class ShelfMaterialDetail extends BaseVOEntity {
|
||||
@TableField("inventory_date")
|
||||
private Date inventoryDate;
|
||||
|
||||
@ApiModelProperty("进货日期")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@Excel(name = "进货日期", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
|
||||
@TableField("purchase_date")
|
||||
private Date purchaseDate;
|
||||
|
||||
@ApiModelProperty("ExtAttr3")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
|
||||
+6
@@ -313,6 +313,12 @@ public class ShelfMaterialDetailDO extends BaseVOEntity {
|
||||
@Excel(name = "存货日期", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date inventoryDate;
|
||||
|
||||
@ApiModelProperty("进货日期")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@Excel(name = "进货日期", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date purchaseDate;
|
||||
|
||||
@ApiModelProperty("ExtAttr3")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
|
||||
+5
-2
@@ -20,6 +20,7 @@ import com.mhd.wms.domain.materialInventory.repository.facade.IMaterialInventory
|
||||
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.outMaterialDetail.entity.OutMaterialDetail;
|
||||
import com.mhd.wms.domain.outMaterialDetailSerialNumber.entity.OutMaterialDetailSerialNumber;
|
||||
import com.mhd.wms.domain.outMaterialDetailSerialNumber.repository.facade.IOutMaterialDetailSerialNumberService;
|
||||
import com.mhd.wms.domain.outMaterialDetailSerialNumber.repository.todo.OutMaterialDetailSerialNumberDO;
|
||||
@@ -153,7 +154,9 @@ public class ShiftMaterialDetailImpl extends ServiceImpl<ShiftMaterialDetailMapp
|
||||
public ShiftMaterialDetailPO getInfo(Long shiftIoDetailId) {
|
||||
LambdaQueryWrapper<ShiftMaterialDetail> lqw = new LambdaQueryWrapper<>();
|
||||
// 按照物料名称排序
|
||||
lqw.eq(ShiftMaterialDetail::getShiftIoDetailId, shiftIoDetailId).orderByAsc(ShiftMaterialDetail::getMaterialName);
|
||||
lqw.eq(ShiftMaterialDetail::getShiftIoDetailId, shiftIoDetailId)
|
||||
.eq(ShiftMaterialDetail::getDelFlag, 1)
|
||||
.orderByAsc(ShiftMaterialDetail::getMaterialName);
|
||||
ShiftMaterialDetail shiftMaterialDetail = shiftMaterialDetailMapper.selectOne(lqw);
|
||||
ShiftMaterialDetailPO shiftMaterialDetailPO = new ShiftMaterialDetailPO();
|
||||
BeanUtils.copyProperties(shiftMaterialDetail, shiftMaterialDetailPO);
|
||||
@@ -888,4 +891,4 @@ public class ShiftMaterialDetailImpl extends ServiceImpl<ShiftMaterialDetailMapp
|
||||
}
|
||||
return outMaterialDetailSerialNumberList;
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
-5
@@ -233,8 +233,9 @@ public class SowingDistributionDetailsImpl extends ServiceImpl<SowingDistributio
|
||||
if (outMaterialDetailSerialNumber == null){
|
||||
throw new ServiceException("序列号不存在");
|
||||
}
|
||||
OutMaterialDetail outMaterialDetail = outMaterialDetailMapper.selectOne(new QueryWrapper<OutMaterialDetail>().lambda().
|
||||
eq(OutMaterialDetail::getUniqueId, outMaterialDetailSerialNumber.getMaterialDetailUniqueId()));
|
||||
OutMaterialDetail outMaterialDetail = outMaterialDetailMapper.selectOne(new QueryWrapper<OutMaterialDetail>().lambda()
|
||||
.eq(OutMaterialDetail::getDelFlag,1)
|
||||
.eq(OutMaterialDetail::getUniqueId, outMaterialDetailSerialNumber.getMaterialDetailUniqueId()));
|
||||
if (outMaterialDetail == null){
|
||||
throw new ServiceException("物料不存在");
|
||||
}
|
||||
@@ -273,7 +274,9 @@ public class SowingDistributionDetailsImpl extends ServiceImpl<SowingDistributio
|
||||
*/
|
||||
@Override
|
||||
public List<SowingDistributionDetailsPO> allocationByOrder(AllocationByOrderDO allocationByOrderDO) {
|
||||
StockOutOrder stockOutOrder = stockOutOrderMapper.selectOne(new QueryWrapper<StockOutOrder>().lambda().eq(StockOutOrder::getOutOrderNumber, allocationByOrderDO.getOutOrderNumber()));
|
||||
StockOutOrder stockOutOrder = stockOutOrderMapper.selectOne(new QueryWrapper<StockOutOrder>().lambda()
|
||||
.eq(StockOutOrder::getOutOrderNumber, allocationByOrderDO.getOutOrderNumber())
|
||||
.eq(StockOutOrder::getDelFlag,1));
|
||||
if (stockOutOrder == null){
|
||||
throw new ServiceException("出库单不存在");
|
||||
}
|
||||
@@ -306,7 +309,9 @@ public class SowingDistributionDetailsImpl extends ServiceImpl<SowingDistributio
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public SowingDistributionDetailsPO materialScanCodeAllocationByOrder(AllocationByOrderDO allocationByOrderDO) {
|
||||
StockOutOrder stockOutOrder = stockOutOrderMapper.selectOne(new QueryWrapper<StockOutOrder>().lambda().eq(StockOutOrder::getOutOrderNumber, allocationByOrderDO.getOutOrderNumber()));
|
||||
StockOutOrder stockOutOrder = stockOutOrderMapper.selectOne(new QueryWrapper<StockOutOrder>().lambda()
|
||||
.eq(StockOutOrder::getOutOrderNumber, allocationByOrderDO.getOutOrderNumber())
|
||||
.eq(StockOutOrder::getDelFlag,1));
|
||||
if (stockOutOrder == null){
|
||||
throw new ServiceException("出库单不存在");
|
||||
}
|
||||
@@ -356,4 +361,4 @@ public class SowingDistributionDetailsImpl extends ServiceImpl<SowingDistributio
|
||||
sowingDistributionDetailsPO.setRatioQuantity(ratioQuantity);
|
||||
return sowingDistributionDetailsPO;
|
||||
}
|
||||
}
|
||||
}
|
||||
+17
-21
@@ -112,8 +112,7 @@ public class ExcelParseService {
|
||||
LoginUser loginUser = SecurityUtils.getLoginUser();
|
||||
Long topOrganizationId = loginUser != null && loginUser.getUserPo() != null
|
||||
? loginUser.getUserPo().getTopOrganizationId() : null;
|
||||
StringBuilder materialConsistencyErrors = new StringBuilder();
|
||||
initList(itemList, warehouseId, warehouseCode, warehouseName, shipperId, topOrganizationId, materialConsistencyErrors);
|
||||
initList(itemList, warehouseId, warehouseCode, warehouseName, shipperId, topOrganizationId);
|
||||
stockOutOrder.setMaterialDetailList(itemList);
|
||||
stockOutOrder.setWarehouseName(warehouseName);
|
||||
stockOutOrder.setWarehouseCode(warehouseCode);
|
||||
@@ -171,10 +170,6 @@ public class ExcelParseService {
|
||||
for (String dateError : headerListener.getDateParseErrors()) {
|
||||
errorMsg.append(dateError).append("; ");
|
||||
}
|
||||
// 物料一致性校验错误与必填校验错误合并,任一有错都不落库
|
||||
if (materialConsistencyErrors.length() > 0) {
|
||||
errorMsg.insert(0, materialConsistencyErrors);
|
||||
}
|
||||
if (errorMsg.length() > 0) {
|
||||
return errorMsg;
|
||||
} else {
|
||||
@@ -425,7 +420,8 @@ public class ExcelParseService {
|
||||
* @param shipperId 货主ID(用于过滤物料基础信息,确保查询到的是该货主绑定的物料)
|
||||
* @param topOrganizationId 一级组织ID(用于过滤物料基础信息)
|
||||
*/
|
||||
private void initList(List<OutMaterialDetailDO> outMaterialDetailDOList, Long warehouseId, String warehouseCode, String warehouseName, Long shipperId, Long topOrganizationId, StringBuilder materialConsistencyErrors) { for (OutMaterialDetailDO outMaterialDetailDO : outMaterialDetailDOList) {
|
||||
private void initList(List<OutMaterialDetailDO> outMaterialDetailDOList, Long warehouseId, String warehouseCode, String warehouseName, Long shipperId, Long topOrganizationId) {
|
||||
for (OutMaterialDetailDO outMaterialDetailDO : outMaterialDetailDOList) {
|
||||
outMaterialDetailDO.setWarehouseId(warehouseId);
|
||||
outMaterialDetailDO.setWarehouseCode(warehouseCode);
|
||||
outMaterialDetailDO.setWarehouseName(warehouseName);
|
||||
@@ -457,25 +453,25 @@ public class ExcelParseService {
|
||||
if (materialList != null && !materialList.isEmpty()) {
|
||||
materialBaseInfoPO = materialList.get(0);
|
||||
materialBaseInfoId = materialBaseInfoPO.getMaterialBaseInfoId();
|
||||
// ==== 新增:料号与规格型号/SKU码一致性校验(档案有值就必须一致,Excel留空视为不一致;档案为空跳过)====
|
||||
BigDecimal unitPrice = materialBaseInfoPO.getUnitPrice();
|
||||
outMaterialDetailDO.setUnitPrice(unitPrice);
|
||||
// ==== 料号与规格型号/SKU码一致性校验:任何一项不符直接报对应错误 ====
|
||||
// 双方(trim后)必须完全一致:Excel留空而档案有值、或Excel填了值而档案为空,均视为不一致报错
|
||||
String excelSpec = StringUtils.trimToEmpty(outMaterialDetailDO.getSpecificationModel());
|
||||
if (StringUtils.isNotBlank(materialBaseInfoPO.getSpecificationModel())
|
||||
&& !excelSpec.equals(materialBaseInfoPO.getSpecificationModel().trim())) {
|
||||
materialConsistencyErrors.append("料号「").append(outMaterialDetailDO.getMaterialNo())
|
||||
.append("」规格型号与物料档案不一致(Excel:").append(excelSpec.isEmpty() ? "空" : excelSpec)
|
||||
.append(" / 档案:").append(materialBaseInfoPO.getSpecificationModel().trim()).append("); ");
|
||||
String dbSpec = StringUtils.trimToEmpty(materialBaseInfoPO.getSpecificationModel());
|
||||
if (!excelSpec.equals(dbSpec)) {
|
||||
throw new ServiceException(String.format("导入失败:料号「%s」规格型号与物料档案不一致(Excel:%s / 档案:%s)",
|
||||
materialNo, excelSpec.isEmpty() ? "空" : excelSpec, dbSpec.isEmpty() ? "空" : dbSpec));
|
||||
}
|
||||
String excelSku = StringUtils.trimToEmpty(outMaterialDetailDO.getSkucode());
|
||||
if (StringUtils.isNotBlank(materialBaseInfoPO.getBarCode())
|
||||
&& !excelSku.equals(materialBaseInfoPO.getBarCode().trim())) {
|
||||
materialConsistencyErrors.append("料号「").append(outMaterialDetailDO.getMaterialNo())
|
||||
.append("」SKU码与物料档案不一致(Excel:").append(excelSku.isEmpty() ? "空" : excelSku)
|
||||
.append(" / 档案:").append(materialBaseInfoPO.getBarCode().trim()).append("); ");
|
||||
String dbSku = StringUtils.trimToEmpty(materialBaseInfoPO.getBarCode());
|
||||
if (!excelSku.equals(dbSku)) {
|
||||
throw new ServiceException(String.format("导入失败:料号「%s」SKU码与物料档案不一致(Excel:%s / 档案:%s)",
|
||||
materialNo, excelSku.isEmpty() ? "空" : excelSku, dbSku.isEmpty() ? "空" : dbSku));
|
||||
}
|
||||
}else {
|
||||
} else {
|
||||
// 料号已填写但在该货主下查不到 → 直接报错(与入库导入一致),不再被SKU码/商品名称静默兜底
|
||||
materialConsistencyErrors.append("料号「").append(materialNo)
|
||||
.append("」在当前客户(货主)下不存在,请核对料号或在物料管理中维护;");
|
||||
throw new ServiceException(String.format("导入失败:料号「%s」在当前客户(货主)下不存在,请核对料号或在物料管理中维护", materialNo));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+45
-10
@@ -1436,7 +1436,10 @@ public class StockOutOrderDomainService {
|
||||
stockOutOrderService.update(stockOutOrder, new UpdateWrapper<StockOutOrder>().lambda().in(StockOutOrder::getOutOrderId, stockOutOrderId));
|
||||
|
||||
List<String> stockOutOrderNumber = stockOutOrderList.stream().map(StockOutOrder::getOutOrderNumber).collect(Collectors.toList());
|
||||
List<OutMaterialDetail> list = outMaterialDetailService.list(new QueryWrapper<OutMaterialDetail>().lambda().in(OutMaterialDetail::getOutOrderNumber, stockOutOrderNumber).eq(OutMaterialDetail::getGenPickingOrder, 2));
|
||||
List<OutMaterialDetail> list = outMaterialDetailService.list(new QueryWrapper<OutMaterialDetail>().lambda()
|
||||
.in(OutMaterialDetail::getOutOrderNumber, stockOutOrderNumber)
|
||||
.eq(OutMaterialDetail::getGenPickingOrder, 2)
|
||||
.eq(OutMaterialDetail::getDelFlag, 1));
|
||||
if (CollectionUtils.isEmpty(list)){
|
||||
throw new ServiceException("不存在已分配且未生成拣货单的物料明细,无法生成拣货单!");
|
||||
}
|
||||
@@ -2542,12 +2545,20 @@ public class StockOutOrderDomainService {
|
||||
private static final String OMS_AUTO_AUDIT_REMARK = "OMS下发自动审核";
|
||||
|
||||
public void omsOrderAdd(StockOutOrder stockOutOrder) {
|
||||
//幂等保护:重复下发时同单号活动单已存在则跳过,避免插入重复出库单(下发失败重试场景此前会产生重复数据)
|
||||
StockOutOrder existOrder = stockOutOrderService.getOne(new QueryWrapper<StockOutOrder>().lambda()
|
||||
.eq(StockOutOrder::getOutOrderNumber, stockOutOrder.getOutOrderNumber())
|
||||
.eq(StockOutOrder::getDelFlag, 1), false);
|
||||
if (existOrder != null) {
|
||||
return;
|
||||
}
|
||||
// 任务下发用户id
|
||||
String userId = stockInOrderMapper.queryWarehouseUserId(stockOutOrder.getOrganizationId(), stockOutOrder.getWarehouseId(), stockOutOrder.getTopOrganizationId());
|
||||
stockOutOrder.setTaskIssueUserId(userId);
|
||||
stockOutOrderService.save(stockOutOrder);
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void cancelExecutionOrder(StockOutOrder stockOutOrder) {
|
||||
String outOrderNumber = stockOutOrder.getOutOrderNumber();
|
||||
StockOutOrder stockOutOrderDB = stockOutOrderService.getOne(new LambdaQueryWrapper<StockOutOrder>()
|
||||
@@ -2556,23 +2567,33 @@ public class StockOutOrderDomainService {
|
||||
if (stockOutOrderDB == null) {
|
||||
throw new ServiceException("出库单不存在");
|
||||
}
|
||||
//逻辑删除配送明细(放在最前:所有清理路径——含下方无明细提前返回——统一先清配送明细,避免残留)
|
||||
deliveryDetailsLinkService.update(new UpdateWrapper<com.mhd.wms.domain.deliveryDetailsLink.entity.DeliveryDetailsLink>().lambda()
|
||||
.set(com.mhd.wms.domain.deliveryDetailsLink.entity.DeliveryDetailsLink::getDelFlag, 2)
|
||||
.eq(com.mhd.wms.domain.deliveryDetailsLink.entity.DeliveryDetailsLink::getOrderNumber, outOrderNumber)
|
||||
.eq(com.mhd.wms.domain.deliveryDetailsLink.entity.DeliveryDetailsLink::getDelFlag, 1));
|
||||
List<OutMaterialDetail> materialDetails = outMaterialDetailService.list(new LambdaQueryWrapper<OutMaterialDetail>()
|
||||
.eq(OutMaterialDetail::getOutOrderNumber, outOrderNumber)
|
||||
.eq(OutMaterialDetail::getDelFlag, 1));
|
||||
if (CollectionUtils.isEmpty(materialDetails)) {
|
||||
throw new ServiceException("出库单明细不存在");
|
||||
//无明细(下发中途失败的补偿清理场景):没有可还原的库存,直接逻辑删除单头即可
|
||||
stockOutOrderDB.setDelFlag(2);
|
||||
stockOutOrderService.updateById(stockOutOrderDB);
|
||||
return;
|
||||
}
|
||||
for (OutMaterialDetail materialDetail : materialDetails) {
|
||||
//还原库存
|
||||
BigDecimal allocationQuantity = materialDetail.getAllocationQuantity();
|
||||
Long materialInventoryId = materialDetail.getMaterialInventoryId();
|
||||
MaterialInventory materialInventory = materialInventoryMapper.selectById(materialInventoryId);
|
||||
if (materialInventory == null) {
|
||||
throw new ServiceException("库存信息不存在");
|
||||
//以下两种情况都无可还原的冻结量,跳过还原直接删单,保证此类单据也能被取消/补偿清理:
|
||||
//1.库存不存在(如OMS漏传库存ID的历史脏单);
|
||||
//2.未分配的明细(allocationQuantity为空或0,如下发失败后的补偿清理)
|
||||
if (materialInventory != null && allocationQuantity != null && allocationQuantity.compareTo(BigDecimal.ZERO) > 0) {
|
||||
materialInventory.setAllocationQuantity((materialInventory.getAllocationQuantity() == null ? BigDecimal.ZERO : materialInventory.getAllocationQuantity()).add(allocationQuantity));
|
||||
materialInventory.setFreezeQuantity((materialInventory.getFreezeQuantity() == null ? BigDecimal.ZERO : materialInventory.getFreezeQuantity()).subtract(allocationQuantity));
|
||||
materialInventoryMapper.updateById(materialInventory);
|
||||
}
|
||||
materialInventory.setAllocationQuantity(materialInventory.getAllocationQuantity().add(allocationQuantity));
|
||||
materialInventory.setFreezeQuantity(materialInventory.getFreezeQuantity().subtract(allocationQuantity));
|
||||
materialInventoryMapper.updateById(materialInventory);
|
||||
//逻辑删除库存调整记录
|
||||
Long uniqueId = materialDetail.getUniqueId();
|
||||
String relateNo = outOrderNumber+"#"+uniqueId;
|
||||
@@ -2583,9 +2604,9 @@ public class StockOutOrderDomainService {
|
||||
materialDetail.setDelFlag(2);
|
||||
outMaterialDetailService.updateById(materialDetail);
|
||||
}
|
||||
//逻辑删除出库单
|
||||
stockOutOrder.setDelFlag(2);
|
||||
stockOutOrderService.updateById(stockOutOrder);
|
||||
//逻辑删除出库单(用按单号查出的DB对象更新:OMS补偿清理只传单号,传入对象无主键,直接updateById不生效)
|
||||
stockOutOrderDB.setDelFlag(2);
|
||||
stockOutOrderService.updateById(stockOutOrderDB);
|
||||
|
||||
PickingOrder pickingOrder = pickingOrderService.getOne(new LambdaQueryWrapper<PickingOrder>()
|
||||
.eq(PickingOrder::getDelFlag, 1)
|
||||
@@ -2599,6 +2620,7 @@ public class StockOutOrderDomainService {
|
||||
pickingMaterialDetail.setDelFlag(2);
|
||||
pickingMaterialDetailService.updateById(pickingMaterialDetail);
|
||||
}
|
||||
pickingOrder.setDelFlag(2);
|
||||
pickingOrderService.updateById(pickingOrder);
|
||||
}
|
||||
}
|
||||
@@ -2608,6 +2630,11 @@ public class StockOutOrderDomainService {
|
||||
if (CollectionUtils.isEmpty(outMaterialDetails)) {
|
||||
return;
|
||||
}
|
||||
//幂等保护:重复下发时先逻辑删除同单号已存在的活动明细,避免重复插入导致分配/拣货数据错乱
|
||||
outMaterialDetailService.update(new UpdateWrapper<OutMaterialDetail>().lambda()
|
||||
.set(OutMaterialDetail::getDelFlag, 2)
|
||||
.eq(OutMaterialDetail::getOutOrderNumber, outMaterialDetails.get(0).getOutOrderNumber())
|
||||
.eq(OutMaterialDetail::getDelFlag, 1));
|
||||
outMaterialDetailService.saveBatch(outMaterialDetails);
|
||||
autoAuditOmsOutOrder(outMaterialDetails.get(0).getOutOrderNumber());
|
||||
}
|
||||
@@ -2617,6 +2644,14 @@ public class StockOutOrderDomainService {
|
||||
if (CollectionUtils.isEmpty(deliveryDetailsLinks)) {
|
||||
return;
|
||||
}
|
||||
//幂等保护:重复下发时先逻辑删除同单号已存在的配送明细,避免重复插入
|
||||
String firstOrderNumber = deliveryDetailsLinks.get(0).getOrderNumber();
|
||||
if (StringUtils.isNotEmpty(firstOrderNumber)) {
|
||||
deliveryDetailsLinkService.update(new UpdateWrapper<com.mhd.wms.domain.deliveryDetailsLink.entity.DeliveryDetailsLink>().lambda()
|
||||
.set(com.mhd.wms.domain.deliveryDetailsLink.entity.DeliveryDetailsLink::getDelFlag, 2)
|
||||
.eq(com.mhd.wms.domain.deliveryDetailsLink.entity.DeliveryDetailsLink::getOrderNumber, firstOrderNumber)
|
||||
.eq(com.mhd.wms.domain.deliveryDetailsLink.entity.DeliveryDetailsLink::getDelFlag, 1));
|
||||
}
|
||||
for (DeliveryDetailsLink deliveryDetailsLink : deliveryDetailsLinks) {
|
||||
com.mhd.wms.domain.deliveryDetailsLink.entity.DeliveryDetailsLink deliveryDetailsLinkEntity = new com.mhd.wms.domain.deliveryDetailsLink.entity.DeliveryDetailsLink();
|
||||
BeanUtils.copyProperties(deliveryDetailsLink, deliveryDetailsLinkEntity);
|
||||
|
||||
+5
-2
@@ -865,7 +865,9 @@ public class StockOutTaskOrderDomainService {
|
||||
pickingOrderDO.setUpdateByName(loginUser.getUsername());
|
||||
pickingOrderDO.setUpdateTime(new Date());
|
||||
pickingOrderService.addQuantity(pickingOrderDO);
|
||||
PickingOrder onePickingOrder = pickingOrderService.getOne(new QueryWrapper<PickingOrder>().lambda().eq(PickingOrder::getPickingOrderNumber, stockOutTaskOrderPODb.getPickingOrderNumber()));
|
||||
PickingOrder onePickingOrder = pickingOrderService.getOne(new QueryWrapper<PickingOrder>().lambda()
|
||||
.eq(PickingOrder::getPickingOrderNumber, stockOutTaskOrderPODb.getPickingOrderNumber())
|
||||
.eq(PickingOrder::getDelFlag,1));
|
||||
PickingOrderPO pickingOrderPODb = pickingOrderService.getInfoByIdAndType(onePickingOrder.getPickingOrderId(), onePickingOrder.getType());
|
||||
return updateStockOutOrder(pickingOrderPODb);
|
||||
}
|
||||
@@ -938,6 +940,7 @@ public class StockOutTaskOrderDomainService {
|
||||
// 与 PickingOrderDomainService.picking 一致:PDA 按物料拣货/作业单路径拣满时只走本方法,需触发生成复核单
|
||||
if (stockOutUpdated) {
|
||||
StockOutOrder so = stockOutOrderService.getOne(new LambdaQueryWrapper<StockOutOrder>()
|
||||
.eq(StockOutOrder::getDelFlag,1)
|
||||
.eq(StockOutOrder::getOutOrderNumber, pickingOrderPODb.getOrderNumber()));
|
||||
if (so != null) {
|
||||
Long newReviewId = reviewOrderDomainService.tryGenerateReviewOrderAfterPickingComplete(pickingOrderPODb, so);
|
||||
@@ -1068,4 +1071,4 @@ public class StockOutTaskOrderDomainService {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+9
-3
@@ -1493,6 +1493,7 @@ public class StockReceiptOrderDomainService {
|
||||
shelfMaterialDetailDO.setTotalGrossWeight(receiptMaterialDetailDO.getTotalGrossWeight());
|
||||
shelfMaterialDetailDO.setExpiryDate(receiptMaterialDetailDO.getExpiryDate());
|
||||
shelfMaterialDetailDO.setInventoryDate(receiptMaterialDetailDO.getInventoryDate());
|
||||
shelfMaterialDetailDO.setPurchaseDate(receiptMaterialDetailDO.getPurchaseDate());
|
||||
shelfMaterialDetailDO.setBatchRefNo(receiptMaterialDetailDO.getBatchRefNo());
|
||||
shelfMaterialDetailDO.setSheetRefNo(receiptMaterialDetailDO.getSheetRefNo());
|
||||
shelfMaterialDetailDO.setBoxPalletNo(receiptMaterialDetailDO.getBoxPalletNo());
|
||||
@@ -1533,6 +1534,7 @@ public class StockReceiptOrderDomainService {
|
||||
shelfMaterialDetailDOChildren.setProductionDate(receiptMaterialDetailDOChildren.getProductionDate());
|
||||
shelfMaterialDetailDOChildren.setExpiryDate(receiptMaterialDetailDOChildren.getExpiryDate());
|
||||
shelfMaterialDetailDOChildren.setInventoryDate(receiptMaterialDetailDOChildren.getInventoryDate());
|
||||
shelfMaterialDetailDOChildren.setPurchaseDate(receiptMaterialDetailDOChildren.getPurchaseDate());
|
||||
shelfMaterialDetailDOChildren.setBatchRefNo(receiptMaterialDetailDOChildren.getBatchRefNo());
|
||||
shelfMaterialDetailDOChildren.setSheetRefNo(receiptMaterialDetailDOChildren.getSheetRefNo());
|
||||
shelfMaterialDetailDOChildren.setBoxPalletNo(receiptMaterialDetailDOChildren.getBoxPalletNo());
|
||||
@@ -1634,10 +1636,11 @@ public class StockReceiptOrderDomainService {
|
||||
shelfMaterialDetailDO.setTotalVolume(receiptMaterialDetailPO.getTotalVolume());
|
||||
shelfMaterialDetailDO.setTotalNetWeight(receiptMaterialDetailPO.getTotalNetWeight());
|
||||
shelfMaterialDetailDO.setTotalGrossWeight(receiptMaterialDetailPO.getTotalGrossWeight());
|
||||
// 传递生产日期、过期日期、存货日期、Batch Ref NO's、Sheet Ref NO's、箱号/卡板号、扩展属性1-4
|
||||
// 传递生产日期、过期日期、存货日期、进货日期、Batch Ref NO's、Sheet Ref NO's、箱号/卡板号、扩展属性1-4
|
||||
shelfMaterialDetailDO.setProductionDate(receiptMaterialDetailPO.getProductionDate());
|
||||
shelfMaterialDetailDO.setExpiryDate(receiptMaterialDetailPO.getExpiryDate());
|
||||
shelfMaterialDetailDO.setInventoryDate(receiptMaterialDetailPO.getInventoryDate());
|
||||
shelfMaterialDetailDO.setPurchaseDate(receiptMaterialDetailPO.getPurchaseDate());
|
||||
shelfMaterialDetailDO.setBatchRefNo(receiptMaterialDetailPO.getBatchRefNo());
|
||||
shelfMaterialDetailDO.setSheetRefNo(receiptMaterialDetailPO.getSheetRefNo());
|
||||
shelfMaterialDetailDO.setBoxPalletNo(receiptMaterialDetailPO.getBoxPalletNo());
|
||||
@@ -1686,6 +1689,7 @@ public class StockReceiptOrderDomainService {
|
||||
shelfMaterialDetailDOChildren.setProductionDate(receiptMaterialDetailPOChildren.getProductionDate());
|
||||
shelfMaterialDetailDOChildren.setExpiryDate(receiptMaterialDetailPOChildren.getExpiryDate());
|
||||
shelfMaterialDetailDOChildren.setInventoryDate(receiptMaterialDetailPOChildren.getInventoryDate());
|
||||
shelfMaterialDetailDOChildren.setPurchaseDate(receiptMaterialDetailPOChildren.getPurchaseDate());
|
||||
shelfMaterialDetailDOChildren.setBatchRefNo(receiptMaterialDetailPOChildren.getBatchRefNo());
|
||||
shelfMaterialDetailDOChildren.setSheetRefNo(receiptMaterialDetailPOChildren.getSheetRefNo());
|
||||
shelfMaterialDetailDOChildren.setBoxPalletNo(receiptMaterialDetailPOChildren.getBoxPalletNo());
|
||||
@@ -1767,10 +1771,11 @@ public class StockReceiptOrderDomainService {
|
||||
shelfMaterialDetailDO.setQuantity(receiptMaterialDetailPO.getReceiptQuantity());
|
||||
shelfMaterialDetailDO.setInUniqueId(receiptMaterialDetailPO.getInUniqueId());
|
||||
shelfMaterialDetailDO.setReceiptUniqueId(receiptMaterialDetailPO.getUniqueId());
|
||||
// 传递生产日期、过期日期、存货日期、Batch Ref NO's、Sheet Ref NO's、箱号/卡板号、扩展属性1-4
|
||||
// 传递生产日期、过期日期、存货日期、进货日期、Batch Ref NO's、Sheet Ref NO's、箱号/卡板号、扩展属性1-4
|
||||
shelfMaterialDetailDO.setProductionDate(receiptMaterialDetailPO.getProductionDate());
|
||||
shelfMaterialDetailDO.setExpiryDate(receiptMaterialDetailPO.getExpiryDate());
|
||||
shelfMaterialDetailDO.setInventoryDate(receiptMaterialDetailPO.getInventoryDate());
|
||||
shelfMaterialDetailDO.setPurchaseDate(receiptMaterialDetailPO.getPurchaseDate());
|
||||
shelfMaterialDetailDO.setBatchRefNo(receiptMaterialDetailPO.getBatchRefNo());
|
||||
shelfMaterialDetailDO.setSheetRefNo(receiptMaterialDetailPO.getSheetRefNo());
|
||||
shelfMaterialDetailDO.setBoxPalletNo(receiptMaterialDetailPO.getBoxPalletNo());
|
||||
@@ -1809,10 +1814,11 @@ public class StockReceiptOrderDomainService {
|
||||
shelfMaterialDetailDOChildren.setInUniqueId(receiptMaterialDetailPO.getInUniqueId());
|
||||
// 子项使用自身的 uniqueId 作为 receiptUniqueId,以便正确关联 material_more_detail 中的扩展属性
|
||||
shelfMaterialDetailDOChildren.setReceiptUniqueId(receiptMaterialDetailDOChildren.getUniqueId());
|
||||
// 传递生产日期、过期日期、存货日期、Batch Ref NO's、Sheet Ref NO's、箱号/卡板号、扩展属性1-4
|
||||
// 传递生产日期、过期日期、存货日期、进货日期、Batch Ref NO's、Sheet Ref NO's、箱号/卡板号、扩展属性1-4
|
||||
shelfMaterialDetailDOChildren.setProductionDate(receiptMaterialDetailDOChildren.getProductionDate());
|
||||
shelfMaterialDetailDOChildren.setExpiryDate(receiptMaterialDetailDOChildren.getExpiryDate());
|
||||
shelfMaterialDetailDOChildren.setInventoryDate(receiptMaterialDetailDOChildren.getInventoryDate());
|
||||
shelfMaterialDetailDOChildren.setPurchaseDate(receiptMaterialDetailDOChildren.getPurchaseDate());
|
||||
shelfMaterialDetailDOChildren.setBatchRefNo(receiptMaterialDetailDOChildren.getBatchRefNo());
|
||||
shelfMaterialDetailDOChildren.setSheetRefNo(receiptMaterialDetailDOChildren.getSheetRefNo());
|
||||
shelfMaterialDetailDOChildren.setBoxPalletNo(receiptMaterialDetailDOChildren.getBoxPalletNo());
|
||||
|
||||
+24
@@ -62,6 +62,8 @@ import com.mhd.wms.domain.materialInventory.repository.po.MaterialInventoryPO;
|
||||
import com.mhd.wms.domain.materialInventory.repository.todo.MaterialInventoryDO;
|
||||
import com.mhd.wms.domain.materialInventory.repository.todo.MaterialInventoryParamDO;
|
||||
import com.mhd.wms.domain.materialMoreDetail.repository.todo.MaterialMoreDetailDO;
|
||||
import com.mhd.wms.domain.receiptMaterialDetail.entity.ReceiptMaterialDetail;
|
||||
import com.mhd.wms.domain.receiptMaterialDetail.repository.facade.IReceiptMaterialDetailService;
|
||||
import com.mhd.wms.domain.serialNumber.entity.SerialNumber;
|
||||
import com.mhd.wms.domain.serialNumber.repository.facade.ISerialNumberService;
|
||||
import com.mhd.wms.domain.shelfMaterialDetail.entity.ShelfMaterialDetail;
|
||||
@@ -148,6 +150,8 @@ public class StockShelfOrderDomainService {
|
||||
private MaterialBaseInfoMapper materialBaseInfoMapper;
|
||||
@Autowired
|
||||
private ICopyCodeReferenceService copyCodeReferenceService;
|
||||
@Autowired
|
||||
private IReceiptMaterialDetailService receiptMaterialDetailService;
|
||||
@Resource
|
||||
private OmsServiceFeign omsServiceFeign;
|
||||
|
||||
@@ -1134,6 +1138,21 @@ public class StockShelfOrderDomainService {
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
}
|
||||
// 过期日期兜底:上架明细未带过期日期时,回查收货明细补齐(优先过期日期,其次饮用日期),
|
||||
// 避免收货环节补填的效期丢失导致库存过期日期为空不回显
|
||||
if (shelfMaterialDetail.getExpiryDate() == null && shelfMaterialDetail.getReceiptUniqueId() != null) {
|
||||
ReceiptMaterialDetail receiptDetail = receiptMaterialDetailService.getOne(
|
||||
new LambdaQueryWrapper<ReceiptMaterialDetail>()
|
||||
.eq(ReceiptMaterialDetail::getUniqueId, shelfMaterialDetail.getReceiptUniqueId())
|
||||
.last("LIMIT 1"));
|
||||
if (receiptDetail != null) {
|
||||
if (receiptDetail.getExpiryDate() != null) {
|
||||
shelfMaterialDetail.setExpiryDate(receiptDetail.getExpiryDate());
|
||||
} else if (receiptDetail.getDrinkDate() != null) {
|
||||
shelfMaterialDetail.setExpiryDate(receiptDetail.getDrinkDate());
|
||||
}
|
||||
}
|
||||
}
|
||||
Long shipperId = stockReceiptOrderDO.getShipperId();
|
||||
MaterialInventory param = getParam(shelfMaterialDetail, fieldNames, shipperId,stockReceiptOrderDO.getInOrderNumber());
|
||||
List<MaterialInventoryPO> materialInventoryPOS = materialInventoryMapper.selectListByWhere(param);
|
||||
@@ -1262,6 +1281,7 @@ public class StockShelfOrderDomainService {
|
||||
inventoryParamDO.setInventoryDate(shelfMaterialDetail.getInventoryDate());
|
||||
inventoryParamDO.setExpiryDate(shelfMaterialDetail.getExpiryDate());
|
||||
inventoryParamDO.setProductionDate(shelfMaterialDetail.getProductionDate());
|
||||
inventoryParamDO.setPurchaseDate(shelfMaterialDetail.getPurchaseDate());
|
||||
inventoryParamDO.setBoxPalletNo(shelfMaterialDetail.getBoxPalletNo());
|
||||
inventoryParamDO.setSheetRefNo(shelfMaterialDetail.getSheetRefNo());
|
||||
inventoryParamDO.setBatchRefNo(shelfMaterialDetail.getBatchRefNo());
|
||||
@@ -1348,6 +1368,7 @@ public class StockShelfOrderDomainService {
|
||||
BeanUtils.copyProperties(inventoryParamDO, materialInventoryOmsParamDO);
|
||||
materialInventoryOmsParamDO.setProductionDate(materialInventoryPO.getProductionDate());
|
||||
materialInventoryOmsParamDO.setExpiryDate(materialInventoryPO.getExpiryDate());
|
||||
materialInventoryOmsParamDO.setPurchaseDate(materialInventoryPO.getPurchaseDate());
|
||||
materialInventoryOmsParamDO.setMaterialBaseInfoId(materialInventoryPO.getMaterialBaseInfoId());
|
||||
materialInventoryOmsParamDO.setWarehouseId(materialInventoryPO.getWarehouseId());
|
||||
materialInventoryOmsParamDO.setLotNumber(materialInventoryPO.getLotNumber());
|
||||
@@ -1510,6 +1531,9 @@ public class StockShelfOrderDomainService {
|
||||
case "production_date":
|
||||
param.setProductionDate(shelfMaterialDetail.getProductionDate());
|
||||
break;
|
||||
case "purchase_date":
|
||||
param.setPurchaseDate(shelfMaterialDetail.getPurchaseDate());
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package com.mhd.wms.interfaces.assember.inboundRank;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.mhd.common.core.exception.digitalLogisticsException.DigitalLogisticsException;
|
||||
import com.mhd.common.core.exception.digitalLogisticsException.UserError;
|
||||
import com.mhd.common.core.utils.IgnoreNullUtil;
|
||||
import com.mhd.common.core.utils.bean.BeanUtils;
|
||||
import com.mhd.common.security.utils.SecurityUtils;
|
||||
import com.mhd.system.api.model.LoginUser;
|
||||
import com.mhd.wms.domain.inboundRank.repository.todo.InboundRankDO;
|
||||
import com.mhd.wms.interfaces.dto.inboundRank.InboundRankDTO;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 入库排名统计Assembler
|
||||
*
|
||||
* @author rcx
|
||||
* @date 2026-08-31
|
||||
*/
|
||||
@Component
|
||||
public class InboundRankAssembler {
|
||||
|
||||
/**
|
||||
* 转换实体
|
||||
*/
|
||||
public InboundRankDO toDO(InboundRankDTO inboundRankDTO) {
|
||||
InboundRankDO inboundRankDO = new InboundRankDO();
|
||||
// 拷贝
|
||||
BeanUtils.copyProperties(inboundRankDTO, inboundRankDO, IgnoreNullUtil.getNullPropertyNames(inboundRankDTO));
|
||||
LoginUser loginUser = SecurityUtils.getLoginUser();
|
||||
if (ObjectUtil.isNull(loginUser)) {
|
||||
throw new DigitalLogisticsException(UserError.TIMEOUT);
|
||||
}
|
||||
return inboundRankDO;
|
||||
}
|
||||
}
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package com.mhd.wms.interfaces.assember.outboundRank;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.mhd.common.core.exception.digitalLogisticsException.DigitalLogisticsException;
|
||||
import com.mhd.common.core.exception.digitalLogisticsException.UserError;
|
||||
import com.mhd.common.core.utils.IgnoreNullUtil;
|
||||
import com.mhd.common.core.utils.bean.BeanUtils;
|
||||
import com.mhd.common.security.utils.SecurityUtils;
|
||||
import com.mhd.system.api.model.LoginUser;
|
||||
import com.mhd.wms.domain.outboundRank.repository.todo.OutboundRankDO;
|
||||
import com.mhd.wms.interfaces.dto.outboundRank.OutboundRankDTO;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* 出库排名统计Assembler
|
||||
*
|
||||
* @author rcx
|
||||
* @date 2026-08-31
|
||||
*/
|
||||
@Component
|
||||
public class OutboundRankAssembler {
|
||||
|
||||
/**
|
||||
* 转换实体
|
||||
*/
|
||||
public OutboundRankDO toDO(OutboundRankDTO outboundRankDTO) {
|
||||
OutboundRankDO outboundRankDO = new OutboundRankDO();
|
||||
// 拷贝
|
||||
BeanUtils.copyProperties(outboundRankDTO, outboundRankDO, IgnoreNullUtil.getNullPropertyNames(outboundRankDTO));
|
||||
LoginUser loginUser = SecurityUtils.getLoginUser();
|
||||
if (ObjectUtil.isNull(loginUser)) {
|
||||
throw new DigitalLogisticsException(UserError.TIMEOUT);
|
||||
}
|
||||
return outboundRankDO;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.mhd.wms.interfaces.dto.inboundRank;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 入库排名统计入参DTO
|
||||
*
|
||||
* <p>按入仓日期区间筛选商品入库量统计排名,统计口径:入仓日期 + 仅已入库状态(5) + 明细仅取 level=1 主行;
|
||||
* 一行 = 一个物料的合计(按物料编码合并),按件数降序排名;
|
||||
* 仓单编号/客户编号/存货人/入仓日期为单据级字段仅作查询条件,返回列不含这些字段</p>
|
||||
*
|
||||
* @author rcx
|
||||
* @date 2026-08-31
|
||||
*/
|
||||
@Data
|
||||
public class InboundRankDTO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ApiModelProperty("入仓日期-开始 yyyy-MM-dd(必填,按入仓单入仓日期筛选)")
|
||||
private String warehouseDateStart;
|
||||
|
||||
@ApiModelProperty("入仓日期-结束 yyyy-MM-dd(必填,按入仓单入仓日期筛选)")
|
||||
private String warehouseDateEnd;
|
||||
|
||||
@ApiModelProperty("仓单编号/入库单号(模糊)")
|
||||
private String inOrderNumber;
|
||||
|
||||
@ApiModelProperty("客户编号(模糊)")
|
||||
private String shipperCode;
|
||||
|
||||
@ApiModelProperty("存货人/客户名称(模糊)")
|
||||
private String shipperName;
|
||||
|
||||
@ApiModelProperty("商品货号(模糊)")
|
||||
private String materialCode;
|
||||
|
||||
@ApiModelProperty("货名/商品名称(模糊)")
|
||||
private String materialName;
|
||||
|
||||
@ApiModelProperty("仓库名称(模糊)")
|
||||
private String warehouseName;
|
||||
}
|
||||
+13
@@ -189,11 +189,17 @@ public class MaterialInventoryDTO extends MaterialBaseDTO {
|
||||
/** 为 true 时排除库存数量为 0 的行(出库分配选库存用);库存查询页不传或 false */
|
||||
@ApiModelProperty(value = "是否排除库存数量为0", example = "false")
|
||||
private Boolean excludeZeroInventoryQuantity;
|
||||
/** 为 true 时排除可用数量为 0 的行(库存数量>0 但可用数量=0 表示已被冻结/占用完,无法出库);不传或 false 不过滤 */
|
||||
@ApiModelProperty(value = "是否排除可用数量为0", example = "false")
|
||||
private Boolean excludeZeroAllocationQuantity;
|
||||
private String expiryDate;
|
||||
private String productionDate;
|
||||
/** 进货日期(yyyy-MM-dd,单日精确查询) */
|
||||
private String purchaseDate;
|
||||
private String expiryDateStr;
|
||||
private String productionDateStr;
|
||||
private String updateTimeStr;
|
||||
private String purchaseDateStr;
|
||||
|
||||
private String expiryDateStart;
|
||||
private String expiryDateEnd;
|
||||
@@ -204,6 +210,13 @@ public class MaterialInventoryDTO extends MaterialBaseDTO {
|
||||
private String updateTimeStart;
|
||||
private String updateTimeEnd;
|
||||
|
||||
private String purchaseDateStart;
|
||||
private String purchaseDateEnd;
|
||||
|
||||
/** 入库日期(库存行创建时间)区间查询 */
|
||||
private String createTimeStart;
|
||||
private String createTimeEnd;
|
||||
|
||||
@ApiModelProperty("上次计费时间")
|
||||
private Date lastBillingTime;
|
||||
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
package com.mhd.wms.interfaces.dto.outboundRank;
|
||||
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* 出库排名统计(明细)入参DTO
|
||||
*
|
||||
* <p>按日期区间筛选出库明细列表,一行 = 仓单×货品(件数/毛重/体积按行汇总,件数降序),
|
||||
* 统计口径:出库单创建时间 + 已出库及之后状态(9,12,13) + 明细仅取 level=1 主行</p>
|
||||
*
|
||||
* @author rcx
|
||||
* @date 2026-08-31
|
||||
*/
|
||||
@Data
|
||||
public class OutboundRankDTO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@ApiModelProperty("出库日期-开始 yyyy-MM-dd(必填,按出库单创建时间筛选)")
|
||||
private String createTimeStart;
|
||||
|
||||
@ApiModelProperty("出库日期-结束 yyyy-MM-dd(必填,按出库单创建时间筛选)")
|
||||
private String createTimeEnd;
|
||||
|
||||
@ApiModelProperty("仓单编号/出库单号(模糊)")
|
||||
private String outOrderNumber;
|
||||
|
||||
@ApiModelProperty("入库单号(模糊)")
|
||||
private String inOrderNumber;
|
||||
|
||||
@ApiModelProperty("商品货号(模糊)")
|
||||
private String materialCode;
|
||||
|
||||
@ApiModelProperty("货名/商品名称(模糊)")
|
||||
private String materialName;
|
||||
|
||||
@ApiModelProperty("线路编码(模糊)")
|
||||
private String lineCode;
|
||||
|
||||
@ApiModelProperty("线路名称(模糊)")
|
||||
private String lineName;
|
||||
|
||||
@ApiModelProperty("仓库名称(模糊)")
|
||||
private String warehouseName;
|
||||
|
||||
@ApiModelProperty("客户名称(模糊)")
|
||||
private String customerName;
|
||||
|
||||
@ApiModelProperty("货主名称(模糊)")
|
||||
private String shipperName;
|
||||
}
|
||||
+6
@@ -311,6 +311,12 @@ public class ShelfMaterialDetailDTO extends BaseVOEntity {
|
||||
@Excel(name = "存货日期", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date inventoryDate;
|
||||
|
||||
@ApiModelProperty("进货日期")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
@Excel(name = "进货日期", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
|
||||
private Date purchaseDate;
|
||||
|
||||
@ApiModelProperty("ExtAttr3")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||
|
||||
+107
@@ -0,0 +1,107 @@
|
||||
package com.mhd.wms.interfaces.facadeApi.inboundRank;
|
||||
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import com.mhd.common.core.constant.HttpStatus;
|
||||
import com.mhd.common.core.utils.PageUtils;
|
||||
import com.mhd.common.core.utils.poi.ExcelUtil;
|
||||
import com.mhd.wms.application.service.inboundRank.InboundRankApplicationService;
|
||||
import com.mhd.wms.domain.inboundRank.repository.po.InboundMaterialRankPO;
|
||||
import com.mhd.wms.domain.inboundRank.repository.po.InboundRankTotalPO;
|
||||
import com.mhd.wms.domain.inboundRank.repository.todo.InboundRankDO;
|
||||
import com.mhd.wms.interfaces.assember.inboundRank.InboundRankAssembler;
|
||||
import com.mhd.wms.interfaces.dto.inboundRank.InboundRankDTO;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 入库排名统计Api
|
||||
*
|
||||
* <p>按入仓日期区间筛选商品入库量统计排名。统计口径:入仓日期(为空的历史单按建档时间兜底) + 仅已入库状态(5),
|
||||
* 明细仅取 level=1 主行;一行 = 一个物料的合计(按物料编码合并区间内全部已入库仓单),
|
||||
* 按件数(实际上架量 SHELVES_QUANTITY)降序排名,件数为0的物料不返回。
|
||||
* 返回字段:物料编码/货名/规格型号/单位/件数/毛重(吨)/投保总额/体积(CBM);
|
||||
* 仓单编号/客户编号/存货人/入仓日期为单据级字段仅作查询条件,不返回。
|
||||
* 与出库排名(/outboundRankApi)配对,前端用 tab 页区分</p>
|
||||
*
|
||||
* @author rcx
|
||||
* @date 2026-08-31
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/inboundRankApi")
|
||||
public class InboundRankApi {
|
||||
|
||||
@Resource
|
||||
private InboundRankAssembler inboundRankAssembler;
|
||||
|
||||
@Autowired
|
||||
private InboundRankApplicationService inboundRankApplicationService;
|
||||
|
||||
/**
|
||||
* 分页查询商品入库排名列表(含合计行)
|
||||
*/
|
||||
@ApiOperation("分页查询商品入库排名列表")
|
||||
@GetMapping("/queryMaterialRankList")
|
||||
public HashMap<String, Object> queryMaterialRankList(InboundRankDTO inboundRankDTO) {
|
||||
//转换实体
|
||||
InboundRankDO inboundRankDO = inboundRankAssembler.toDO(inboundRankDTO);
|
||||
startPage();
|
||||
List<InboundMaterialRankPO> list = inboundRankApplicationService.queryMaterialRankList(inboundRankDO);
|
||||
InboundRankTotalPO total = inboundRankApplicationService.queryMaterialRankTotal(inboundRankDO);
|
||||
return getDataTableWithTotal(list, total);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出商品入库排名Excel
|
||||
*/
|
||||
@ApiOperation("导出商品入库排名Excel")
|
||||
@GetMapping("/exportMaterialRank")
|
||||
public void exportMaterialRank(HttpServletResponse response, InboundRankDTO inboundRankDTO) throws Exception {
|
||||
//转换实体(不分页,导出全量)
|
||||
InboundRankDO inboundRankDO = inboundRankAssembler.toDO(inboundRankDTO);
|
||||
List<InboundMaterialRankPO> list = inboundRankApplicationService.exportMaterialRank(inboundRankDO);
|
||||
|
||||
String fileName = URLEncoder.encode("入库排名统计", "UTF-8").replaceAll("\\+", "%20");
|
||||
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
||||
response.setCharacterEncoding("utf-8");
|
||||
response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
|
||||
|
||||
ExcelUtil<InboundMaterialRankPO> util = new ExcelUtil<>(InboundMaterialRankPO.class);
|
||||
util.exportExcel(response, list, "入库排名统计");
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页结果 + 合计行:data/total/code/msg 之外追加
|
||||
* totalPieceCount/totalGrossWeightTon/totalInsureAmount/totalVolume/totalOrderCount
|
||||
*/
|
||||
private HashMap<String, Object> getDataTableWithTotal(List<?> list, InboundRankTotalPO total) {
|
||||
HashMap<String, Object> result = new HashMap<>();
|
||||
result.put("data", list);
|
||||
result.put("total", new PageInfo<>(list).getTotal());
|
||||
result.put("code", HttpStatus.SUCCESS);
|
||||
result.put("msg", "查询成功");
|
||||
if (total != null) {
|
||||
result.put("totalPieceCount", total.getTotalPieceCount());
|
||||
result.put("totalGrossWeightTon", total.getTotalGrossWeightTon());
|
||||
result.put("totalInsureAmount", total.getTotalInsureAmount());
|
||||
result.put("totalVolume", total.getTotalVolume());
|
||||
result.put("totalOrderCount", total.getTotalOrderCount());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置请求分页数据
|
||||
*/
|
||||
protected void startPage() {
|
||||
PageUtils.startPage();
|
||||
}
|
||||
}
|
||||
+24
-3
@@ -55,18 +55,31 @@ public class MaterialInventoryApi extends BaseController {
|
||||
/**
|
||||
* 分页查询物料库存列表
|
||||
*/
|
||||
@ApiOperation(value = "查询物料库存列表", notes = "库存查询页不传 excludeZeroInventoryQuantity 可查出数量为0;出库分配页传 excludeZeroInventoryQuantity=true 排除库存数量为0")
|
||||
@ApiOperation(value = "查询物料库存列表", notes = "两个隐藏0库存开关(均不传或 false 不过滤,保持原行为):"
|
||||
+ "excludeZeroInventoryQuantity=true 排除库存数量为0(盘点-库存选择页\"隐藏数量为0的物料\");"
|
||||
+ "excludeZeroAllocationQuantity=true 排除可用数量为0(出库选库存,可用数量=0 表示已被冻结/占用完无法出库);"
|
||||
+ "物料编号筛选传 materialCode(精确匹配),仓库筛选传 warehouseId(下拉);"
|
||||
+ "库存查询页不传开关可查出数量为0;导出复用本接口:传 isExport=true 标识导出请求"
|
||||
+ "(导出显示:商品饮用有效期expiryDate/物料分类materialClassifyName/进货日期purchaseDate,所有查询维度均返回)")
|
||||
@GetMapping("/list")
|
||||
public TableDataInfo list(MaterialInventoryDTO materialInventoryDTO,
|
||||
@RequestParam(value = "customerName", required = false) String customerName,
|
||||
@RequestParam(value = "excludeZeroInventoryQuantity", required = false) Boolean excludeZeroInventoryQuantity,
|
||||
@RequestParam(value = "excludeZeroAllocationQuantity", required = false) Boolean excludeZeroAllocationQuantity,
|
||||
@RequestParam(value = "expiryDateStart", required = false) String expiryDateStart,
|
||||
@RequestParam(value = "expiryDateEnd", required = false) String expiryDateEnd,
|
||||
@RequestParam(value = "orderByExpiryDate", required = false) Boolean orderByExpiryDate)
|
||||
@RequestParam(value = "purchaseDateStart", required = false) String purchaseDateStart,
|
||||
@RequestParam(value = "purchaseDateEnd", required = false) String purchaseDateEnd,
|
||||
@RequestParam(value = "orderByExpiryDate", required = false) Boolean orderByExpiryDate,
|
||||
// 导出标识:导出与查询共用本接口,isExport=true 表示本次请求为导出(导出专属排序等逻辑以此开关)
|
||||
@RequestParam(value = "isExport", required = false) Boolean isExport)
|
||||
{
|
||||
if (Boolean.TRUE.equals(excludeZeroInventoryQuantity)) {
|
||||
materialInventoryDTO.setExcludeZeroInventoryQuantity(true);
|
||||
}
|
||||
if (Boolean.TRUE.equals(excludeZeroAllocationQuantity)) {
|
||||
materialInventoryDTO.setExcludeZeroAllocationQuantity(true);
|
||||
}
|
||||
// 出库分配前端传的是客户名称 customerName,这里通过名称查询货主ID,使用精确匹配(不模糊匹配)
|
||||
String shipperName = null; // 保存查询到的货主名称
|
||||
if (StringUtils.isNotBlank(customerName) && materialInventoryDTO.getShipperId() == null) {
|
||||
@@ -93,10 +106,15 @@ public class MaterialInventoryApi extends BaseController {
|
||||
MaterialInventoryDO materialInventoryDO = materialInventoryAssembler.toDO(materialInventoryDTO);
|
||||
materialInventoryDO.setExpiryDateStr(materialInventoryDTO.getExpiryDate());
|
||||
materialInventoryDO.setProductionDateStr(materialInventoryDTO.getProductionDate());
|
||||
materialInventoryDO.setPurchaseDateStr(materialInventoryDTO.getPurchaseDate());
|
||||
materialInventoryDO.setExpiryDateStart(expiryDateStart);
|
||||
materialInventoryDO.setExpiryDateEnd(expiryDateEnd);
|
||||
materialInventoryDO.setPurchaseDateStart(purchaseDateStart);
|
||||
materialInventoryDO.setPurchaseDateEnd(purchaseDateEnd);
|
||||
// 导出场景:queryRule=wlExpiry + orderByExpiryDate=true 时 SQL 按到期日倒序分组(与 OMS 库存查询导出一致)
|
||||
materialInventoryDO.setOrderByExpiryDate(orderByExpiryDate);
|
||||
// 导出标识:isExport=true 启用导出融合排序(到期日倒序优先 → 同到期日按物料编码升序,所有维度生效)
|
||||
materialInventoryDO.setIsExport(isExport);
|
||||
Date updateTime = materialInventoryDTO.getUpdateTime();
|
||||
if (updateTime != null) {
|
||||
LocalDateTime localDateTime = updateTime.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
|
||||
@@ -169,7 +187,10 @@ public class MaterialInventoryApi extends BaseController {
|
||||
// materialDetailId 是新接口专用参数(出库单明细ID),库存 DTO 的同名字段语义是「上架单明细ID」,
|
||||
// 泄入原查询会生成错误的 a.material_detail_id 条件导致查空,进原查询前显式清除
|
||||
materialInventoryDTO.setMaterialDetailId(null);
|
||||
return list(materialInventoryDTO, customerName, excludeZeroInventoryQuantity, expiryDateStart, expiryDateEnd, orderByExpiryDate);
|
||||
// assignableList 非导出场景,isExport 传 null;excludeZeroAllocationQuantity 已随 DTO 绑定,透传保持开关生效
|
||||
return list(materialInventoryDTO, customerName, excludeZeroInventoryQuantity,
|
||||
materialInventoryDTO.getExcludeZeroAllocationQuantity(),
|
||||
expiryDateStart, expiryDateEnd, null, null, orderByExpiryDate, null);
|
||||
}
|
||||
|
||||
@ApiOperation("查询物料库存列表不分页;queryRule=hz 时按货主+物料分组(同一物料在不同货主各占一行)")
|
||||
|
||||
+151
@@ -0,0 +1,151 @@
|
||||
package com.mhd.wms.interfaces.facadeApi.outboundRank;
|
||||
|
||||
import com.github.pagehelper.PageInfo;
|
||||
import com.mhd.common.core.constant.HttpStatus;
|
||||
import com.mhd.common.core.utils.PageUtils;
|
||||
import com.mhd.common.core.utils.poi.ExcelUtil;
|
||||
import com.mhd.wms.application.service.outboundRank.OutboundRankApplicationService;
|
||||
import com.mhd.wms.domain.outboundRank.repository.po.OutboundDetailRankTotalPO;
|
||||
import com.mhd.wms.domain.outboundRank.repository.po.OutboundLineRankPO;
|
||||
import com.mhd.wms.domain.outboundRank.repository.po.OutboundMaterialRankPO;
|
||||
import com.mhd.wms.domain.outboundRank.repository.todo.OutboundRankDO;
|
||||
import com.mhd.wms.interfaces.assember.outboundRank.OutboundRankAssembler;
|
||||
import com.mhd.wms.interfaces.dto.outboundRank.OutboundRankDTO;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 出库排名统计Api
|
||||
*
|
||||
* <p>按日期区间筛选出库量统计排名,按出库数量(实际复核出库量)降序。
|
||||
* 商品tab:一行 = 一个货品(货号/货名/件数/毛重(吨)/体积(CBM)/退保总额占位),跨出库单汇总,忽略线路筛选参数;
|
||||
* 线路tab:一行 = 线路×货品(线路编码/线路/货号/货名/件数/毛重(吨)/体积(CBM)/退保总额占位),按线路+物料编码合并,
|
||||
* 仅统计带线路的单,商品/线路筛选参数均生效;
|
||||
* 统计口径:出库单创建时间 + 已出库及之后状态(9,12,13),明细仅取 level=1 主行;
|
||||
* 件数 = SUM(CHECK_QUANTITY) 复核确认的实际出库量(与入库排名的实际上架量对称);
|
||||
* 退保总额后端暂无对应数据来源,恒为 null</p>
|
||||
*
|
||||
* @author rcx
|
||||
* @date 2026-08-31
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/outboundRankApi")
|
||||
public class OutboundRankApi {
|
||||
|
||||
@Resource
|
||||
private OutboundRankAssembler outboundRankAssembler;
|
||||
|
||||
@Autowired
|
||||
private OutboundRankApplicationService outboundRankApplicationService;
|
||||
|
||||
/**
|
||||
* 分页查询商品出库排名列表(含合计行,商品tab;忽略线路筛选参数)
|
||||
*/
|
||||
@ApiOperation("分页查询商品出库排名列表")
|
||||
@GetMapping("/queryMaterialRankList")
|
||||
public HashMap<String, Object> queryMaterialRankList(OutboundRankDTO outboundRankDTO) {
|
||||
//转换实体
|
||||
OutboundRankDO outboundRankDO = outboundRankAssembler.toDO(outboundRankDTO);
|
||||
//商品tab:忽略线路筛选参数
|
||||
outboundRankDO.setLineCode(null);
|
||||
outboundRankDO.setLineName(null);
|
||||
startPage();
|
||||
List<OutboundMaterialRankPO> list = outboundRankApplicationService.queryMaterialRankList(outboundRankDO);
|
||||
OutboundDetailRankTotalPO total = outboundRankApplicationService.queryMaterialRankTotal(outboundRankDO);
|
||||
return getDataTableWithTotal(list, total);
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页查询线路出库排名列表(含合计行,线路tab;一行=线路×货品,仅统计带线路的单)
|
||||
*/
|
||||
@ApiOperation("分页查询线路出库排名列表")
|
||||
@GetMapping("/queryLineRankList")
|
||||
public HashMap<String, Object> queryLineRankList(OutboundRankDTO outboundRankDTO) {
|
||||
//转换实体(线路tab:商品/线路筛选参数均生效,按线路+物料编码合并)
|
||||
OutboundRankDO outboundRankDO = outboundRankAssembler.toDO(outboundRankDTO);
|
||||
startPage();
|
||||
List<OutboundLineRankPO> list = outboundRankApplicationService.queryLineRankList(outboundRankDO);
|
||||
OutboundDetailRankTotalPO total = outboundRankApplicationService.queryLineRankTotal(outboundRankDO);
|
||||
return getDataTableWithTotal(list, total);
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出商品出库排名Excel(商品tab;忽略线路筛选参数)
|
||||
*/
|
||||
@ApiOperation("导出商品出库排名Excel")
|
||||
@GetMapping("/exportMaterialRank")
|
||||
public void exportMaterialRank(HttpServletResponse response, OutboundRankDTO outboundRankDTO) throws Exception {
|
||||
//转换实体(不分页,导出全量)
|
||||
OutboundRankDO outboundRankDO = outboundRankAssembler.toDO(outboundRankDTO);
|
||||
//商品tab:忽略线路筛选参数
|
||||
outboundRankDO.setLineCode(null);
|
||||
outboundRankDO.setLineName(null);
|
||||
List<OutboundMaterialRankPO> list = outboundRankApplicationService.exportMaterialRankList(outboundRankDO);
|
||||
|
||||
String fileName = URLEncoder.encode("商品出库排名", "UTF-8").replaceAll("\\+", "%20");
|
||||
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
||||
response.setCharacterEncoding("utf-8");
|
||||
response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
|
||||
|
||||
ExcelUtil<OutboundMaterialRankPO> util = new ExcelUtil<>(OutboundMaterialRankPO.class);
|
||||
util.exportExcel(response, list, "商品出库排名");
|
||||
}
|
||||
|
||||
/**
|
||||
* 导出线路出库排名Excel(线路tab;一行=线路×货品,仅统计带线路的单)
|
||||
*/
|
||||
@ApiOperation("导出线路出库排名Excel")
|
||||
@GetMapping("/exportLineRank")
|
||||
public void exportLineRank(HttpServletResponse response, OutboundRankDTO outboundRankDTO) throws Exception {
|
||||
//转换实体(不分页,导出全量;线路tab:商品/线路筛选参数均生效,按线路+物料编码合并)
|
||||
OutboundRankDO outboundRankDO = outboundRankAssembler.toDO(outboundRankDTO);
|
||||
List<OutboundLineRankPO> list = outboundRankApplicationService.exportLineRankList(outboundRankDO);
|
||||
|
||||
String fileName = URLEncoder.encode("线路出库排名", "UTF-8").replaceAll("\\+", "%20");
|
||||
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
|
||||
response.setCharacterEncoding("utf-8");
|
||||
response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
|
||||
|
||||
ExcelUtil<OutboundLineRankPO> util = new ExcelUtil<>(OutboundLineRankPO.class);
|
||||
util.exportExcel(response, list, "线路出库排名");
|
||||
}
|
||||
|
||||
/**
|
||||
* 分页结果 + 合计行:data/total/code/msg 之外追加合计字段(商品tab含 totalOrderCount,线路tab含 totalOrderCount/totalLineCount)
|
||||
*/
|
||||
private HashMap<String, Object> getDataTableWithTotal(List<?> list, OutboundDetailRankTotalPO total) {
|
||||
HashMap<String, Object> result = new HashMap<>();
|
||||
result.put("data", list);
|
||||
result.put("total", new PageInfo<>(list).getTotal());
|
||||
result.put("code", HttpStatus.SUCCESS);
|
||||
result.put("msg", "查询成功");
|
||||
if (total != null) {
|
||||
result.put("totalPieceCount", total.getTotalPieceCount());
|
||||
result.put("totalGrossWeightTon", total.getTotalGrossWeightTon());
|
||||
result.put("totalVolume", total.getTotalVolume());
|
||||
if (total.getTotalOrderCount() != null) {
|
||||
result.put("totalOrderCount", total.getTotalOrderCount());
|
||||
}
|
||||
if (total.getTotalLineCount() != null) {
|
||||
result.put("totalLineCount", total.getTotalLineCount());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置请求分页数据
|
||||
*/
|
||||
protected void startPage() {
|
||||
PageUtils.startPage();
|
||||
}
|
||||
}
|
||||
+24
-24
@@ -53,8 +53,8 @@ public class StockInOrderApi extends BaseController {
|
||||
private StockInOrderAssembler stockInOrderAssembler;
|
||||
@Resource
|
||||
private StockOutOrderAssembler stockOutOrderAssembler;
|
||||
@Autowired
|
||||
private XxlJobServiceFeign xxlJobServiceFeign;
|
||||
// @Autowired
|
||||
// private XxlJobServiceFeign xxlJobServiceFeign;
|
||||
|
||||
/**
|
||||
* 分页查询入库单列表
|
||||
@@ -353,32 +353,32 @@ public class StockInOrderApi extends BaseController {
|
||||
return stockInOrderApplicationService.batchSignature(dto);
|
||||
}
|
||||
|
||||
@GetMapping("/xxlopenfeign")
|
||||
public AjaxResult xxlopenfeign(@RequestParam String param) {
|
||||
R<Map<String, Object>> mapR = xxlJobServiceFeign.openFeignTest(param);
|
||||
return AjaxResult.success(mapR);
|
||||
}
|
||||
// @GetMapping("/xxlopenfeign")
|
||||
// public AjaxResult xxlopenfeign(@RequestParam String param) {
|
||||
// R<Map<String, Object>> mapR = xxlJobServiceFeign.openFeignTest(param);
|
||||
// return AjaxResult.success(mapR);
|
||||
// }
|
||||
|
||||
/**
|
||||
* 1. 简单任务示例(Bean模式)
|
||||
* 这里的 demoJobHandler 必须和调度中心配置一致
|
||||
*/
|
||||
@XxlJob("demoJobHandler")
|
||||
public void demoJobHandler() {
|
||||
// 获取任务参数
|
||||
String param = XxlJobHelper.getJobParam();
|
||||
logger.info("XXL-JOB 开始执行,参数:{}", param);
|
||||
|
||||
try {
|
||||
// ========== 你的业务逻辑 ==========
|
||||
logger.info("执行若依微服务定时任务...");
|
||||
|
||||
// 设置任务执行结果
|
||||
XxlJobHelper.handleSuccess("执行成功");
|
||||
} catch (Exception e) {
|
||||
logger.error("XXL-JOB 执行失败", e);
|
||||
XxlJobHelper.handleFail("执行失败:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
// @XxlJob("demoJobHandler")
|
||||
// public void demoJobHandler() {
|
||||
// // 获取任务参数
|
||||
// String param = XxlJobHelper.getJobParam();
|
||||
// logger.info("XXL-JOB 开始执行,参数:{}", param);
|
||||
//
|
||||
// try {
|
||||
// // ========== 你的业务逻辑 ==========
|
||||
// logger.info("执行若依微服务定时任务...");
|
||||
//
|
||||
// // 设置任务执行结果
|
||||
// XxlJobHelper.handleSuccess("执行成功");
|
||||
// } catch (Exception e) {
|
||||
// logger.error("XXL-JOB 执行失败", e);
|
||||
// XxlJobHelper.handleFail("执行失败:" + e.getMessage());
|
||||
// }
|
||||
// }
|
||||
|
||||
}
|
||||
+14
-1
@@ -208,6 +208,7 @@ public class StockOutOrderApi extends BaseController {
|
||||
public AjaxResult getInfoOutOrderNumber(String outOrderNumber) {
|
||||
// 根据出库单号查询出库单,再按出库单ID查询详情,保证与出库管理页面一致
|
||||
StockOutOrder stockOutOrder = stockOutOrderService.getOne(new LambdaQueryWrapper<StockOutOrder>()
|
||||
.eq(StockOutOrder::getDelFlag,1)
|
||||
.eq(StockOutOrder::getOutOrderNumber, outOrderNumber));
|
||||
if (stockOutOrder == null) {
|
||||
return AjaxResult.error("出库单不存在");
|
||||
@@ -226,6 +227,7 @@ public class StockOutOrderApi extends BaseController {
|
||||
return AjaxResult.error("orderNumber不能为空");
|
||||
}
|
||||
StockOutOrder stockOutOrder = stockOutOrderService.getOne(new LambdaQueryWrapper<StockOutOrder>()
|
||||
.eq(StockOutOrder::getDelFlag,1)
|
||||
.eq(StockOutOrder::getOutOrderNumber, orderNumber));
|
||||
if (stockOutOrder == null) {
|
||||
return AjaxResult.error("出库单不存在");
|
||||
@@ -542,10 +544,21 @@ public class StockOutOrderApi extends BaseController {
|
||||
stockOutOrderApplicationService.omsOrderAddDetail(outMaterialDetails);
|
||||
}
|
||||
|
||||
/**
|
||||
* oms下发前库存校验:不足时返回错误,OMS据此拦截下发,避免单据落库后分配失败残留垃圾单
|
||||
*/
|
||||
@ApiOperation("oms下发前库存校验")
|
||||
@PostMapping(value = "/checkOmsAssignInventory")
|
||||
public AjaxResult checkOmsAssignInventory(@RequestBody List<OutMaterialDetail> outMaterialDetails) {
|
||||
stockOutOrderApplicationService.checkOmsAssignInventory(outMaterialDetails);
|
||||
return AjaxResult.success("库存校验通过");
|
||||
}
|
||||
|
||||
@ApiOperation("oms下发单保存")
|
||||
@PostMapping(value = "/cancelExecutionOrder")
|
||||
public void omsCancelExecutionOrder(@RequestBody StockOutOrder stockOutOrder) {
|
||||
public AjaxResult omsCancelExecutionOrder(@RequestBody StockOutOrder stockOutOrder) {
|
||||
stockOutOrderApplicationService.cancelExecutionOrder(stockOutOrder);
|
||||
return AjaxResult.success();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -9,46 +9,46 @@ import org.springframework.context.annotation.Configuration;
|
||||
/**
|
||||
* XXL-JOB 配置类
|
||||
*/
|
||||
@Configuration
|
||||
//@Configuration
|
||||
public class XxlJobConfig {
|
||||
private Logger logger = LoggerFactory.getLogger(XxlJobConfig.class);
|
||||
|
||||
@Value("${xxl.job.admin.addresses}")
|
||||
private String adminAddresses;
|
||||
|
||||
@Value("${xxl.job.accessToken}")
|
||||
private String accessToken;
|
||||
|
||||
@Value("${xxl.job.executor.appname}")
|
||||
private String appname;
|
||||
|
||||
@Value("${xxl.job.executor.address}")
|
||||
private String address;
|
||||
|
||||
@Value("${xxl.job.executor.ip}")
|
||||
private String ip;
|
||||
|
||||
@Value("${xxl.job.executor.port}")
|
||||
private int port;
|
||||
|
||||
@Value("${xxl.job.executor.logpath}")
|
||||
private String logPath;
|
||||
|
||||
@Value("${xxl.job.executor.logretentiondays}")
|
||||
private int logRetentionDays;
|
||||
|
||||
@Bean
|
||||
public XxlJobSpringExecutor xxlJobExecutor() {
|
||||
logger.info(">>>>>>>>>>> xxl-job config init.");
|
||||
XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
|
||||
xxlJobSpringExecutor.setAdminAddresses(adminAddresses);
|
||||
xxlJobSpringExecutor.setAppname(appname);
|
||||
xxlJobSpringExecutor.setAddress(address);
|
||||
xxlJobSpringExecutor.setIp(ip);
|
||||
xxlJobSpringExecutor.setPort(port);
|
||||
xxlJobSpringExecutor.setAccessToken(accessToken);
|
||||
xxlJobSpringExecutor.setLogPath(logPath);
|
||||
xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);
|
||||
return xxlJobSpringExecutor;
|
||||
}
|
||||
// private Logger logger = LoggerFactory.getLogger(XxlJobConfig.class);
|
||||
//
|
||||
// @Value("${xxl.job.admin.addresses}")
|
||||
// private String adminAddresses;
|
||||
//
|
||||
// @Value("${xxl.job.accessToken}")
|
||||
// private String accessToken;
|
||||
//
|
||||
// @Value("${xxl.job.executor.appname}")
|
||||
// private String appname;
|
||||
//
|
||||
// @Value("${xxl.job.executor.address}")
|
||||
// private String address;
|
||||
//
|
||||
// @Value("${xxl.job.executor.ip}")
|
||||
// private String ip;
|
||||
//
|
||||
// @Value("${xxl.job.executor.port}")
|
||||
// private int port;
|
||||
//
|
||||
// @Value("${xxl.job.executor.logpath}")
|
||||
// private String logPath;
|
||||
//
|
||||
// @Value("${xxl.job.executor.logretentiondays}")
|
||||
// private int logRetentionDays;
|
||||
//
|
||||
// @Bean
|
||||
// public XxlJobSpringExecutor xxlJobExecutor() {
|
||||
// logger.info(">>>>>>>>>>> xxl-job config init.");
|
||||
// XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
|
||||
// xxlJobSpringExecutor.setAdminAddresses(adminAddresses);
|
||||
// xxlJobSpringExecutor.setAppname(appname);
|
||||
// xxlJobSpringExecutor.setAddress(address);
|
||||
// xxlJobSpringExecutor.setIp(ip);
|
||||
// xxlJobSpringExecutor.setPort(port);
|
||||
// xxlJobSpringExecutor.setAccessToken(accessToken);
|
||||
// xxlJobSpringExecutor.setLogPath(logPath);
|
||||
// xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);
|
||||
// return xxlJobSpringExecutor;
|
||||
// }
|
||||
}
|
||||
Reference in New Issue
Block a user