Merge branch 'dev' into dev_WMS20260401
# Conflicts: # mhd-modules/mhd-system/src/main/java/com/mhd/basic/domain/materialBaseInfo/entity/MaterialBaseInfo.java # mhd-modules/mhd-system/src/main/java/com/mhd/basic/domain/materialBaseInfo/repository/po/MaterialBaseInfoPO.java # mhd-modules/mhd-system/src/main/java/com/mhd/basic/domain/materialBaseInfo/repository/todo/MaterialBaseInfoDO.java # mhd-modules/mhd-system/src/main/java/com/mhd/basic/interfaces/dto/materialBaseInfo/MaterialBaseInfoDTO.java # mhd_wms/src/main/java/com/mhd/wms/application/service/stockInOrder/StockInOrderApplicationService.java # mhd_wms/src/main/java/com/mhd/wms/application/service/stockOutOrder/StockOutOrderApplicationService.java # mhd_wms/src/main/java/com/mhd/wms/application/service/stockReceiptOrder/StockReceiptOrderApplicationService.java # mhd_wms/src/main/java/com/mhd/wms/domain/handoverTaskOrder/service/HandoverTaskOrderDomainService.java # mhd_wms/src/main/java/com/mhd/wms/domain/pickingOrder/service/PickingOrderDomainService.java # mhd_wms/src/main/java/com/mhd/wms/domain/receiptMaterialDetail/repository/facade/IReceiptMaterialDetailService.java # mhd_wms/src/main/java/com/mhd/wms/domain/receiptMaterialDetail/repository/persistence/ReceiptMaterialDetailImpl.java # mhd_wms/src/main/java/com/mhd/wms/domain/shelfMaterialDetail/repository/todo/ShelfMaterialDetailDO.java # mhd_wms/src/main/java/com/mhd/wms/domain/stockInOrder/repository/po/StockInOrderPO.java # mhd_wms/src/main/java/com/mhd/wms/domain/stockOutOrder/entity/StockOutOrder.java # mhd_wms/src/main/java/com/mhd/wms/domain/stockOutOrder/repository/po/StockOutOrderPO.java # mhd_wms/src/main/java/com/mhd/wms/domain/stockOutOrder/repository/todo/StockOutOrderDO.java # mhd_wms/src/main/java/com/mhd/wms/domain/stockReceiptOrder/repository/po/StockReceiptOrderPO.java # mhd_wms/src/main/java/com/mhd/wms/interfaces/dto/stockOutOrder/StockOutOrderDTO.java # mhd_wms/src/main/java/com/mhd/wms/interfaces/facadeApi/stockInOrder/StockInOrderApi.java # mhd_wms/src/main/java/com/mhd/wms/interfaces/facadeApi/stockReceiptOrder/StockReceiptOrderApi.java # mhd_wms/src/main/java/com/mhd/wms/interfaces/facadeApp/stockReceiptOrder/StockReceiptOrderAppApi.java # mhd_wms/src/main/resources/mapper/stockInOrder/StockInOrderMapper.xml # mhd_wms/src/main/resources/mapper/stockReceiptOrder/StockReceiptOrderMapper.xml
This commit is contained in:
+3
-2
@@ -142,5 +142,6 @@ public class HandoverTaskOrder extends BaseVOEntity {
|
||||
|
||||
@ApiModelProperty("作业人姓名")
|
||||
private String operatorsName;
|
||||
|
||||
}
|
||||
@ApiModelProperty("计费信息")
|
||||
private String billingJson;
|
||||
}
|
||||
+3
-2
@@ -141,5 +141,6 @@ public class HandoverTaskOrderPO extends BaseVOEntity {
|
||||
|
||||
@ApiModelProperty("物料明细(根据复核单数据生成,数量为复核数量)")
|
||||
private List<TaskHandoverMaterialDetailPO> materialDetailList;
|
||||
|
||||
}
|
||||
@ApiModelProperty("计费信息")
|
||||
private String billingJson;
|
||||
}
|
||||
+3
-1
@@ -142,4 +142,6 @@ public class HandoverTaskOrderDO extends BaseVOEntity {
|
||||
|
||||
@ApiModelProperty("app上传的图片")
|
||||
private String pictureApp;
|
||||
}
|
||||
|
||||
private String billingJson;
|
||||
}
|
||||
+8
-8
@@ -27,6 +27,7 @@ import com.mhd.wms.domain.outMaterialDetail.entity.OutMaterialDetail;
|
||||
import com.mhd.wms.domain.outMaterialDetail.repository.mapper.OutMaterialDetailMapper;
|
||||
import com.mhd.wms.domain.pickingMaterialDetail.repository.mapper.PickingMaterialDetailMapper;
|
||||
import com.mhd.wms.domain.pickingMaterialDetail.repository.po.PickingMaterialDetailPO;
|
||||
import com.mhd.wms.domain.stockOutOrder.repository.facade.IStockOutOrderService;
|
||||
import com.mhd.wms.domain.taskHandoverMaterialDetail.repository.po.TaskHandoverMaterialDetailPO;
|
||||
import com.mhd.wms.domain.shiftManage.repository.po.ShiftManagePO;
|
||||
import com.mhd.wms.domain.shiftManage.repository.todo.ShiftManageDO;
|
||||
@@ -74,6 +75,8 @@ public class HandoverTaskOrderDomainService {
|
||||
private IMaterialBarCodeService materialBarCodeService;
|
||||
@Autowired
|
||||
private IMaterialInventoryService materialInventoryService;
|
||||
@Autowired
|
||||
private IStockOutOrderService stockOutOrderService;
|
||||
|
||||
|
||||
/**
|
||||
@@ -171,14 +174,8 @@ public class HandoverTaskOrderDomainService {
|
||||
detail.setMaterialCode(omd.getMaterialCode() != null ? omd.getMaterialCode() : omd.getMaterialNo());
|
||||
detail.setMaterialName(omd.getMaterialName() != null ? omd.getMaterialName() : omd.getCommodityName());
|
||||
detail.setBarCode(omd.getBarCode());
|
||||
// 需要复核时:交接展示以出库明细上的复核计量为准(完成复核时由复核单同步写入 check_*)
|
||||
if (Integer.valueOf(1).equals(review)) {
|
||||
detail.setWeightLimit(omd.getCheckNetWeight() != null ? omd.getCheckNetWeight() : omd.getWeightLimit());
|
||||
detail.setVolumeLimit(omd.getCheckVolume() != null ? omd.getCheckVolume() : omd.getVolumeLimit());
|
||||
} else {
|
||||
detail.setWeightLimit(omd.getWeightLimit());
|
||||
detail.setVolumeLimit(omd.getVolumeLimit());
|
||||
}
|
||||
detail.setWeightLimit(omd.getWeightLimit());
|
||||
detail.setVolumeLimit(omd.getVolumeLimit());
|
||||
detail.setQuantity(omd.getQuantity());
|
||||
detail.setPickingQuantity(pickQty);
|
||||
detail.setCheckQuantity(handoverQuantity);
|
||||
@@ -291,11 +288,14 @@ public class HandoverTaskOrderDomainService {
|
||||
for (Long handoverTaskOrderId : handoverTaskOrderIds) {
|
||||
pushOms(handoverTaskOrderId);
|
||||
}
|
||||
HandoverTaskOrder handoverTaskOrder = handoverTaskOrderService.getById(handoverTaskOrderIds.get(0));
|
||||
stockOutOrderService.update(null,new UpdateWrapper<StockOutOrder>().lambda().set(StockOutOrder::getBillingJson,handoverTaskOrderDO.getBillingJson()).eq(StockOutOrder::getOutOrderNumber,handoverTaskOrder.getOrderNumber()));
|
||||
return handoverTaskOrderService.update(null, new UpdateWrapper<HandoverTaskOrder>().lambda()
|
||||
.set(HandoverTaskOrder::getStatus, 2)
|
||||
.set(HandoverTaskOrder::getUpdateBy, loginUser.getUserid())
|
||||
.set(HandoverTaskOrder::getUpdateByName, loginUser.getUsername())
|
||||
.set(HandoverTaskOrder::getUpdateTime, new Date())
|
||||
.set(HandoverTaskOrder::getBillingJson, handoverTaskOrderDO.getBillingJson())
|
||||
.in(HandoverTaskOrder::getHandoverTaskOrderId, handoverTaskOrderIds)
|
||||
);
|
||||
}
|
||||
|
||||
+11
-2
@@ -322,8 +322,17 @@ public class OutMaterialDetailImpl extends ServiceImpl<OutMaterialDetailMapper,
|
||||
// 有子项时,父项不参与库存扣减,避免父项+子项重复扣减导致数量翻倍(子项已代表实际分配)
|
||||
outMaterialDetail.setNowAllocationQuantity(BigDecimal.ZERO);
|
||||
}
|
||||
//记录收货单收货总数
|
||||
totalAllocationQuantity = totalAllocationQuantity.add(outMaterialDetail.getAlreadyAllocationQuantity());
|
||||
// 单头「分配数量」= 本计划行主行已分配 + 各子行已分配(主行字段不再存主+子合计)
|
||||
BigDecimal lineAllocatedSum = outMaterialDetail.getAlreadyAllocationQuantity() != null
|
||||
? outMaterialDetail.getAlreadyAllocationQuantity() : BigDecimal.ZERO;
|
||||
if (!CollectionUtils.isEmpty(materialDetailDOChildList)) {
|
||||
for (OutMaterialDetailDO childDo : materialDetailDOChildList) {
|
||||
BigDecimal childAlloc = childDo.getAlreadyAllocationQuantity() != null
|
||||
? childDo.getAlreadyAllocationQuantity() : BigDecimal.ZERO;
|
||||
lineAllocatedSum = lineAllocatedSum.add(childAlloc);
|
||||
}
|
||||
}
|
||||
totalAllocationQuantity = totalAllocationQuantity.add(lineAllocatedSum);
|
||||
}
|
||||
stockOutOrderPO.setAllocationQuantity(totalAllocationQuantity);
|
||||
//分配(修改库存)
|
||||
|
||||
+2
-3
@@ -664,8 +664,7 @@ public class PickingOrderDomainService {
|
||||
if (1 == pickingOrderPO.getType()) {
|
||||
StockOutOrder forceUpdate = new StockOutOrder();
|
||||
forceUpdate.setOutOrderNumber(pickingOrderPO.getOrderNumber());
|
||||
int forceStatus = (pickingOrderPO.getReview() != null && pickingOrderPO.getReview() == 2) ? 9 : 7;
|
||||
forceUpdate.setStatus(forceStatus);
|
||||
forceUpdate.setStatus(7);
|
||||
forceUpdate.setUpdateBy(loginUser.getUserid());
|
||||
forceUpdate.setUpdateByName(loginUser.getUsername());
|
||||
forceUpdate.setUpdateTime(new Date());
|
||||
@@ -846,4 +845,4 @@ public class PickingOrderDomainService {
|
||||
}
|
||||
deliveTaskService.batchInsert(deliveTaskDOList);
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -83,4 +83,4 @@ public interface IReceiptMaterialDetailService extends IService<ReceiptMaterialD
|
||||
* @return Boolean
|
||||
*/
|
||||
public Boolean noOrderReceiptInsert(StockReceiptOrderDO stockReceiptOrderDO);
|
||||
}
|
||||
}
|
||||
+55
-13
@@ -202,7 +202,7 @@ public class ReceiptMaterialDetailImpl extends ServiceImpl<ReceiptMaterialDetail
|
||||
fillAttributeValueFromInMaterialDetail(ch, materialMoreDetailList);
|
||||
ch.setMaterialMoreDetailList(materialMoreDetailList);
|
||||
});
|
||||
// 首笔只落主计划行、后续批次才 INSERT 子行时:主行上仍有累计实收,列表需在子行之外再带一条「主行首笔」快照(否则只剩子行 500,看不到主行 200)
|
||||
// 首笔只落主计划行、后续批次才 INSERT 子行时:主行上仍有累计实收,列表需在子行之外再带一条「主行首笔」快照
|
||||
if (!children.isEmpty() && parent.getLevel() != null && parent.getLevel() == 1
|
||||
&& parent.getAlreadyReceiptQuantity() != null
|
||||
&& parent.getAlreadyReceiptQuantity().compareTo(BigDecimal.ZERO) > 0) {
|
||||
@@ -407,13 +407,22 @@ public class ReceiptMaterialDetailImpl extends ServiceImpl<ReceiptMaterialDetail
|
||||
// 如果获取失败,记录日志但继续处理
|
||||
}
|
||||
}
|
||||
|
||||
// 仅按「本入库单」与 material_inventory.in_order_number 比对批次是否冲突;避免其它单据已落库的批次拦截本单首笔收货
|
||||
String currentInOrderNumber = resolveCurrentInOrderNumberForBatchReceipt(stockReceiptOrderDO);
|
||||
|
||||
//批量新增或修改物料信息
|
||||
List<ReceiptMaterialDetail> receiptMaterialDetailList = new ArrayList<>();
|
||||
// 批量修改更多属性和新增序列号
|
||||
List<MaterialMoreDetail> materialMoreDetailList = new ArrayList<>();
|
||||
List<InMaterialDetailSerialNumber> materialDetailSerialNumberList = new ArrayList<>();
|
||||
for (ReceiptMaterialDetailDO receiptMaterialDetailDO : receiptMaterialDetailDOList){
|
||||
extractBatchAttributesToReceiptDetail(receiptMaterialDetailDO);
|
||||
// 自动生成批次号并校验唯一性(包括子项)
|
||||
generateAndValidateBatchNumber(receiptMaterialDetailDO, shipperId, currentInOrderNumber);
|
||||
// 当 materialMoreDetailList 为空时(如 PDA 未传),从 receiptMaterialDetailDO 的 batch_number、material_status_code 等字段构建,确保更多属性能保存并回显
|
||||
if (CollectionUtils.isEmpty(receiptMaterialDetailDO.getMaterialMoreDetailList())) {
|
||||
receiptMaterialDetailDO.setMaterialMoreDetailList(buildMaterialMoreDetailFromReceiptFields(receiptMaterialDetailDO));
|
||||
}
|
||||
// 批次号:默认取 Sheet Ref NO's(sheetRefNo),不再自动生成 PC 流水号(逻辑见 generateAndValidateBatchNumber)
|
||||
generateAndValidateBatchNumber(receiptMaterialDetailDO, shipperId);
|
||||
//更多属性
|
||||
@@ -745,7 +754,7 @@ public class ReceiptMaterialDetailImpl extends ServiceImpl<ReceiptMaterialDetail
|
||||
if (StringUtils.isBlank(receiptMaterialDetailPO.getLotNo()) && StringUtils.isNotBlank(inMaterialDetail.getLotNo())) {
|
||||
receiptMaterialDetailPO.setLotNo(inMaterialDetail.getLotNo());
|
||||
}
|
||||
|
||||
|
||||
// 如果materialMoreDetailList为空,直接返回
|
||||
if (CollectionUtils.isEmpty(materialMoreDetailList)) {
|
||||
return;
|
||||
@@ -1201,15 +1210,39 @@ public class ReceiptMaterialDetailImpl extends ServiceImpl<ReceiptMaterialDetail
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析本笔收货对应的入库单号:DO 未带时从收货单主表补全,供批次校验限定「本单」范围。
|
||||
*/
|
||||
private String resolveCurrentInOrderNumberForBatchReceipt(StockReceiptOrderDO stockReceiptOrderDO) {
|
||||
if (stockReceiptOrderDO == null) {
|
||||
return null;
|
||||
}
|
||||
String in = stockReceiptOrderDO.getInOrderNumber();
|
||||
if (StringUtils.isNotBlank(in)) {
|
||||
return in.trim();
|
||||
}
|
||||
Long receiptOrderId = stockReceiptOrderDO.getReceiptOrderId();
|
||||
if (receiptOrderId == null) {
|
||||
return null;
|
||||
}
|
||||
StockReceiptOrder head = stockReceiptOrderMapper.selectById(receiptOrderId);
|
||||
if (head != null && StringUtils.isNotBlank(head.getInOrderNumber())) {
|
||||
return head.getInOrderNumber().trim();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 批次号默认取 Sheet Ref NO's(sheetRefNo),并校验库存唯一性;不再使用 PC 流水号自动生成
|
||||
* @author Auto
|
||||
* @date 2026/1/28
|
||||
* @param receiptMaterialDetailDO 收货明细
|
||||
* @param shipperId 货主ID
|
||||
* @param currentInOrderNumber 当前入库单号,与 material_inventory.in_order_number 一致时才视为本单内批次冲突
|
||||
* @return void
|
||||
*/
|
||||
private void generateAndValidateBatchNumber(ReceiptMaterialDetailDO receiptMaterialDetailDO, Long shipperId) {
|
||||
private void generateAndValidateBatchNumber(ReceiptMaterialDetailDO receiptMaterialDetailDO, Long shipperId,
|
||||
String currentInOrderNumber) {
|
||||
if (receiptMaterialDetailDO == null) {
|
||||
return;
|
||||
}
|
||||
@@ -1220,13 +1253,13 @@ public class ReceiptMaterialDetailImpl extends ServiceImpl<ReceiptMaterialDetail
|
||||
extractBatchAttributesToReceiptDetail(receiptMaterialDetailDO);
|
||||
|
||||
// 处理当前明细
|
||||
processBatchNumberForDetail(receiptMaterialDetailDO, shipperId);
|
||||
processBatchNumberForDetail(receiptMaterialDetailDO, shipperId, currentInOrderNumber);
|
||||
|
||||
// 递归处理子项
|
||||
List<ReceiptMaterialDetailDO> children = receiptMaterialDetailDO.getChildren();
|
||||
if (!CollectionUtils.isEmpty(children)) {
|
||||
for (ReceiptMaterialDetailDO child : children) {
|
||||
generateAndValidateBatchNumber(child, shipperId);
|
||||
generateAndValidateBatchNumber(child, shipperId, currentInOrderNumber);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1237,9 +1270,11 @@ public class ReceiptMaterialDetailImpl extends ServiceImpl<ReceiptMaterialDetail
|
||||
* @date 2026/1/28
|
||||
* @param receiptMaterialDetailDO 收货明细
|
||||
* @param shipperId 货主ID
|
||||
* @param currentInOrderNumber 当前入库单号
|
||||
* @return void
|
||||
*/
|
||||
private void processBatchNumberForDetail(ReceiptMaterialDetailDO receiptMaterialDetailDO, Long shipperId) {
|
||||
private void processBatchNumberForDetail(ReceiptMaterialDetailDO receiptMaterialDetailDO, Long shipperId,
|
||||
String currentInOrderNumber) {
|
||||
if (receiptMaterialDetailDO == null) {
|
||||
return;
|
||||
}
|
||||
@@ -1264,33 +1299,40 @@ public class ReceiptMaterialDetailImpl extends ServiceImpl<ReceiptMaterialDetail
|
||||
batchNumber = receiptMaterialDetailDO.getBatchNumber();
|
||||
|
||||
// 校验批次号唯一性:货主+商品+库存属性值相同时,批次号不能重复
|
||||
|
||||
// 校验批次号:仅本入库单范围内,货主+商品+库存属性+批次在库存中是否已存在(不同入库单允许相同批次号)
|
||||
if (shipperId != null && materialBaseInfoId != null && batchNumber != null && !batchNumber.trim().isEmpty()) {
|
||||
// 使用 LambdaQueryWrapper 查询库存表中是否存在相同的货主+商品+库存属性值+批次号的记录
|
||||
if (StringUtils.isBlank(currentInOrderNumber)) {
|
||||
log.warn("batchReceiptUpdate:未解析到入库单号,跳过库存批次重复校验,receiptOrderNumber={}",
|
||||
receiptMaterialDetailDO != null ? receiptMaterialDetailDO.getReceiptOrderNumber() : null);
|
||||
return;
|
||||
}
|
||||
com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<MaterialInventory> wrapper =
|
||||
new com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper<MaterialInventory>()
|
||||
.eq(MaterialInventory::getShipperId, shipperId)
|
||||
.eq(MaterialInventory::getMaterialBaseInfoId, materialBaseInfoId)
|
||||
.eq(MaterialInventory::getBatchNumber, batchNumber)
|
||||
.eq(MaterialInventory::getDelFlag, 1);
|
||||
.eq(MaterialInventory::getDelFlag, 1)
|
||||
.eq(MaterialInventory::getInOrderNumber, currentInOrderNumber);
|
||||
|
||||
// 如果库存属性值不为空,需要精确匹配;如果为空,查询库存属性值为空或null的记录
|
||||
if (materialStatusCode != null && !materialStatusCode.trim().isEmpty()) {
|
||||
wrapper.eq(MaterialInventory::getMaterialStatusCode, materialStatusCode);
|
||||
} else {
|
||||
// 如果库存属性值为空,查询库存属性值为null或空字符串的记录
|
||||
wrapper.and(w -> w.isNull(MaterialInventory::getMaterialStatusCode)
|
||||
.or()
|
||||
.eq(MaterialInventory::getMaterialStatusCode, ""));
|
||||
}
|
||||
|
||||
List<MaterialInventory> existingInventoryList = materialInventoryMapper.selectList(wrapper);
|
||||
|
||||
// 如果存在相同的货主+商品+库存属性值+批次号的记录,抛出异常
|
||||
|
||||
if (!CollectionUtils.isEmpty(existingInventoryList)) {
|
||||
String statusCodeDesc = (materialStatusCode != null && !materialStatusCode.trim().isEmpty())
|
||||
? ",库存属性值:" + materialStatusCode
|
||||
: ",库存属性值:空";
|
||||
throw new ServiceException("批次号【" + batchNumber + "】已存在,货主ID【" + shipperId + "】+商品ID【" + materialBaseInfoId + "】" + statusCodeDesc + "相同的记录不允许使用重复的批次号");
|
||||
throw new ServiceException("批次号【" + batchNumber + "】在本入库单「" + currentInOrderNumber
|
||||
+ "」下已存在库存,货主ID【" + shipperId + "】+商品ID【" + materialBaseInfoId + "】" + statusCodeDesc
|
||||
+ ",不允许重复使用");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
@@ -112,4 +112,7 @@ public class ReceiptOrderAccount extends BaseVOEntity {
|
||||
@ApiModelProperty(value = "单价")
|
||||
@Excel(name = "单价", width = 15)
|
||||
private BigDecimal price;
|
||||
|
||||
@ApiModelProperty(value = "计算价格json")
|
||||
private String amountJson;
|
||||
}
|
||||
+5
@@ -26,6 +26,11 @@ public interface IShelfMaterialDetailService extends IService<ShelfMaterialDetai
|
||||
*/
|
||||
public List<ShelfMaterialDetailPO> queryListChildren(ShelfMaterialDetailDO shelfMaterialDetailDO);
|
||||
|
||||
/**
|
||||
* PDA:指定计划行(卡片 material_detail_id)下所有 level=2 分批上架子行;可含首笔仅落主行时的主行快照。
|
||||
*/
|
||||
public List<ShelfMaterialDetailPO> queryLevel2ChildrenByParentMaterialDetailId(String shelfOrderNumber, Long parentMaterialDetailId);
|
||||
|
||||
/**
|
||||
* 新增物料明细
|
||||
*/
|
||||
|
||||
+131
-1
@@ -31,8 +31,10 @@ import org.springframework.util.CollectionUtils;
|
||||
import javax.annotation.Resource;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
@@ -123,6 +125,103 @@ public class ShelfMaterialDetailImpl extends ServiceImpl<ShelfMaterialDetailMapp
|
||||
return receiptMaterialDetailPOParentList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ShelfMaterialDetailPO> queryLevel2ChildrenByParentMaterialDetailId(String shelfOrderNumber,
|
||||
Long parentMaterialDetailId) {
|
||||
List<ShelfMaterialDetailPO> empty = new ArrayList<>();
|
||||
if (shelfOrderNumber == null || parentMaterialDetailId == null) {
|
||||
return empty;
|
||||
}
|
||||
ShelfMaterialDetailDO q = new ShelfMaterialDetailDO();
|
||||
q.setShelfOrderNumber(shelfOrderNumber);
|
||||
List<ShelfMaterialDetailPO> all = shelfMaterialDetailMapper.queryList(q);
|
||||
if (CollectionUtils.isEmpty(all)) {
|
||||
return empty;
|
||||
}
|
||||
ShelfMaterialDetailPO anchor = all.stream()
|
||||
.filter(p -> parentMaterialDetailId.equals(p.getMaterialDetailId()))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
if (anchor == null) {
|
||||
return empty;
|
||||
}
|
||||
ShelfMaterialDetailPO parent = anchor;
|
||||
if (anchor.getLevel() != null && anchor.getLevel() == 2 && anchor.getParentUniqueId() != null) {
|
||||
Long puid = anchor.getParentUniqueId();
|
||||
ShelfMaterialDetailPO plan = all.stream()
|
||||
.filter(row -> puid.equals(row.getUniqueId()) || puid.equals(row.getInUniqueId()))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
if (plan != null) {
|
||||
parent = plan;
|
||||
}
|
||||
}
|
||||
Long pid = parent.getUniqueId();
|
||||
Long inPid = parent.getInUniqueId();
|
||||
if (pid == null && inPid == null) {
|
||||
return empty;
|
||||
}
|
||||
final Long fpid = pid;
|
||||
final Long finPid = inPid;
|
||||
List<ShelfMaterialDetailPO> children = all.stream()
|
||||
.filter(m -> m.getLevel() != null && m.getLevel() == 2)
|
||||
.filter(m -> {
|
||||
Long p = m.getParentUniqueId();
|
||||
if (p == null) {
|
||||
return false;
|
||||
}
|
||||
return (fpid != null && p.equals(fpid)) || (finPid != null && p.equals(finPid));
|
||||
})
|
||||
.sorted(Comparator.comparing(ShelfMaterialDetailPO::getCreateTime, Comparator.nullsLast(Comparator.naturalOrder()))
|
||||
.thenComparing(ShelfMaterialDetailPO::getMaterialDetailId, Comparator.nullsLast(Comparator.naturalOrder())))
|
||||
.collect(Collectors.toList());
|
||||
children.forEach(this::enrichShelfRowMaterialMoreDetail);
|
||||
// 首笔只落主计划行、后续批次才 INSERT 子行时:主行上仍有累计已上架,列表需在子行之外再带一条「主行首笔」快照
|
||||
if (!children.isEmpty() && parent.getLevel() != null && parent.getLevel() == 1
|
||||
&& parent.getAlreadyShelvesQuantity() != null
|
||||
&& parent.getAlreadyShelvesQuantity().compareTo(BigDecimal.ZERO) > 0) {
|
||||
ShelfMaterialDetailPO mainSnap = new ShelfMaterialDetailPO();
|
||||
BeanUtils.copyProperties(parent, mainSnap);
|
||||
enrichShelfRowMaterialMoreDetail(mainSnap);
|
||||
children.add(0, mainSnap);
|
||||
}
|
||||
// 未拆 level=2 子行、已上架全部记在主计划行时:仍返回一条与主行一致的快照,供 PDA「历史上架列表」展示
|
||||
if (children.isEmpty() && parent.getAlreadyShelvesQuantity() != null
|
||||
&& parent.getAlreadyShelvesQuantity().compareTo(BigDecimal.ZERO) > 0) {
|
||||
ShelfMaterialDetailPO mainSnap = new ShelfMaterialDetailPO();
|
||||
BeanUtils.copyProperties(parent, mainSnap);
|
||||
enrichShelfRowMaterialMoreDetail(mainSnap);
|
||||
children.add(mainSnap);
|
||||
}
|
||||
return children;
|
||||
}
|
||||
|
||||
/**
|
||||
* 与 queryListChildren 中单行一致:批次更多属性 + 从上架明细填充 attributeValue。
|
||||
*/
|
||||
private void enrichShelfRowMaterialMoreDetail(ShelfMaterialDetailPO row) {
|
||||
if (row == null) {
|
||||
return;
|
||||
}
|
||||
MaterialMoreDetailDO materialMoreDetailDO = new MaterialMoreDetailDO();
|
||||
Long materialDetailUniqueIdForQuery = row.getReceiptUniqueId() != null
|
||||
? row.getReceiptUniqueId() : row.getUniqueId();
|
||||
materialMoreDetailDO.setMaterialDetailUniqueId(materialDetailUniqueIdForQuery);
|
||||
List<MaterialMoreDetailPO> materialMoreDetailList = IMaterialMoreDetailService.queryList(materialMoreDetailDO);
|
||||
if (CollectionUtils.isEmpty(materialMoreDetailList)) {
|
||||
AjaxResult ajaxResult = systemServiceFeign.getBatchDetailListByMaterialBaseInfoId(row.getMaterialBaseInfoId());
|
||||
if (ajaxResult != null && "200".equals(String.valueOf(ajaxResult.get("code")))) {
|
||||
List<BatchDetailFeignPO> batchList = JSON.parseArray(JSONObject.toJSONString(ajaxResult.get("data")), BatchDetailFeignPO.class);
|
||||
materialMoreDetailList = filterAndConvertToMaterialMoreDetail(batchList);
|
||||
}
|
||||
}
|
||||
if (materialMoreDetailList == null) {
|
||||
materialMoreDetailList = new ArrayList<>();
|
||||
}
|
||||
fillAttributeValueFromShelfMaterialDetail(row, materialMoreDetailList);
|
||||
row.setMaterialMoreDetailList(materialMoreDetailList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 过滤 isDisplay=1 的批次属性并转换为 MaterialMoreDetailPO,与收货/PC 端一致
|
||||
*/
|
||||
@@ -309,9 +408,13 @@ public class ShelfMaterialDetailImpl extends ServiceImpl<ShelfMaterialDetailMapp
|
||||
List<ShelfMaterialDetail> shelfMaterialDetailChildList = new ArrayList<>();
|
||||
if (!CollectionUtils.isEmpty(inMaterialDetailDOChildList)){
|
||||
for (ShelfMaterialDetailDO shelfMaterialDetailDOChild : inMaterialDetailDOChildList){
|
||||
// 与收货 batchReceiptUpdate 一致:不强行 setLevel(2)。PDA 可能在 children 中带 parent_copy(与主行同 material_detail_id/unique_id),
|
||||
// 若再强制 level=2,saveOrUpdateBatch 后写会覆盖主行,把主行改成 level=2。
|
||||
if (isShelfParentCopyMirrorRow(shelfMaterialDetailDO, shelfMaterialDetailDOChild)) {
|
||||
continue;
|
||||
}
|
||||
ShelfMaterialDetail shelfMaterialDetailChild = new ShelfMaterialDetail();
|
||||
BeanUtils.copyProperties(shelfMaterialDetailDOChild, shelfMaterialDetailChild);
|
||||
shelfMaterialDetailChild.setLevel(2);
|
||||
shelfMaterialDetailChild.setCreateBy(loginUser.getUserid());
|
||||
shelfMaterialDetailChild.setCreateByName(loginUser.getUsername());
|
||||
shelfMaterialDetailChild.setCreateTime(new Date());
|
||||
@@ -359,6 +462,33 @@ public class ShelfMaterialDetailImpl extends ServiceImpl<ShelfMaterialDetailMapp
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* PDA getInfo 注入的 parent_copy:与主项同 material_detail_id 或 unique_id,仅用于展示;落库子项循环需跳过,避免重复 UPDATE 覆盖主行 level。
|
||||
* 口径与 {@link com.mhd.wms.application.service.stockShelfOrder.StockShelfOrderApplicationService#isShelfParentCopyPo} 一致。
|
||||
*/
|
||||
private static boolean isShelfParentCopyMirrorRow(ShelfMaterialDetailDO parent, ShelfMaterialDetailDO child) {
|
||||
if (parent == null || child == null) {
|
||||
return false;
|
||||
}
|
||||
Long parentId = parent.getMaterialDetailId();
|
||||
Long childId = child.getMaterialDetailId();
|
||||
Long parentUid = parent.getUniqueId();
|
||||
Long childUid = child.getUniqueId();
|
||||
if (parentId != null && Objects.equals(parentId, childId)) {
|
||||
return true;
|
||||
}
|
||||
if (parentUid != null && Objects.equals(parentUid, childUid)) {
|
||||
return true;
|
||||
}
|
||||
if (childId != null && parentId != null && !Objects.equals(childId, parentId)) {
|
||||
return false;
|
||||
}
|
||||
if (childUid != null && parentUid != null && !Objects.equals(childUid, parentUid)) {
|
||||
return false;
|
||||
}
|
||||
return childId == null && childUid == null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 生成流水号
|
||||
* @author ZhouGY
|
||||
|
||||
+7
@@ -356,4 +356,11 @@ public class ShelfMaterialDetailDO extends BaseVOEntity {
|
||||
@ApiModelProperty("抄码数量克重详情")
|
||||
@Excel(name = "抄码数量克重详情")
|
||||
private String copyDetails;
|
||||
|
||||
/**
|
||||
* 服务端内部使用:{@code injectPdaFlatShelfAsSyntheticChild} 已将本次上架量与 total* 挪到新建子行,
|
||||
* assemble 时主行不再把子行增量再累加到 total*(与无 children 时的虚拟子行分支一致)。
|
||||
*/
|
||||
@ApiModelProperty(hidden = true)
|
||||
private Boolean pdaShelfSyntheticChildInjected;
|
||||
}
|
||||
@@ -352,4 +352,12 @@ public class StockInOrder extends BaseVOEntity {
|
||||
@ApiModelProperty("订单状态")
|
||||
@Excel(name = "订单状态")
|
||||
private String orderStatus;
|
||||
@ApiModelProperty(name = "费用参数json")
|
||||
private String billingJson;
|
||||
@ApiModelProperty("结算币种")
|
||||
private String settlementCurrency;
|
||||
@ApiModelProperty("业务员ID")
|
||||
private String salesmanId;
|
||||
@ApiModelProperty("业务员名称")
|
||||
private String salesmanName;
|
||||
}
|
||||
+12
@@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.mhd.common.core.annotation.Excel;
|
||||
import com.mhd.common.core.web.domain.BaseVOEntity;
|
||||
import com.mhd.wms.domain.inMaterialDetail.repository.po.InMaterialDetailPO;
|
||||
import com.mhd.wms.domain.receiptOrderAccount.entity.ReceiptOrderAccount;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
@@ -374,6 +375,17 @@ public class StockInOrderPO extends BaseVOEntity {
|
||||
@Excel(name = "订单状态")
|
||||
private String orderStatus;
|
||||
|
||||
@ApiModelProperty(name = "费用参数json")
|
||||
private String billingJson;
|
||||
@ApiModelProperty("费用")
|
||||
List<ReceiptOrderAccount> receiptOrderAccountList;
|
||||
@ApiModelProperty("结算币种")
|
||||
private String settlementCurrency;
|
||||
@ApiModelProperty("业务员ID")
|
||||
private String salesmanId;
|
||||
@ApiModelProperty("业务员名称")
|
||||
private String salesmanName;
|
||||
|
||||
@ApiModelProperty("批号")
|
||||
private String batchNumber;
|
||||
|
||||
|
||||
+12
@@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.mhd.common.core.annotation.Excel;
|
||||
import com.mhd.common.core.web.domain.BaseVOEntity;
|
||||
import com.mhd.wms.domain.inMaterialDetail.repository.todo.InMaterialDetailDO;
|
||||
import com.mhd.wms.domain.receiptOrderAccount.entity.ReceiptOrderAccount;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
@@ -379,4 +380,15 @@ public class StockInOrderDO extends BaseVOEntity {
|
||||
|
||||
@ApiModelProperty("入库明细-物料编码,模糊匹配")
|
||||
private String materialCode;
|
||||
|
||||
@ApiModelProperty(name = "费用参数json")
|
||||
private String billingJson;
|
||||
@ApiModelProperty("费用")
|
||||
List<ReceiptOrderAccount> receiptOrderAccountList;
|
||||
@ApiModelProperty("结算币种")
|
||||
private String settlementCurrency;
|
||||
@ApiModelProperty("业务员ID")
|
||||
private String salesmanId;
|
||||
@ApiModelProperty("业务员名称")
|
||||
private String salesmanName;
|
||||
}
|
||||
@@ -395,4 +395,14 @@ public class StockOutOrder extends BaseVOEntity {
|
||||
@Excel(name = "制单日期", width = 30, dateFormat = "yyyy-MM-dd")
|
||||
private Date documentDate;
|
||||
|
||||
@ApiModelProperty("计费信息")
|
||||
private String billingJson;
|
||||
|
||||
@ApiModelProperty("结算币种")
|
||||
private String settlementCurrency;
|
||||
@ApiModelProperty("业务员ID")
|
||||
private String salesmanId;
|
||||
@ApiModelProperty("业务员名称")
|
||||
private String salesmanName;
|
||||
|
||||
}
|
||||
+143
-93
@@ -7,6 +7,7 @@ import com.alibaba.excel.read.builder.ExcelReaderBuilder;
|
||||
import com.alibaba.excel.read.metadata.ReadSheet;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.alibaba.fastjson.TypeReference;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.mhd.common.core.domain.po.SysDictDataVo;
|
||||
import com.mhd.common.core.domain.po.UserPo;
|
||||
@@ -35,6 +36,7 @@ import org.springframework.web.multipart.MultipartFile;
|
||||
import javax.annotation.Resource;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@@ -155,10 +157,20 @@ public class ExcelParseService {
|
||||
}
|
||||
|
||||
private void initParam(StockOutOrderDO stockOutOrderDO) {
|
||||
//设置货主信息
|
||||
shipperParam(stockOutOrderDO);
|
||||
//设置客户信息
|
||||
customerParam(stockOutOrderDO);
|
||||
String customerName = stockOutOrderDO.getCustomerName();
|
||||
if (StringUtils.isEmpty(customerName)) {
|
||||
return;
|
||||
}
|
||||
UserPo userPo = resolveCustomerShipperUserPoForImport(customerName);
|
||||
if (userPo == null) {
|
||||
throw new ServiceException("获取客户信息失败:未在名称与货主列表中匹配到当前组织下的客户,请核对名称或改用客户编号/ID");
|
||||
}
|
||||
stockOutOrderDO.setShipperId(userPo.getUserId());
|
||||
stockOutOrderDO.setShipperCode(userPo.getUserMemberCode());
|
||||
stockOutOrderDO.setShipperName(userPo.getUserName());
|
||||
stockOutOrderDO.setCustomerId(userPo.getUserId());
|
||||
stockOutOrderDO.setCustomerCode(userPo.getUserMemberCode());
|
||||
stockOutOrderDO.setCustomerName(userPo.getUserName());
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -168,66 +180,6 @@ public class ExcelParseService {
|
||||
return stockOutOrderDomainService.insert(stockOutOrderDO);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 封装货主信息
|
||||
* @author ZhouGY
|
||||
* @date 2024/5/9 20:43
|
||||
* @param stockOutOrderDO
|
||||
*/
|
||||
private void shipperParam(StockOutOrderDO stockOutOrderDO){
|
||||
String customerName = stockOutOrderDO.getCustomerName();
|
||||
if (StringUtils.isEmpty(customerName)) return;
|
||||
if (!customerName.matches("\\d+")) {
|
||||
AjaxResult ajaxResult = userServiceFeign.getInfoByName(customerName);
|
||||
if(!"200".equals(String.valueOf(ajaxResult.get("code")))){
|
||||
throw new ServiceException("获取客户信息失败");
|
||||
}
|
||||
UserPo userPo = JSON.parseObject(com.alibaba.fastjson2.JSONObject.toJSONString(ajaxResult.get("data")), UserPo.class);
|
||||
stockOutOrderDO.setShipperId(userPo.getUserId());
|
||||
stockOutOrderDO.setShipperCode(userPo.getUserMemberCode());
|
||||
stockOutOrderDO.setShipperName(userPo.getUserName());
|
||||
} else {
|
||||
AjaxResult ajaxResult = userServiceFeign.getInfo(Long.valueOf(customerName));
|
||||
if(!"200".equals(String.valueOf(ajaxResult.get("code")))){
|
||||
throw new ServiceException("获取货主信息失败");
|
||||
}
|
||||
UserPo userPo = JSON.parseObject(com.alibaba.fastjson2.JSONObject.toJSONString(ajaxResult.get("data")), UserPo.class);
|
||||
stockOutOrderDO.setShipperId(userPo.getUserId());
|
||||
stockOutOrderDO.setShipperCode(userPo.getUserMemberCode());
|
||||
stockOutOrderDO.setShipperName(userPo.getUserName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 封装客户信息
|
||||
* @author ZhouGY
|
||||
* @date 2024/5/9 20:43
|
||||
* @param stockOutOrderDO
|
||||
*/
|
||||
private void customerParam(StockOutOrderDO stockOutOrderDO){
|
||||
String customerName = stockOutOrderDO.getCustomerName();
|
||||
if (StringUtils.isEmpty(customerName)) return;
|
||||
if (!customerName.matches("\\d+")) {
|
||||
AjaxResult ajaxResult = userServiceFeign.getInfoByName(customerName);
|
||||
if(!"200".equals(String.valueOf(ajaxResult.get("code")))){
|
||||
throw new ServiceException("获取客户信息失败");
|
||||
}
|
||||
UserPo userPo = JSON.parseObject(com.alibaba.fastjson2.JSONObject.toJSONString(ajaxResult.get("data")), UserPo.class);
|
||||
stockOutOrderDO.setCustomerId(userPo.getUserId());
|
||||
stockOutOrderDO.setCustomerCode(userPo.getUserMemberCode());
|
||||
stockOutOrderDO.setCustomerName(userPo.getUserName());
|
||||
} else {
|
||||
AjaxResult ajaxResult = userServiceFeign.getInfo(Long.valueOf(customerName));
|
||||
if(!"200".equals(String.valueOf(ajaxResult.get("code")))){
|
||||
throw new ServiceException("获取客户信息失败");
|
||||
}
|
||||
UserPo userPo = JSON.parseObject(com.alibaba.fastjson2.JSONObject.toJSONString(ajaxResult.get("data")), UserPo.class);
|
||||
stockOutOrderDO.setCustomerId(userPo.getUserId());
|
||||
stockOutOrderDO.setCustomerCode(userPo.getUserMemberCode());
|
||||
stockOutOrderDO.setCustomerName(userPo.getUserName());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 校验导入明细是否已在当前货主下维护物料基础信息
|
||||
*/
|
||||
@@ -302,41 +254,139 @@ public class ExcelParseService {
|
||||
return errorMsg;
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入出库单:解析出的货主用户是否属于当前登录用户同一组织(organizationId)。
|
||||
* 仅当登录用户带有 organizationId 时启用过滤;否则保持与旧行为一致。
|
||||
*/
|
||||
private boolean shipperMatchesImporterOrganization(UserPo userPo, Long loginOrganizationId) {
|
||||
if (loginOrganizationId == null) {
|
||||
return true;
|
||||
}
|
||||
if (userPo == null) {
|
||||
return false;
|
||||
}
|
||||
Long oid = userPo.getOrganizationId();
|
||||
return oid != null && loginOrganizationId.equals(oid);
|
||||
}
|
||||
|
||||
/**
|
||||
* 按客户名称或数字ID解析货主用户,逻辑与入库单导入一致:getInfoByName → 货主列表兜底,均做 organizationId 校验。
|
||||
*/
|
||||
private UserPo resolveCustomerShipperUserPoForImport(String customerName) {
|
||||
if (StringUtils.isEmpty(customerName)) {
|
||||
return null;
|
||||
}
|
||||
Long loginOrganizationId = null;
|
||||
LoginUser loginUser = SecurityUtils.getLoginUser();
|
||||
if (loginUser != null && loginUser.getUserPo() != null) {
|
||||
loginOrganizationId = loginUser.getUserPo().getOrganizationId();
|
||||
}
|
||||
String shipperName = customerName.trim();
|
||||
if (StringUtils.isEmpty(shipperName)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 纯数字:按用户ID查询
|
||||
if (shipperName.matches("\\d+")) {
|
||||
try {
|
||||
Long possibleId = Long.valueOf(shipperName);
|
||||
AjaxResult ajaxResult = userServiceFeign.getInfo(possibleId);
|
||||
if ("200".equals(String.valueOf(ajaxResult.get("code"))) && ajaxResult.get("data") != null) {
|
||||
UserPo userPo = JSON.parseObject(com.alibaba.fastjson2.JSONObject.toJSONString(ajaxResult.get("data")), UserPo.class);
|
||||
if (userPo != null && shipperMatchesImporterOrganization(userPo, loginOrganizationId)) {
|
||||
return userPo;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// 按名称查询(用户中心)
|
||||
try {
|
||||
AjaxResult ajaxResult = userServiceFeign.getInfoByName(shipperName);
|
||||
if ("200".equals(String.valueOf(ajaxResult.get("code"))) && ajaxResult.get("data") != null) {
|
||||
UserPo userPo = JSON.parseObject(com.alibaba.fastjson2.JSONObject.toJSONString(ajaxResult.get("data")), UserPo.class);
|
||||
if (userPo != null && shipperMatchesImporterOrganization(userPo, loginOrganizationId)) {
|
||||
return userPo;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// 继续货主列表兜底
|
||||
}
|
||||
|
||||
// 货主列表兜底(与入库单 getShipperIdByNameOrCode 一致)
|
||||
try {
|
||||
AjaxResult shipperListResult = userServiceFeign.userShipperListAll();
|
||||
if ("200".equals(String.valueOf(shipperListResult.get("code"))) && shipperListResult.get("data") != null) {
|
||||
Object data = shipperListResult.get("data");
|
||||
List<Map<String, Object>> shipperList = null;
|
||||
if (data instanceof List) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Object> rawList = (List<Object>) data;
|
||||
shipperList = new ArrayList<>();
|
||||
for (Object item : rawList) {
|
||||
if (item instanceof Map) {
|
||||
@SuppressWarnings("unchecked")
|
||||
Map<String, Object> mapItem = (Map<String, Object>) item;
|
||||
shipperList.add(mapItem);
|
||||
} else {
|
||||
Map<String, Object> mapItem = JSON.parseObject(JSONObject.toJSONString(item), Map.class);
|
||||
shipperList.add(mapItem);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
String jsonStr = JSONObject.toJSONString(data);
|
||||
shipperList = JSON.parseObject(jsonStr, new TypeReference<List<Map<String, Object>>>(){});
|
||||
}
|
||||
|
||||
if (shipperList != null && !shipperList.isEmpty()) {
|
||||
String normalizedShipperName = shipperName;
|
||||
for (Map<String, Object> shipper : shipperList) {
|
||||
Object userId = shipper.get("userId");
|
||||
Object userName = shipper.get("userName");
|
||||
if (userName == null) {
|
||||
userName = shipper.get("name");
|
||||
}
|
||||
if (userName == null) {
|
||||
userName = shipper.get("shipperName");
|
||||
}
|
||||
boolean matched = false;
|
||||
if (StringUtils.isNotEmpty(normalizedShipperName) && userName != null) {
|
||||
String normalizedUserName = String.valueOf(userName).trim();
|
||||
if (normalizedShipperName.equals(normalizedUserName)
|
||||
|| normalizedUserName.contains(normalizedShipperName)) {
|
||||
matched = true;
|
||||
}
|
||||
}
|
||||
if (matched && userId != null) {
|
||||
Long candidateId = Long.valueOf(String.valueOf(userId));
|
||||
AjaxResult infoRes = userServiceFeign.getInfo(candidateId);
|
||||
if ("200".equals(String.valueOf(infoRes.get("code"))) && infoRes.get("data") != null) {
|
||||
UserPo up = JSON.parseObject(com.alibaba.fastjson2.JSONObject.toJSONString(infoRes.get("data")), UserPo.class);
|
||||
if (shipperMatchesImporterOrganization(up, loginOrganizationId)) {
|
||||
return up;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// ignore
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 根据客户名称获取货主ID(用于导入时提前获取货主ID)
|
||||
* @param customerName 客户名称(在出库单中,客户名称就是货主名称)
|
||||
* @return 货主ID,如果找不到则返回null
|
||||
*/
|
||||
private Long getShipperIdByCustomerName(String customerName) {
|
||||
if (StringUtils.isEmpty(customerName)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
if (!customerName.matches("\\d+")) {
|
||||
// 按名称查询
|
||||
AjaxResult ajaxResult = userServiceFeign.getInfoByName(customerName);
|
||||
if ("200".equals(String.valueOf(ajaxResult.get("code")))) {
|
||||
UserPo userPo = JSON.parseObject(com.alibaba.fastjson2.JSONObject.toJSONString(ajaxResult.get("data")), UserPo.class);
|
||||
if (userPo != null) {
|
||||
return userPo.getUserId();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 按ID查询
|
||||
AjaxResult ajaxResult = userServiceFeign.getInfo(Long.valueOf(customerName));
|
||||
if ("200".equals(String.valueOf(ajaxResult.get("code")))) {
|
||||
UserPo userPo = JSON.parseObject(com.alibaba.fastjson2.JSONObject.toJSONString(ajaxResult.get("data")), UserPo.class);
|
||||
if (userPo != null) {
|
||||
return userPo.getUserId();
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
// 如果查询失败,返回null,后续在shipperParam方法中会再次尝试
|
||||
}
|
||||
|
||||
return null;
|
||||
UserPo userPo = resolveCustomerShipperUserPoForImport(customerName);
|
||||
return userPo != null ? userPo.getUserId() : null;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+11
@@ -5,6 +5,7 @@ import com.mhd.common.core.annotation.Excel;
|
||||
import com.mhd.common.core.web.domain.BaseVOEntity;
|
||||
import com.mhd.wms.domain.outMaterialDetail.repository.po.OutMaterialCheckPO;
|
||||
import com.mhd.wms.domain.outMaterialDetail.repository.po.OutMaterialDetailPO;
|
||||
import com.mhd.wms.domain.receiptOrderAccount.entity.ReceiptOrderAccount;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
@@ -406,4 +407,14 @@ public class StockOutOrderPO extends BaseVOEntity {
|
||||
@Excel(name = "承运商名称")
|
||||
private String carrierName;
|
||||
|
||||
@ApiModelProperty("计费信息")
|
||||
private String billingJson;
|
||||
@ApiModelProperty("结算币种")
|
||||
private String settlementCurrency;
|
||||
@ApiModelProperty("业务员ID")
|
||||
private String salesmanId;
|
||||
@ApiModelProperty("业务员名称")
|
||||
private String salesmanName;
|
||||
@ApiModelProperty("费用")
|
||||
List<ReceiptOrderAccount> receiptOrderAccountList;
|
||||
}
|
||||
+11
@@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.mhd.common.core.annotation.Excel;
|
||||
import com.mhd.common.core.web.domain.BaseVOEntity;
|
||||
import com.mhd.wms.domain.outMaterialDetail.repository.todo.OutMaterialDetailDO;
|
||||
import com.mhd.wms.domain.receiptOrderAccount.entity.ReceiptOrderAccount;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import org.springframework.format.annotation.DateTimeFormat;
|
||||
@@ -441,4 +442,14 @@ public class StockOutOrderDO extends BaseVOEntity {
|
||||
@ApiModelProperty("承运商名称")
|
||||
@Excel(name = "承运商名称")
|
||||
private String carrierName;
|
||||
@ApiModelProperty("计费信息")
|
||||
private String billingJson;
|
||||
@ApiModelProperty("结算币种")
|
||||
private String settlementCurrency;
|
||||
@ApiModelProperty("业务员ID")
|
||||
private String salesmanId;
|
||||
@ApiModelProperty("业务员名称")
|
||||
private String salesmanName;
|
||||
@ApiModelProperty("费用")
|
||||
List<ReceiptOrderAccount> receiptOrderAccountList;
|
||||
}
|
||||
+3
-2
@@ -129,8 +129,9 @@ public class StockReceiptOrder extends BaseVOEntity {
|
||||
@ApiModelProperty("备注")
|
||||
@Excel(name = "备注")
|
||||
private String remark;
|
||||
@ApiModelProperty(name = "费用参数json")
|
||||
private String billingJson;
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
+3
@@ -180,4 +180,7 @@ public class StockReceiptOrderPO extends StockInOrderBasePO {
|
||||
|
||||
@ApiModelProperty("序号")
|
||||
private String serialNumber;
|
||||
|
||||
@ApiModelProperty(name = "费用参数json")
|
||||
private String billingJson;
|
||||
}
|
||||
+3
@@ -185,4 +185,7 @@ public class StockReceiptOrderDO extends StockInOrderBaseDO {
|
||||
|
||||
@ApiModelProperty("费用")
|
||||
List<ReceiptOrderAccount> receiptOrderAccountList;
|
||||
|
||||
@ApiModelProperty(name = "费用参数json")
|
||||
private String billingJson;
|
||||
}
|
||||
+122
-57
@@ -448,8 +448,9 @@ public class StockReceiptOrderDomainService {
|
||||
genStockReceiptTaskOrderByReceivingGoods(stockReceiptOrderPO,stockReceiptOrderDO);
|
||||
//收货后上架前 生成质检
|
||||
genQualityInspectionByReceivingGoods(stockReceiptOrderDO);
|
||||
saveAmount(stockReceiptOrderDO);
|
||||
//saveAmount(stockReceiptOrderDO);
|
||||
//更新入库单状态
|
||||
stockReceiptOrderPO.setBillingJson(stockReceiptOrderDO.getBillingJson());
|
||||
updateStockInOrder(stockReceiptOrderPO);
|
||||
//修改收货单 设置收货单收货需要更新的数据数据
|
||||
return updateStockReceiptOrder(stockReceiptOrderDO, stockReceiptOrderPO);
|
||||
@@ -468,60 +469,7 @@ public class StockReceiptOrderDomainService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 定时任务整租推送到bms装卸费
|
||||
*/
|
||||
public void wholeRentSynchronizationZXF(Long busId) {
|
||||
StockReceiptOrder stockReceiptOrder = stockReceiptOrderService.getById(busId);
|
||||
String inOrderNumber = stockReceiptOrder.getInOrderNumber();
|
||||
StockInOrder stockInOrder = stockInOrderService.getOne(new QueryWrapper<StockInOrder>().lambda().eq(StockInOrder::getInOrderNumber, inOrderNumber),false);
|
||||
Long shipperId = stockInOrder.getShipperId();
|
||||
Long organizationId = stockInOrder.getOrganizationId();
|
||||
String organizationName = stockInOrder.getOrganizationName();
|
||||
Long topOrganizationId = stockInOrder.getTopOrganizationId();
|
||||
List<ReceiptOrderAccount> accounts = receiptOrderAccountService.list(new QueryWrapper<ReceiptOrderAccount>().lambda().eq(ReceiptOrderAccount::getOrderId, busId));
|
||||
for (ReceiptOrderAccount account : accounts) {
|
||||
String subjectCode = account.getSubjectCode();
|
||||
String subjectName = account.getSubjectName();
|
||||
String serviceItemsCode = account.getServiceItemsCode();
|
||||
if (shipperId == null) {
|
||||
continue;
|
||||
}
|
||||
log.info("开始执行{}", com.alibaba.fastjson.JSONObject.toJSONString(stockReceiptOrder));
|
||||
BusinessDataPushDTO businessDataPushDTO = new BusinessDataPushDTO();
|
||||
businessDataPushDTO.setOrganizationId(organizationId);
|
||||
businessDataPushDTO.setTopOrganizationId(topOrganizationId);
|
||||
businessDataPushDTO.setOrganizationName(organizationName);
|
||||
businessDataPushDTO.setBelongModuleCode("wms");
|
||||
businessDataPushDTO.setBillAmount(account.getAmount());//计费金额
|
||||
businessDataPushDTO.setEstimatedCost(account.getSettlementAmount());//计算金额
|
||||
com.alibaba.fastjson.JSONObject jsonObject = new com.alibaba.fastjson.JSONObject();
|
||||
if ("装卸费".equals(subjectName)) {
|
||||
jsonObject.put("loading_unloading_unit_price", account.getPrice());//装卸货单价
|
||||
jsonObject.put("cargo_quantity",account.getNum());//货物数量
|
||||
} else if ("贴标费".equals(subjectName)) {
|
||||
jsonObject.put("wooden_case_labeling_unit_price", account.getPrice());//木箱单价
|
||||
jsonObject.put("carton_labeling_unit_price",account.getPrice());//纸箱单价
|
||||
jsonObject.put("wooden_case_quantity",account.getNum());//木箱数量
|
||||
jsonObject.put("carton_quantity",account.getNum());//纸箱数量
|
||||
} else if ("进出仓操作费".equals(subjectName)) {
|
||||
jsonObject.put("cargo_quantity", account.getNum());//货物数量
|
||||
jsonObject.put("warehouse_handling_unit_price",account.getPrice());//进出仓操作费单价
|
||||
}
|
||||
businessDataPushDTO.setDocumentFormJson(jsonObject.toJSONString());
|
||||
businessDataPushDTO.setDocumentTypeCode("WMS_ckjccd");
|
||||
businessDataPushDTO.setSettlementEntityId(shipperId);
|
||||
businessDataPushDTO.setSecondSubjectCode(subjectCode);
|
||||
businessDataPushDTO.setServiceItemsCode(serviceItemsCode);
|
||||
businessDataPushDTO.setDataSources(1);
|
||||
businessDataPushDTO.setTaxRate(account.getRate());
|
||||
|
||||
//businessDataPushDTO.setSettlementCurrency(leasePO.getSettlementCurrency());
|
||||
//businessDataPushDTO.setSalesmanId(leasePO.getSalesmanId());
|
||||
bmsServiceFeign.wholeRentSynchronizationZXF(businessDataPushDTO);
|
||||
}
|
||||
log.info("定时任务整租推送到bms触发--结束");
|
||||
}
|
||||
|
||||
/**
|
||||
* 同步更新入库单明细的收货数量(总毛重/总净重/总面积/总体积不再写入入库单明细,逻辑已注释保留)
|
||||
@@ -720,6 +668,91 @@ public class StockReceiptOrderDomainService {
|
||||
* @author ZhouGY
|
||||
* @date 2024/6/14 17:27
|
||||
*/
|
||||
/**
|
||||
* 整单完成判断:只认计划主行(level 空或 1)。分批子行(level=2)不应单独占一票,否则易与主行同组已收尾仍计为「未完结」。
|
||||
*/
|
||||
private static boolean isReceiptPlanLineForOrderCompletionGate(ReceiptMaterialDetailDO d) {
|
||||
Integer lv = d.getLevel();
|
||||
return lv == null || lv == 1;
|
||||
}
|
||||
|
||||
private static boolean sameLongIdForReceiptGate(Long a, Long b) {
|
||||
if (a == null || b == null) {
|
||||
return false;
|
||||
}
|
||||
return a.longValue() == b.longValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否与 {@link com.mhd.wms.application.service.stockReceiptOrder.StockReceiptOrderApplicationService} 中
|
||||
* PDA flatten / 超收校验用的「计划父行下 level=2」范围一致。
|
||||
*/
|
||||
private static boolean isLevel2ChildUnderPlanForReceiptCompletionGate(ReceiptMaterialDetailPO plan, ReceiptMaterialDetailPO x) {
|
||||
if (plan == null || x == null) {
|
||||
return false;
|
||||
}
|
||||
if (x.getLevel() == null || x.getLevel() != 2) {
|
||||
return false;
|
||||
}
|
||||
Long puid = x.getParentUniqueId();
|
||||
if (puid == null || Long.valueOf(0).equals(puid)) {
|
||||
return false;
|
||||
}
|
||||
Long uid = plan.getUniqueId();
|
||||
Long inUid = plan.getInUniqueId();
|
||||
boolean linked = (uid != null && sameLongIdForReceiptGate(uid, puid))
|
||||
|| (inUid != null && sameLongIdForReceiptGate(inUid, puid));
|
||||
if (!linked) {
|
||||
return false;
|
||||
}
|
||||
return plan.getUniqueId() == null || !sameLongIdForReceiptGate(plan.getUniqueId(), x.getUniqueId());
|
||||
}
|
||||
|
||||
private static BigDecimal nzBdGate(BigDecimal v) {
|
||||
return v != null ? v : BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
/** 计划父行自身 already_receipt + 其下归属子行,与 PDA 汇总口径一致 */
|
||||
private static BigDecimal sumAlreadyReceiptUnderPlanForWholeOrderGate(ReceiptMaterialDetailPO plan,
|
||||
List<ReceiptMaterialDetailPO> allRows) {
|
||||
if (plan == null || CollectionUtils.isEmpty(allRows)) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
BigDecimal sum = nzBdGate(plan.getAlreadyReceiptQuantity());
|
||||
for (ReceiptMaterialDetailPO x : allRows) {
|
||||
if (isLevel2ChildUnderPlanForReceiptCompletionGate(plan, x)) {
|
||||
sum = sum.add(nzBdGate(x.getAlreadyReceiptQuantity()));
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
private static boolean isReceiptPlanLinePoForGate(ReceiptMaterialDetailPO p) {
|
||||
if (p == null) {
|
||||
return false;
|
||||
}
|
||||
Integer lv = p.getLevel();
|
||||
return lv == null || lv == 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 计划主行是否仍阻塞整单完成:状态为待收/收货中,且(主+子)累计已收仍低于计划量。
|
||||
* 多批次拆子行后主行 receipt_status 可能长期为 2,但累计已收已满,不得再阻塞。
|
||||
*/
|
||||
private static boolean isPlanLineStillBlockingWholeOrderCompletion(ReceiptMaterialDetailPO plan,
|
||||
List<ReceiptMaterialDetailPO> allDbLines) {
|
||||
Integer st = plan.getReceiptStatus();
|
||||
if (st == null || st >= 3) {
|
||||
return false;
|
||||
}
|
||||
BigDecimal planQty = plan.getQuantity();
|
||||
if (planQty == null) {
|
||||
planQty = BigDecimal.ZERO;
|
||||
}
|
||||
BigDecimal sumAlready = sumAlreadyReceiptUnderPlanForWholeOrderGate(plan, allDbLines);
|
||||
return sumAlready.compareTo(planQty) < 0;
|
||||
}
|
||||
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Boolean updateStockReceiptOrder(StockReceiptOrderDO stockReceiptOrderDO, StockReceiptOrderPO stockReceiptOrderPO) {
|
||||
LoginUser loginUser = SecurityUtils.getLoginUser();
|
||||
@@ -738,13 +771,32 @@ public class StockReceiptOrderDomainService {
|
||||
int addArm = stockReceiptOrderDO.getActualReceiptMaterialQuantity() != null ? stockReceiptOrderDO.getActualReceiptMaterialQuantity() : 0;
|
||||
stockReceiptOrder.setReceiptMaterialQuantity(prevRmq + addArm);
|
||||
}
|
||||
stockReceiptOrder.setBillingJson(stockReceiptOrderDO.getBillingJson());
|
||||
stockReceiptOrder.setStatus(2);
|
||||
stockReceiptOrder.setUpdateBy(loginUser.getUserid());
|
||||
stockReceiptOrder.setUpdateByName(loginUser.getUsername());
|
||||
stockReceiptOrder.setUpdateTime(new Date());
|
||||
stockReceiptOrderService.updateById(stockReceiptOrder);
|
||||
//获取所有明细中的收货状态小于3的数量--未完成收货的明细
|
||||
long receiptMaterialQuantity = stockReceiptOrderDO.getMaterialDetailList().stream().filter(receiptMaterialDetailDO -> receiptMaterialDetailDO.getReceiptStatus() < 3).count();
|
||||
// 必须以落库后的全量明细为准:请求体里的主行 receipt_status 在多批次拆子行后可能仍为「收货中」,
|
||||
// 但主行+子行 already_receipt 已满计划量,不得阻塞 completeReceipt。
|
||||
long receiptMaterialQuantity = 0L;
|
||||
if (StringUtils.isNotBlank(stockReceiptOrderPO.getReceiptOrderNumber())) {
|
||||
ReceiptMaterialDetailDO qAll = new ReceiptMaterialDetailDO();
|
||||
qAll.setReceiptOrderNumber(stockReceiptOrderPO.getReceiptOrderNumber());
|
||||
List<ReceiptMaterialDetailPO> allDbLines = receiptMaterialDetailService.queryList(qAll);
|
||||
if (!CollectionUtils.isEmpty(allDbLines)) {
|
||||
receiptMaterialQuantity = allDbLines.stream()
|
||||
.filter(StockReceiptOrderDomainService::isReceiptPlanLinePoForGate)
|
||||
.filter(p -> isPlanLineStillBlockingWholeOrderCompletion(p, allDbLines))
|
||||
.count();
|
||||
}
|
||||
} else {
|
||||
receiptMaterialQuantity = stockReceiptOrderDO.getMaterialDetailList().stream()
|
||||
.filter(d -> d != null && isReceiptPlanLineForOrderCompletionGate(d))
|
||||
.filter(receiptMaterialDetailDO -> receiptMaterialDetailDO.getReceiptStatus() != null
|
||||
&& receiptMaterialDetailDO.getReceiptStatus() < 3)
|
||||
.count();
|
||||
}
|
||||
//收货数量大于等于计划数量 直接完成收货
|
||||
if (stockReceiptOrder.getReceiptQuantity().compareTo(stockReceiptOrderPO.getQuantity()) >= 0 && receiptMaterialQuantity == 0){
|
||||
completeReceipt(stockReceiptOrderPO.getReceiptOrderId(), stockReceiptOrderDO.getFromPda());
|
||||
@@ -765,6 +817,7 @@ public class StockReceiptOrderDomainService {
|
||||
StockInOrder stockInOrder = new StockInOrder();
|
||||
stockInOrder.setInOrderNumber(stockReceiptOrderPO.getInOrderNumber());
|
||||
stockInOrder.setStatus(3);
|
||||
stockInOrder.setBillingJson(stockReceiptOrderPO.getBillingJson());
|
||||
stockInOrder.setUpdateBy(loginUser.getUserid());
|
||||
stockInOrder.setUpdateByName(loginUser.getUsername());
|
||||
stockInOrder.setUpdateTime(new Date());
|
||||
@@ -837,10 +890,22 @@ public class StockReceiptOrderDomainService {
|
||||
.set(StockReceiptOrder::getUpdateTime, new Date())
|
||||
.eq(StockReceiptOrder::getReceiptOrderId, receiptOrderId));
|
||||
//推送bms
|
||||
wholeRentSynchronizationZXF(receiptOrderId);
|
||||
//wholeRentSynchronizationZXF(receiptOrderId);
|
||||
return update;
|
||||
}
|
||||
|
||||
public void updateInOrder(StockReceiptOrderDTO stockReceiptOrderDTO) {
|
||||
String inOrderNumber = stockReceiptOrderDTO.getInOrderNumber();
|
||||
Long receiptOrderId = stockReceiptOrderDTO.getReceiptOrderId();
|
||||
String billingJson = stockReceiptOrderDTO.getBillingJson();
|
||||
if (inOrderNumber == null) {
|
||||
StockReceiptOrder stockReceiptOrder = stockReceiptOrderService.getById(receiptOrderId);
|
||||
inOrderNumber = stockReceiptOrder.getInOrderNumber();
|
||||
}
|
||||
stockInOrderService.update(null, new UpdateWrapper<StockInOrder>().lambda().set(StockInOrder::getBillingJson,billingJson).eq(StockInOrder::getInOrderNumber, inOrderNumber));
|
||||
stockReceiptOrderService.update(null, new UpdateWrapper<StockReceiptOrder>().lambda().set(StockReceiptOrder::getBillingJson,billingJson).eq(StockReceiptOrder::getReceiptOrderId, receiptOrderId));
|
||||
}
|
||||
|
||||
/**
|
||||
* 收货单完成时:按累计已收与计划数量比较,更新明细 receipt_status(3 正常收完 / 4 少收 / 5 超收)
|
||||
* <p>PC 主子行拆分收货时:计划数量只在主行(level=1),子行 quantity 常为 0;须按「主行已收 + 其下子行已收」与主行计划比较,
|
||||
|
||||
+17
@@ -105,4 +105,21 @@ public class StockShelfOrderPO extends StockInOrderBasePO {
|
||||
@ApiModelProperty("物料明细")
|
||||
private List<ShelfMaterialDetailPO> materialDetailList;
|
||||
|
||||
/** 详情接口按行递归汇总(与收货单 getInfo 一致),供 PC 展示 */
|
||||
@ApiModelProperty("总净重(KG)")
|
||||
@Excel(name = "总净重(KG)")
|
||||
private BigDecimal totalNetWeight;
|
||||
|
||||
@ApiModelProperty("总毛重(KG)")
|
||||
@Excel(name = "总毛重(KG)")
|
||||
private BigDecimal totalGrossWeight;
|
||||
|
||||
@ApiModelProperty("总体积(CBM)")
|
||||
@Excel(name = "总体积(CBM)")
|
||||
private BigDecimal totalVolume;
|
||||
|
||||
@ApiModelProperty("总面积(SQM)")
|
||||
@Excel(name = "总面积(SQM)")
|
||||
private BigDecimal totalArea;
|
||||
|
||||
}
|
||||
|
||||
+246
-1
@@ -7,6 +7,7 @@ import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
|
||||
import com.mhd.common.core.constant.SnowFlakeConstants;
|
||||
import com.mhd.common.core.domain.po.UserPo;
|
||||
@@ -264,7 +265,33 @@ public class StockShelfOrderDomainService {
|
||||
return stockShelfOrderPO;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* PDA:指定计划行(卡片)下所有 level=2 分批上架子行(库表真实子行,不含 parent_copy),附带序列号。
|
||||
*
|
||||
* @param shelfOrderId 上架单主键
|
||||
* @param parentMaterialDetailId 卡片对应 shelf_material_detail.material_detail_id(可误传为某子行 id,将解析到其父计划行)
|
||||
*/
|
||||
public List<ShelfMaterialDetailPO> listLevel2ChildrenByParentForApp(Long shelfOrderId, Long parentMaterialDetailId) {
|
||||
StockShelfOrderPO order = stockShelfOrderService.getInfo(shelfOrderId);
|
||||
if (order == null) {
|
||||
throw new ServiceException("上架单不存在");
|
||||
}
|
||||
List<ShelfMaterialDetailPO> children = shelfMaterialDetailService.queryLevel2ChildrenByParentMaterialDetailId(
|
||||
order.getShelfOrderNumber(), parentMaterialDetailId);
|
||||
if (CollectionUtils.isEmpty(children)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
InMaterialDetailSerialNumberDO snDo = new InMaterialDetailSerialNumberDO();
|
||||
snDo.setOrderNumber(order.getShelfOrderNumber());
|
||||
List<InMaterialDetailSerialNumberPO> snList = inMaterialDetailSerialNumberService.queryList(snDo);
|
||||
Map<Long, List<InMaterialDetailSerialNumberPO>> snMap = snList.stream()
|
||||
.collect(Collectors.groupingBy(InMaterialDetailSerialNumberPO::getMaterialDetailUniqueId));
|
||||
for (ShelfMaterialDetailPO ch : children) {
|
||||
List<InMaterialDetailSerialNumberPO> sns = ch.getUniqueId() != null ? snMap.get(ch.getUniqueId()) : null;
|
||||
ch.setMaterialDetailSerialNumberList(!CollectionUtils.isEmpty(sns) ? sns : new ArrayList<>());
|
||||
}
|
||||
return children;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 任务下发
|
||||
@@ -320,6 +347,10 @@ public class StockShelfOrderDomainService {
|
||||
genContainerUsageRecord(stockShelfOrderDO);
|
||||
//修改物料明细信息
|
||||
shelfMaterialDetailService.batchShelfUpdate(stockShelfOrderDO);
|
||||
LoginUser loginUserUpShelf = SecurityUtils.getLoginUser();
|
||||
String userRealNameUpShelf = resolveUserRealNameForShelf(loginUserUpShelf);
|
||||
refreshShelfMaterialDetailShelvesStatusAfterPartialUpShelf(stockShelfOrderPO.getShelfOrderNumber(), loginUserUpShelf,
|
||||
userRealNameUpShelf);
|
||||
//同步更新入库单明细的上架数量/上架状态
|
||||
syncShelvesQuantityToInMaterialDetail(stockShelfOrderDO);
|
||||
//生成 上架作业单
|
||||
@@ -659,11 +690,225 @@ public class StockShelfOrderDomainService {
|
||||
if (abnormal == 1){
|
||||
genInOrderAbnormal(stockShelfOrderPO);
|
||||
}
|
||||
String userRealNameComplete = resolveUserRealNameForShelf(loginUser);
|
||||
updateShelfMaterialDetailShelvesStatusWhenOrderCompleted(stockShelfOrderPO, loginUser, userRealNameComplete);
|
||||
//推送业务数据到BMS系统
|
||||
// pushSyncBmsDomainService.pushInShelfOrder(stockShelfOrderPO.getInOrderNumber());
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 分批/单次上架提交后:按主行+子行汇总「累计已上架」与主行计划量比较,刷新各明细 shelves_status(待上 1 / 上中 2 / 满 3 / 超 5)
|
||||
*/
|
||||
private void refreshShelfMaterialDetailShelvesStatusAfterPartialUpShelf(String shelfOrderNumber,
|
||||
LoginUser loginUser, String userRealName) {
|
||||
if (StringUtils.isBlank(shelfOrderNumber) || loginUser == null) {
|
||||
return;
|
||||
}
|
||||
Date updateTime = new Date();
|
||||
List<ShelfMaterialDetail> details = shelfMaterialDetailService.list(
|
||||
new QueryWrapper<ShelfMaterialDetail>().lambda()
|
||||
.eq(ShelfMaterialDetail::getShelfOrderNumber, shelfOrderNumber)
|
||||
.eq(ShelfMaterialDetail::getDelFlag, 1));
|
||||
if (CollectionUtils.isEmpty(details)) {
|
||||
return;
|
||||
}
|
||||
Map<Long, List<ShelfMaterialDetail>> childrenByParentUniqueId = new HashMap<>();
|
||||
for (ShelfMaterialDetail d : details) {
|
||||
if (isShelfDetailChildRow(d) && d.getParentUniqueId() != null) {
|
||||
childrenByParentUniqueId.computeIfAbsent(d.getParentUniqueId(), k -> new ArrayList<>()).add(d);
|
||||
}
|
||||
}
|
||||
Set<Long> parentUniqueIdsInOrder = details.stream()
|
||||
.filter(d -> !isShelfDetailChildRow(d))
|
||||
.map(ShelfMaterialDetail::getUniqueId)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toSet());
|
||||
for (ShelfMaterialDetail parent : details) {
|
||||
if (isShelfDetailChildRow(parent)) {
|
||||
continue;
|
||||
}
|
||||
Integer status;
|
||||
List<ShelfMaterialDetail> children = parent.getUniqueId() == null ? null
|
||||
: childrenByParentUniqueId.get(parent.getUniqueId());
|
||||
if (!CollectionUtils.isEmpty(children)) {
|
||||
BigDecimal groupShelved = nzShelf(parent.getAlreadyShelvesQuantity());
|
||||
for (ShelfMaterialDetail ch : children) {
|
||||
groupShelved = groupShelved.add(nzShelf(ch.getAlreadyShelvesQuantity()));
|
||||
}
|
||||
status = deriveShelfDetailStatusWhileOrderOpen(groupShelved, parent.getQuantity());
|
||||
} else {
|
||||
status = deriveShelfDetailStatusWhileOrderOpen(parent.getAlreadyShelvesQuantity(), parent.getQuantity());
|
||||
}
|
||||
parent.setShelvesStatus(status);
|
||||
parent.setUpdateBy(loginUser.getUserid());
|
||||
parent.setUpdateByName(userRealName);
|
||||
parent.setUpdateTime(updateTime);
|
||||
if (!CollectionUtils.isEmpty(children)) {
|
||||
for (ShelfMaterialDetail ch : children) {
|
||||
ch.setShelvesStatus(status);
|
||||
ch.setUpdateBy(loginUser.getUserid());
|
||||
ch.setUpdateByName(userRealName);
|
||||
ch.setUpdateTime(updateTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (ShelfMaterialDetail d : details) {
|
||||
if (isShelfDetailChildRow(d) && d.getParentUniqueId() != null
|
||||
&& !parentUniqueIdsInOrder.contains(d.getParentUniqueId())) {
|
||||
d.setShelvesStatus(deriveShelfDetailStatusWhileOrderOpen(d.getAlreadyShelvesQuantity(), d.getQuantity()));
|
||||
d.setUpdateBy(loginUser.getUserid());
|
||||
d.setUpdateByName(userRealName);
|
||||
d.setUpdateTime(updateTime);
|
||||
}
|
||||
}
|
||||
flushShelfMaterialDetailShelvesStatusColumnsOnly(details, loginUser, userRealName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 整单完成上架:按累计已上架与计划比较,更新明细 shelves_status(3 已上满 / 4 少上 / 5 超上)
|
||||
*/
|
||||
private void updateShelfMaterialDetailShelvesStatusWhenOrderCompleted(StockShelfOrderPO stockShelfOrderPO,
|
||||
LoginUser loginUser, String userRealName) {
|
||||
if (stockShelfOrderPO == null || StringUtils.isBlank(stockShelfOrderPO.getShelfOrderNumber()) || loginUser == null) {
|
||||
return;
|
||||
}
|
||||
Date updateTime = new Date();
|
||||
List<ShelfMaterialDetail> details = shelfMaterialDetailService.list(
|
||||
new QueryWrapper<ShelfMaterialDetail>().lambda()
|
||||
.eq(ShelfMaterialDetail::getShelfOrderNumber, stockShelfOrderPO.getShelfOrderNumber())
|
||||
.eq(ShelfMaterialDetail::getDelFlag, 1));
|
||||
if (CollectionUtils.isEmpty(details)) {
|
||||
return;
|
||||
}
|
||||
Map<Long, List<ShelfMaterialDetail>> childrenByParentUniqueId = new HashMap<>();
|
||||
for (ShelfMaterialDetail d : details) {
|
||||
if (isShelfDetailChildRow(d) && d.getParentUniqueId() != null) {
|
||||
childrenByParentUniqueId.computeIfAbsent(d.getParentUniqueId(), k -> new ArrayList<>()).add(d);
|
||||
}
|
||||
}
|
||||
Set<Long> parentUniqueIdsInOrder = details.stream()
|
||||
.filter(d -> !isShelfDetailChildRow(d))
|
||||
.map(ShelfMaterialDetail::getUniqueId)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.toSet());
|
||||
for (ShelfMaterialDetail parent : details) {
|
||||
if (isShelfDetailChildRow(parent)) {
|
||||
continue;
|
||||
}
|
||||
Integer status;
|
||||
List<ShelfMaterialDetail> children = parent.getUniqueId() == null ? null
|
||||
: childrenByParentUniqueId.get(parent.getUniqueId());
|
||||
if (!CollectionUtils.isEmpty(children)) {
|
||||
BigDecimal groupShelved = nzShelf(parent.getAlreadyShelvesQuantity());
|
||||
for (ShelfMaterialDetail ch : children) {
|
||||
groupShelved = groupShelved.add(nzShelf(ch.getAlreadyShelvesQuantity()));
|
||||
}
|
||||
status = resolveShelfDetailStatusOnOrderComplete(groupShelved, parent.getQuantity());
|
||||
} else {
|
||||
status = resolveShelfDetailStatusOnOrderComplete(parent.getAlreadyShelvesQuantity(), parent.getQuantity());
|
||||
}
|
||||
parent.setShelvesStatus(status);
|
||||
parent.setUpdateBy(loginUser.getUserid());
|
||||
parent.setUpdateByName(userRealName);
|
||||
parent.setUpdateTime(updateTime);
|
||||
if (!CollectionUtils.isEmpty(children)) {
|
||||
for (ShelfMaterialDetail ch : children) {
|
||||
ch.setShelvesStatus(status);
|
||||
ch.setUpdateBy(loginUser.getUserid());
|
||||
ch.setUpdateByName(userRealName);
|
||||
ch.setUpdateTime(updateTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (ShelfMaterialDetail d : details) {
|
||||
if (isShelfDetailChildRow(d) && d.getParentUniqueId() != null
|
||||
&& !parentUniqueIdsInOrder.contains(d.getParentUniqueId())) {
|
||||
d.setShelvesStatus(resolveShelfDetailStatusOnOrderComplete(d.getAlreadyShelvesQuantity(), d.getQuantity()));
|
||||
d.setUpdateBy(loginUser.getUserid());
|
||||
d.setUpdateByName(userRealName);
|
||||
d.setUpdateTime(updateTime);
|
||||
}
|
||||
}
|
||||
flushShelfMaterialDetailShelvesStatusColumnsOnly(details, loginUser, userRealName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 只落库上架状态及审计字段。{@link ShelfMaterialDetail} 查询结果中 total_* 与 alreadyShelves* 曾映射同一列,
|
||||
* 使用 {@code updateBatchById} 会生成重复的 SET 列名(达梦报错)。此处按主键逐条 {@code update(wrapper)} 仅更新必要列。
|
||||
*/
|
||||
private void flushShelfMaterialDetailShelvesStatusColumnsOnly(List<ShelfMaterialDetail> details, LoginUser loginUser,
|
||||
String userRealName) {
|
||||
if (CollectionUtils.isEmpty(details) || loginUser == null) {
|
||||
return;
|
||||
}
|
||||
for (ShelfMaterialDetail d : details) {
|
||||
if (d == null || d.getMaterialDetailId() == null) {
|
||||
continue;
|
||||
}
|
||||
shelfMaterialDetailService.update(null, new LambdaUpdateWrapper<ShelfMaterialDetail>()
|
||||
.set(ShelfMaterialDetail::getShelvesStatus, d.getShelvesStatus())
|
||||
.set(ShelfMaterialDetail::getUpdateBy, loginUser.getUserid())
|
||||
.set(ShelfMaterialDetail::getUpdateByName, userRealName)
|
||||
.set(ShelfMaterialDetail::getUpdateTime, d.getUpdateTime() != null ? d.getUpdateTime() : new Date())
|
||||
.eq(ShelfMaterialDetail::getMaterialDetailId, d.getMaterialDetailId()));
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean isShelfDetailChildRow(ShelfMaterialDetail d) {
|
||||
return d.getLevel() != null && d.getLevel() == 2
|
||||
&& d.getParentUniqueId() != null && d.getParentUniqueId() != 0L;
|
||||
}
|
||||
|
||||
private static BigDecimal nzShelf(BigDecimal v) {
|
||||
return v != null ? v : BigDecimal.ZERO;
|
||||
}
|
||||
|
||||
/** 进行中:1 待上架 / 2 上架中 / 3 已上满 / 5 超上 */
|
||||
private static Integer deriveShelfDetailStatusWhileOrderOpen(BigDecimal alreadyShelvesQuantity, BigDecimal quantity) {
|
||||
BigDecimal already = alreadyShelvesQuantity != null ? alreadyShelvesQuantity : BigDecimal.ZERO;
|
||||
BigDecimal plan = quantity != null ? quantity : BigDecimal.ZERO;
|
||||
if (already.compareTo(BigDecimal.ZERO) == 0) {
|
||||
return 1;
|
||||
}
|
||||
int cmp = already.compareTo(plan);
|
||||
if (cmp < 0) {
|
||||
return 2;
|
||||
}
|
||||
if (cmp > 0) {
|
||||
return 5;
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
|
||||
/** 完成整单:3 已上满 / 4 少上 / 5 超上 */
|
||||
private static Integer resolveShelfDetailStatusOnOrderComplete(BigDecimal alreadyShelvesQuantity, BigDecimal quantity) {
|
||||
BigDecimal already = alreadyShelvesQuantity != null ? alreadyShelvesQuantity : BigDecimal.ZERO;
|
||||
BigDecimal plan = quantity != null ? quantity : BigDecimal.ZERO;
|
||||
int cmp = already.compareTo(plan);
|
||||
if (cmp > 0) {
|
||||
return 5;
|
||||
}
|
||||
if (cmp < 0) {
|
||||
return 4;
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
|
||||
private static String resolveUserRealNameForShelf(LoginUser loginUser) {
|
||||
if (loginUser == null) {
|
||||
return "";
|
||||
}
|
||||
if (loginUser.getUserPo() != null && loginUser.getUserPo().getUserName() != null
|
||||
&& !loginUser.getUserPo().getUserName().trim().isEmpty()) {
|
||||
return loginUser.getUserPo().getUserName();
|
||||
}
|
||||
if (loginUser.getRealname() != null && !loginUser.getRealname().trim().isEmpty()) {
|
||||
return loginUser.getRealname();
|
||||
}
|
||||
return loginUser.getUsername() != null ? loginUser.getUsername() : "";
|
||||
}
|
||||
|
||||
private synchronized void stockIn(List<ShelfMaterialDetail> shelfMaterialDetailDOList, StockShelfOrderDO stockReceiptOrderDO) {
|
||||
for (ShelfMaterialDetail shelfMaterialDetail : shelfMaterialDetailDOList) {
|
||||
Long materialBaseInfoId = shelfMaterialDetail.getMaterialBaseInfoId();
|
||||
|
||||
Reference in New Issue
Block a user