PDA收货上架修改内容
This commit is contained in:
+5
@@ -26,6 +26,11 @@ public interface IReceiptMaterialDetailService extends IService<ReceiptMaterialD
|
||||
*/
|
||||
public List<ReceiptMaterialDetailPO> queryListChildren(ReceiptMaterialDetailDO receiptMaterialDetailDO);
|
||||
|
||||
/**
|
||||
* PDA:按收货单号 + 父计划行 material_detail_id,查询其下 level=2 子行;若无子行但主行已有实收,返回主行快照。
|
||||
*/
|
||||
List<ReceiptMaterialDetailPO> queryLevel2ChildrenByParentMaterialDetailId(String receiptOrderNumber, Long parentMaterialDetailId);
|
||||
|
||||
/**
|
||||
* 新增物料明细
|
||||
*/
|
||||
|
||||
+80
@@ -50,6 +50,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||
import javax.annotation.Resource;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
@@ -146,6 +147,85 @@ public class ReceiptMaterialDetailImpl extends ServiceImpl<ReceiptMaterialDetail
|
||||
return receiptMaterialDetailPOParentList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ReceiptMaterialDetailPO> queryLevel2ChildrenByParentMaterialDetailId(String receiptOrderNumber,
|
||||
Long parentMaterialDetailId) {
|
||||
List<ReceiptMaterialDetailPO> empty = new ArrayList<>();
|
||||
if (receiptOrderNumber == null || parentMaterialDetailId == null) {
|
||||
return empty;
|
||||
}
|
||||
ReceiptMaterialDetailDO q = new ReceiptMaterialDetailDO();
|
||||
q.setReceiptOrderNumber(receiptOrderNumber);
|
||||
List<ReceiptMaterialDetailPO> all = receiptMaterialDetailMapper.queryList(q);
|
||||
if (CollectionUtils.isEmpty(all)) {
|
||||
return empty;
|
||||
}
|
||||
ReceiptMaterialDetailPO anchor = all.stream()
|
||||
.filter(p -> parentMaterialDetailId.equals(p.getMaterialDetailId()))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
if (anchor == null) {
|
||||
return empty;
|
||||
}
|
||||
ReceiptMaterialDetailPO parent = anchor;
|
||||
if (anchor.getLevel() != null && anchor.getLevel() == 2 && anchor.getParentUniqueId() != null) {
|
||||
Long puid = anchor.getParentUniqueId();
|
||||
ReceiptMaterialDetailPO 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<ReceiptMaterialDetailPO> 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(ReceiptMaterialDetailPO::getCreateTime, Comparator.nullsLast(Comparator.naturalOrder()))
|
||||
.thenComparing(ReceiptMaterialDetailPO::getMaterialDetailId, Comparator.nullsLast(Comparator.naturalOrder())))
|
||||
.collect(Collectors.toList());
|
||||
children.forEach(ch -> {
|
||||
List<MaterialMoreDetailPO> materialMoreDetailList = buildMaterialMoreDetailListByMaterialBinding(ch);
|
||||
fillAttributeValueFromInMaterialDetail(ch, materialMoreDetailList);
|
||||
ch.setMaterialMoreDetailList(materialMoreDetailList);
|
||||
});
|
||||
// 首笔只落主计划行、后续批次才 INSERT 子行时:主行上仍有累计实收,列表需在子行之外再带一条「主行首笔」快照
|
||||
if (!children.isEmpty() && parent.getLevel() != null && parent.getLevel() == 1
|
||||
&& parent.getAlreadyReceiptQuantity() != null
|
||||
&& parent.getAlreadyReceiptQuantity().compareTo(BigDecimal.ZERO) > 0) {
|
||||
ReceiptMaterialDetailPO mainSnap = new ReceiptMaterialDetailPO();
|
||||
BeanUtils.copyProperties(parent, mainSnap);
|
||||
List<MaterialMoreDetailPO> mainMore = buildMaterialMoreDetailListByMaterialBinding(mainSnap);
|
||||
fillAttributeValueFromInMaterialDetail(mainSnap, mainMore);
|
||||
mainSnap.setMaterialMoreDetailList(mainMore);
|
||||
children.add(0, mainSnap);
|
||||
}
|
||||
// 未拆 level=2 子行、实收全部记在主计划行时:仍返回一条与主行一致的快照,供 PDA「已收货列表」展示
|
||||
if (children.isEmpty() && parent.getAlreadyReceiptQuantity() != null
|
||||
&& parent.getAlreadyReceiptQuantity().compareTo(BigDecimal.ZERO) > 0) {
|
||||
ReceiptMaterialDetailPO mainSnap = new ReceiptMaterialDetailPO();
|
||||
BeanUtils.copyProperties(parent, mainSnap);
|
||||
List<MaterialMoreDetailPO> materialMoreDetailList = buildMaterialMoreDetailListByMaterialBinding(mainSnap);
|
||||
fillAttributeValueFromInMaterialDetail(mainSnap, materialMoreDetailList);
|
||||
mainSnap.setMaterialMoreDetailList(materialMoreDetailList);
|
||||
children.add(mainSnap);
|
||||
}
|
||||
return children;
|
||||
}
|
||||
|
||||
private void collectUniqueIdsRecursively(ReceiptMaterialDetailPO po, java.util.Set<Long> set) {
|
||||
if (po == null || po.getUniqueId() == null) return;
|
||||
set.add(po.getUniqueId());
|
||||
|
||||
+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
@@ -336,4 +336,11 @@ public class ShelfMaterialDetailDO extends BaseVOEntity {
|
||||
@ApiModelProperty("总面积(SQM)")
|
||||
@Excel(name = "总面积(SQM)")
|
||||
private BigDecimal totalArea;
|
||||
|
||||
/**
|
||||
* 服务端内部使用:{@code injectPdaFlatShelfAsSyntheticChild} 已将本次上架量与 total* 挪到新建子行,
|
||||
* assemble 时主行不再把子行增量再累加到 total*(与无 children 时的虚拟子行分支一致)。
|
||||
*/
|
||||
@ApiModelProperty(hidden = true)
|
||||
private Boolean pdaShelfSyntheticChildInjected;
|
||||
}
|
||||
+133
-2
@@ -257,6 +257,34 @@ public class StockReceiptOrderDomainService {
|
||||
return stockReceiptOrderPO;
|
||||
}
|
||||
|
||||
/**
|
||||
* PDA:指定计划行(卡片)下所有 level=2 分批收货子行(库表真实子行,不含 parent_copy),附带序列号。
|
||||
*
|
||||
* @param receiptOrderId 收货单主键
|
||||
* @param parentMaterialDetailId 卡片对应 receipt_material_detail.material_detail_id(可误传为某子行 id,将解析到其父计划行)
|
||||
*/
|
||||
public List<ReceiptMaterialDetailPO> listLevel2ChildrenByParentForApp(Long receiptOrderId, Long parentMaterialDetailId) {
|
||||
StockReceiptOrderPO order = stockReceiptOrderService.getInfo(receiptOrderId);
|
||||
if (order == null) {
|
||||
throw new ServiceException("收货单不存在");
|
||||
}
|
||||
List<ReceiptMaterialDetailPO> children = receiptMaterialDetailService.queryLevel2ChildrenByParentMaterialDetailId(
|
||||
order.getReceiptOrderNumber(), parentMaterialDetailId);
|
||||
if (CollectionUtils.isEmpty(children)) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
InMaterialDetailSerialNumberDO snDo = new InMaterialDetailSerialNumberDO();
|
||||
snDo.setOrderNumber(order.getReceiptOrderNumber());
|
||||
List<InMaterialDetailSerialNumberPO> snList = inMaterialDetailSerialNumberService.queryList(snDo);
|
||||
Map<Long, List<InMaterialDetailSerialNumberPO>> snMap = snList.stream()
|
||||
.collect(Collectors.groupingBy(InMaterialDetailSerialNumberPO::getMaterialDetailUniqueId));
|
||||
for (ReceiptMaterialDetailPO ch : children) {
|
||||
List<InMaterialDetailSerialNumberPO> sns = ch.getUniqueId() != null ? snMap.get(ch.getUniqueId()) : null;
|
||||
ch.setMaterialDetailSerialNumberList(!CollectionUtils.isEmpty(sns) ? sns : new ArrayList<>());
|
||||
}
|
||||
return children;
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据物料绑定的批次属性动态获取更多属性(按 materialBaseInfoId,不再使用 MaterialGoodsRule.batchId)
|
||||
* @param receiptMaterialDetailPO 收货明细
|
||||
@@ -640,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();
|
||||
@@ -664,8 +777,26 @@ public class StockReceiptOrderDomainService {
|
||||
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());
|
||||
|
||||
+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
@@ -6,6 +6,7 @@ import cn.hutool.json.JSONUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
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;
|
||||
@@ -257,7 +258,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 任务下发
|
||||
@@ -313,6 +340,10 @@ public class StockShelfOrderDomainService {
|
||||
genContainerUsageRecord(stockShelfOrderDO);
|
||||
//修改物料明细信息
|
||||
shelfMaterialDetailService.batchShelfUpdate(stockShelfOrderDO);
|
||||
LoginUser loginUserUpShelf = SecurityUtils.getLoginUser();
|
||||
String userRealNameUpShelf = resolveUserRealNameForShelf(loginUserUpShelf);
|
||||
refreshShelfMaterialDetailShelvesStatusAfterPartialUpShelf(stockShelfOrderPO.getShelfOrderNumber(), loginUserUpShelf,
|
||||
userRealNameUpShelf);
|
||||
//同步更新入库单明细的上架数量/上架状态
|
||||
syncShelvesQuantityToInMaterialDetail(stockShelfOrderDO);
|
||||
//生成 上架作业单
|
||||
@@ -652,11 +683,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