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:
+4
-1
@@ -268,11 +268,13 @@ public class HandoverTaskOrderApplicationService {
|
||||
// 1. PDA上传图片插入交接作业单
|
||||
handoverTaskOrderService.update(new LambdaUpdateWrapper<HandoverTaskOrder>()
|
||||
.eq(HandoverTaskOrder::getOrderNumber, orderNumber)
|
||||
.set(HandoverTaskOrder::getBillingJson, handoverTaskOrderDO.getBillingJson())
|
||||
.set(HandoverTaskOrder::getPictureApp, handoverTaskOrderDO.getPictureApp()));
|
||||
// 2. PDA上传图片插入出库管理,状态改为已出库
|
||||
stockOutOrderService.update(new LambdaUpdateWrapper<StockOutOrder>()
|
||||
.eq(StockOutOrder::getOutOrderNumber, orderNumber)
|
||||
.set(StockOutOrder::getStatus, "9")
|
||||
.set(StockOutOrder::getBillingJson, handoverTaskOrderDO.getBillingJson())
|
||||
.set(StockOutOrder::getPictureApp, handoverTaskOrderDO.getPictureApp()));
|
||||
// 3. 参考PC端完成交接:根据orderNumber查询交接单ID,执行库存扣减+交接状态更新
|
||||
List<HandoverTaskOrder> handoverList = handoverTaskOrderService.list(
|
||||
@@ -286,8 +288,9 @@ public class HandoverTaskOrderApplicationService {
|
||||
if (!handoverTaskOrderIds.isEmpty()) {
|
||||
HandoverTaskOrderDO completeDO = new HandoverTaskOrderDO();
|
||||
completeDO.setHandoverTaskOrderIds(handoverTaskOrderIds);
|
||||
completeDO.setBillingJson(handoverTaskOrderDO.getBillingJson());
|
||||
handoverTaskOrderDomainService.completeHandover(completeDO);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+262
-13
@@ -3,7 +3,12 @@ package com.mhd.wms.application.service.stockInOrder;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.TypeReference;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.mhd.common.core.domain.dto.BusinessDataPushDTO;
|
||||
import com.mhd.common.core.domain.po.UserPo;
|
||||
import com.mhd.common.core.enums.DictCode;
|
||||
import com.mhd.common.core.exception.ServiceException;
|
||||
@@ -11,6 +16,7 @@ import com.mhd.common.core.utils.StringUtils;
|
||||
import com.mhd.common.core.utils.poi.ExcelUtil;
|
||||
import com.mhd.common.core.web.domain.AjaxResult;
|
||||
import com.mhd.common.security.utils.SecurityUtils;
|
||||
import com.mhd.system.api.BmsServiceFeign;
|
||||
import com.mhd.system.api.SystemServiceFeign;
|
||||
import com.mhd.system.api.UserServiceFeign;
|
||||
import com.mhd.system.api.domain.SysDictData;
|
||||
@@ -18,17 +24,29 @@ import com.mhd.system.api.domain.WarehouseFeignPO;
|
||||
import com.mhd.system.api.domain.cache.AssociationWarehouseCacheDO;
|
||||
import com.mhd.system.api.domain.cache.SystemServiceCacheUtil;
|
||||
import com.mhd.system.api.model.LoginUser;
|
||||
import com.mhd.wms.domain.handoverTaskOrder.entity.HandoverTaskOrder;
|
||||
import com.mhd.wms.domain.handoverTaskOrder.repository.facade.IHandoverTaskOrderService;
|
||||
import com.mhd.wms.domain.inMaterialDetail.entity.InMaterialDetail;
|
||||
import com.mhd.wms.domain.inMaterialDetail.repository.todo.InMaterialDetailDO;
|
||||
import com.mhd.wms.domain.materialBaseInfo.entity.MaterialBaseInfo;
|
||||
import com.mhd.wms.domain.materialBaseInfo.repository.facade.IMaterialBaseInfoService;
|
||||
import com.mhd.wms.domain.materialBaseInfo.repository.po.MaterialBaseInfoPO;
|
||||
import com.mhd.wms.domain.materialBaseInfo.repository.todo.MaterialBaseInfoDO;
|
||||
import com.mhd.wms.domain.receiptOrderAccount.entity.ReceiptOrderAccount;
|
||||
import com.mhd.wms.domain.receiptOrderAccount.repository.facade.IReceiptOrderAccountService;
|
||||
import com.mhd.wms.domain.stockInOrder.entity.StockInOrder;
|
||||
import com.mhd.wms.domain.stockInOrder.repository.facade.IStockInOrderService;
|
||||
import com.mhd.wms.domain.stockInOrder.entity.StockInOrder;
|
||||
import com.mhd.wms.domain.stockInOrder.repository.po.StockInOrderPO;
|
||||
import com.mhd.wms.domain.stockInOrder.repository.todo.StockInOrderDO;
|
||||
import com.mhd.wms.domain.stockInOrder.service.StockInOrderDomainService;
|
||||
import com.mhd.wms.interfaces.dto.stockInOrder.StockInOrderDTO;
|
||||
import com.mhd.wms.domain.stockOutOrder.entity.StockOutOrder;
|
||||
import com.mhd.wms.domain.stockOutOrder.repository.facade.IStockOutOrderService;
|
||||
import com.mhd.wms.domain.stockOutOrder.repository.todo.StockOutOrderDO;
|
||||
import com.mhd.wms.domain.stockReceiptOrder.entity.StockReceiptOrder;
|
||||
import com.mhd.wms.domain.stockReceiptOrder.repository.facade.IStockReceiptOrderService;
|
||||
import com.mhd.wms.domain.stockReceiptOrder.repository.todo.StockReceiptOrderDO;
|
||||
import com.mhd.wms.interfaces.dto.stockInOrder.StockInOrderImportRowDTO;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.poi.ss.usermodel.*;
|
||||
@@ -37,6 +55,7 @@ import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.InputStream;
|
||||
import java.math.BigDecimal;
|
||||
import java.text.ParseException;
|
||||
@@ -58,12 +77,24 @@ import java.util.stream.Collectors;
|
||||
public class StockInOrderApplicationService {
|
||||
@Autowired
|
||||
private StockInOrderDomainService stockInOrderDomainService;
|
||||
@Autowired
|
||||
@Resource
|
||||
private UserServiceFeign userServiceFeign;
|
||||
@Autowired
|
||||
@Resource
|
||||
private SystemServiceFeign systemServiceFeign;
|
||||
@Resource
|
||||
private BmsServiceFeign bmsServiceFeign;
|
||||
@Autowired
|
||||
private IMaterialBaseInfoService materialBaseInfoService;
|
||||
@Resource
|
||||
private IReceiptOrderAccountService receiptOrderAccountService;
|
||||
@Autowired
|
||||
private IStockInOrderService stockInOrderService;
|
||||
@Autowired
|
||||
private IStockReceiptOrderService stockReceiptOrderService;
|
||||
@Autowired
|
||||
private IStockOutOrderService stockOutOrderService;
|
||||
@Autowired
|
||||
private IHandoverTaskOrderService handoverTaskOrderService;
|
||||
|
||||
|
||||
/**
|
||||
@@ -157,7 +188,13 @@ public class StockInOrderApplicationService {
|
||||
}
|
||||
}
|
||||
}
|
||||
return stockInOrderDomainService.queryList(stockInOrderDO);
|
||||
List<StockInOrderPO> stockInOrderPOS = stockInOrderDomainService.queryList(stockInOrderDO);
|
||||
for (StockInOrderPO stockInOrderPO : stockInOrderPOS) {
|
||||
Long inOrderId = stockInOrderPO.getInOrderId();
|
||||
List<ReceiptOrderAccount> list = receiptOrderAccountService.list(new LambdaQueryWrapper<ReceiptOrderAccount>().eq(ReceiptOrderAccount::getOrderId, inOrderId));
|
||||
stockInOrderPO.setReceiptOrderAccountList(list);
|
||||
}
|
||||
return stockInOrderPOS;
|
||||
}
|
||||
|
||||
|
||||
@@ -203,6 +240,176 @@ public class StockInOrderApplicationService {
|
||||
return stockInOrderDomainService.update(stockInOrderDO);
|
||||
}
|
||||
|
||||
public Boolean saveAmount(StockInOrderDO stockInOrderDO) {
|
||||
boolean r = true;
|
||||
Long inOrderId = stockInOrderDO.getInOrderId();
|
||||
String inOrderNumber = stockInOrderDO.getInOrderNumber();
|
||||
String billingJson = stockInOrderDO.getBillingJson();
|
||||
if (billingJson != null) {
|
||||
stockInOrderService.update(null,new LambdaUpdateWrapper<StockInOrder>().set(StockInOrder::getBillingJson,billingJson).eq(StockInOrder::getInOrderId,inOrderId));
|
||||
stockReceiptOrderService.update(null,new LambdaUpdateWrapper<StockReceiptOrder>().set(StockReceiptOrder::getBillingJson,billingJson).eq(StockReceiptOrder::getInOrderNumber,inOrderNumber));
|
||||
}
|
||||
receiptOrderAccountService.remove(new QueryWrapper<ReceiptOrderAccount>().lambda().eq(ReceiptOrderAccount::getOrderId, inOrderId));
|
||||
List<ReceiptOrderAccount> receiptOrderAccountList = stockInOrderDO.getReceiptOrderAccountList();
|
||||
if (receiptOrderAccountList != null && !receiptOrderAccountList.isEmpty()) {
|
||||
for (ReceiptOrderAccount receiptOrderAccount : receiptOrderAccountList) {
|
||||
receiptOrderAccount.setOrderId(inOrderId);
|
||||
}
|
||||
r = receiptOrderAccountService.saveBatch(receiptOrderAccountList);
|
||||
wholeRentSynchronizationZXF(inOrderId);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
public Boolean saveOutAmount(StockOutOrderDO stockOutOrderDO) {
|
||||
boolean r = true;
|
||||
Long outOrderId = stockOutOrderDO.getOutOrderId();
|
||||
String outOrderNumber = stockOutOrderDO.getOutOrderNumber();
|
||||
String billingJson = stockOutOrderDO.getBillingJson();
|
||||
if (billingJson != null) {
|
||||
stockOutOrderService.update(null,new LambdaUpdateWrapper<StockOutOrder>().set(StockOutOrder::getBillingJson,billingJson).eq(StockOutOrder::getOutOrderId,outOrderId));
|
||||
handoverTaskOrderService.update(null,new LambdaUpdateWrapper<HandoverTaskOrder>().set(HandoverTaskOrder::getBillingJson,billingJson).eq(HandoverTaskOrder::getOrderNumber,outOrderNumber));
|
||||
}
|
||||
receiptOrderAccountService.remove(new QueryWrapper<ReceiptOrderAccount>().lambda().eq(ReceiptOrderAccount::getOrderId, outOrderId));
|
||||
List<ReceiptOrderAccount> receiptOrderAccountList = stockOutOrderDO.getReceiptOrderAccountList();
|
||||
if (receiptOrderAccountList != null && !receiptOrderAccountList.isEmpty()) {
|
||||
for (ReceiptOrderAccount receiptOrderAccount : receiptOrderAccountList) {
|
||||
receiptOrderAccount.setOrderId(outOrderId);
|
||||
}
|
||||
r = receiptOrderAccountService.saveBatch(receiptOrderAccountList);
|
||||
wholeRentSynchronizationZXF(outOrderId);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
/**
|
||||
* 定时任务整租推送到bms装卸费
|
||||
*/
|
||||
public void wholeRentSynchronizationZXF(Long busId) {
|
||||
StockInOrder stockInOrder = stockInOrderService.getOne(new QueryWrapper<StockInOrder>().lambda().eq(StockInOrder::getInOrderId, busId),false);
|
||||
StockOutOrder stockOutOrder = stockOutOrderService.getOne(new QueryWrapper<StockOutOrder>().lambda().eq(StockOutOrder::getOutOrderId, busId),false);
|
||||
if (stockInOrder != null) {
|
||||
Long shipperId = stockInOrder.getShipperId();
|
||||
Long organizationId = stockInOrder.getOrganizationId();
|
||||
String organizationName = stockInOrder.getOrganizationName();
|
||||
Long topOrganizationId = stockInOrder.getTopOrganizationId();
|
||||
String inOrderNumber = stockInOrder.getInOrderNumber();
|
||||
String settlementCurrency = stockInOrder.getSettlementCurrency();
|
||||
String salesmanId = stockInOrder.getSalesmanId();
|
||||
List<ReceiptOrderAccount> accounts = receiptOrderAccountService.list(new QueryWrapper<ReceiptOrderAccount>().lambda().eq(ReceiptOrderAccount::getOrderId, busId));
|
||||
for (ReceiptOrderAccount account : accounts) {
|
||||
BigDecimal amount = account.getAmount();
|
||||
String subjectCode = account.getSubjectCode();
|
||||
String subjectName = account.getSubjectName();
|
||||
|
||||
String serviceItemsCode = account.getServiceItemsCode();
|
||||
if (shipperId == null) {
|
||||
continue;
|
||||
}
|
||||
BusinessDataPushDTO businessDataPushDTO = new BusinessDataPushDTO();
|
||||
businessDataPushDTO.setOrganizationId(organizationId);
|
||||
businessDataPushDTO.setTopOrganizationId(topOrganizationId);
|
||||
businessDataPushDTO.setOrganizationName(organizationName);
|
||||
businessDataPushDTO.setBelongModuleCode("wms");
|
||||
businessDataPushDTO.setBillAmount(account.getAmount());//计费金额
|
||||
businessDataPushDTO.setEstimatedCost(account.getSettlementAmount());//计算金额
|
||||
businessDataPushDTO.setOriginalBusinessNum(inOrderNumber);
|
||||
String amountJson = account.getAmountJson();
|
||||
if (amountJson != null) {
|
||||
List<Map<String, Object>> billingParamsList = JSON.parseObject(amountJson, new TypeReference<List<Map<String, Object>>>() {});
|
||||
com.alibaba.fastjson.JSONObject jsonObject = new com.alibaba.fastjson.JSONObject();
|
||||
for (Map<String, Object> stringObjectMap : billingParamsList) {
|
||||
String isFee = (String) stringObjectMap.get("isFee");
|
||||
if ("1".equals(isFee)) {
|
||||
jsonObject.put((String) stringObjectMap.get("fields"), stringObjectMap.get("price"));
|
||||
} else {
|
||||
jsonObject.put((String) stringObjectMap.get("fields"), stringObjectMap.get("num"));
|
||||
}
|
||||
}
|
||||
businessDataPushDTO.setDocumentFormJson(jsonObject.toJSONString());
|
||||
}
|
||||
/*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.setDocumentTypeCode("WMS_ckjccd");
|
||||
businessDataPushDTO.setSettlementEntityId(shipperId);
|
||||
businessDataPushDTO.setSecondSubjectCode(subjectCode);
|
||||
businessDataPushDTO.setServiceItemsCode(serviceItemsCode);
|
||||
businessDataPushDTO.setDataSources(1);
|
||||
businessDataPushDTO.setTaxRate(account.getRate());
|
||||
|
||||
businessDataPushDTO.setSettlementCurrency(settlementCurrency);
|
||||
businessDataPushDTO.setSalesmanId(salesmanId);
|
||||
if (amount != null&&amount.compareTo(BigDecimal.ZERO)!=0) {
|
||||
bmsServiceFeign.wholeRentSynchronizationZXF(businessDataPushDTO);
|
||||
}
|
||||
}
|
||||
} else if (stockOutOrder != null) {
|
||||
Long shipperId = stockOutOrder.getShipperId();
|
||||
Long organizationId = stockOutOrder.getOrganizationId();
|
||||
String organizationName = stockOutOrder.getOrganizationName();
|
||||
Long topOrganizationId = stockOutOrder.getTopOrganizationId();
|
||||
String inOrderNumber = stockOutOrder.getOutOrderNumber();
|
||||
String settlementCurrency = stockOutOrder.getSettlementCurrency();
|
||||
String salesmanId = stockOutOrder.getSalesmanId();
|
||||
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;
|
||||
}
|
||||
BusinessDataPushDTO businessDataPushDTO = new BusinessDataPushDTO();
|
||||
businessDataPushDTO.setOrganizationId(organizationId);
|
||||
businessDataPushDTO.setTopOrganizationId(topOrganizationId);
|
||||
businessDataPushDTO.setOrganizationName(organizationName);
|
||||
businessDataPushDTO.setBelongModuleCode("wms");
|
||||
businessDataPushDTO.setBillAmount(account.getAmount());//计费金额
|
||||
businessDataPushDTO.setEstimatedCost(account.getSettlementAmount());//计算金额
|
||||
businessDataPushDTO.setOriginalBusinessNum(inOrderNumber);
|
||||
String amountJson = account.getAmountJson();
|
||||
if (amountJson!=null) {
|
||||
List<Map<String, Object>> billingParamsList = JSON.parseObject(amountJson, new TypeReference<List<Map<String, Object>>>() {});
|
||||
com.alibaba.fastjson.JSONObject jsonObject = new com.alibaba.fastjson.JSONObject();
|
||||
for (Map<String, Object> stringObjectMap : billingParamsList) {
|
||||
String isFee = (String) stringObjectMap.get("isFee");
|
||||
if ("1".equals(isFee)) {
|
||||
jsonObject.put((String) stringObjectMap.get("fields"), stringObjectMap.get("price"));
|
||||
} else {
|
||||
jsonObject.put((String) stringObjectMap.get("fields"), stringObjectMap.get("num"));
|
||||
}
|
||||
}
|
||||
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(settlementCurrency);
|
||||
businessDataPushDTO.setSalesmanId(salesmanId);
|
||||
bmsServiceFeign.wholeRentSynchronizationZXF(businessDataPushDTO);
|
||||
}
|
||||
} else {
|
||||
throw new RuntimeException("未找到业务单!");
|
||||
}
|
||||
|
||||
log.info("定时任务整租推送到bms触发--结束");
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除入库单
|
||||
* 只有已创建状态(status = 1)的入库单可以删除
|
||||
@@ -1640,6 +1847,21 @@ public class StockInOrderApplicationService {
|
||||
stockInOrderDO.setWarehouseName(warehouseFeignPO.getWarehouseName());
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入入库单:解析出的货主用户是否属于当前登录用户同一组织(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);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 根据货主名称或编号获取货主ID(用于导入时提前获取货主ID)
|
||||
* @param shipperName 货主名称
|
||||
@@ -1650,7 +1872,13 @@ public class StockInOrderApplicationService {
|
||||
if (StringUtils.isBlank(shipperName) && StringUtils.isBlank(shipperCode)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
Long loginOrganizationId = null;
|
||||
LoginUser loginUser = SecurityUtils.getLoginUser();
|
||||
if (loginUser != null && loginUser.getUserPo() != null) {
|
||||
loginOrganizationId = loginUser.getUserPo().getOrganizationId();
|
||||
}
|
||||
|
||||
Long shipperId = null;
|
||||
|
||||
// 优先尝试:如果名称是纯数字,可能是误传的ID,直接按ID查询
|
||||
@@ -1660,29 +1888,37 @@ public class StockInOrderApplicationService {
|
||||
AjaxResult ajaxResult = userServiceFeign.getInfo(possibleId);
|
||||
if ("200".equals(String.valueOf(ajaxResult.get("code"))) && ajaxResult.get("data") != null) {
|
||||
UserPo userPo = JSON.parseObject(JSONObject.toJSONString(ajaxResult.get("data")), UserPo.class);
|
||||
if (userPo != null) {
|
||||
if (userPo != null && shipperMatchesImporterOrganization(userPo, loginOrganizationId)) {
|
||||
shipperId = userPo.getUserId();
|
||||
log.info("根据货主名称(实际为ID)找到货主ID:{}", shipperId);
|
||||
log.info("根据货主名称(实际为ID)找到货主ID:{},organizationId={}", shipperId, loginOrganizationId);
|
||||
return shipperId;
|
||||
}
|
||||
if (userPo != null) {
|
||||
log.info("按ID查到用户但与当前登录组织不一致,忽略。userId={},货主organizationId={},当前登录organizationId={}",
|
||||
userPo.getUserId(), userPo.getOrganizationId(), loginOrganizationId);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.debug("尝试将货主名称作为ID查询失败,货主名称:{},错误:{}", shipperName, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// 如果仍未找到,尝试根据名称查询
|
||||
// 如果仍未找到,尝试根据名称查询(用户中心 user_name 等值匹配)
|
||||
if (shipperId == null && StringUtils.isNotEmpty(shipperName) && !shipperName.matches("\\d+")) {
|
||||
try {
|
||||
AjaxResult ajaxResult = userServiceFeign.getInfoByName(shipperName);
|
||||
String code = String.valueOf(ajaxResult.get("code"));
|
||||
if ("200".equals(code) && ajaxResult.get("data") != null) {
|
||||
UserPo userPo = JSON.parseObject(JSONObject.toJSONString(ajaxResult.get("data")), UserPo.class);
|
||||
if (userPo != null) {
|
||||
if (userPo != null && shipperMatchesImporterOrganization(userPo, loginOrganizationId)) {
|
||||
shipperId = userPo.getUserId();
|
||||
log.info("根据货主名称找到货主ID,货主名称:{},货主ID:{}", shipperName, shipperId);
|
||||
log.info("根据货主名称找到货主ID,货主名称:{},货主ID:{},organizationId={}", shipperName, shipperId, loginOrganizationId);
|
||||
return shipperId;
|
||||
}
|
||||
if (userPo != null) {
|
||||
log.info("按名称查到用户但与当前登录组织不一致,继续从货主列表匹配。userId={},货主organizationId={},当前登录organizationId={}",
|
||||
userPo.getUserId(), userPo.getOrganizationId(), loginOrganizationId);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.debug("根据货主名称查询失败,货主名称:{},错误:{}", shipperName, e.getMessage());
|
||||
@@ -1752,10 +1988,23 @@ public class StockInOrderApplicationService {
|
||||
}
|
||||
|
||||
if (matched && userId != null) {
|
||||
shipperId = Long.valueOf(String.valueOf(userId));
|
||||
log.info("从货主列表中找到货主ID,货主名称:{},货主编号:{},货主ID:{}",
|
||||
shipperName, shipperCode, shipperId);
|
||||
return shipperId;
|
||||
Long candidateId = Long.valueOf(String.valueOf(userId));
|
||||
try {
|
||||
AjaxResult infoRes = userServiceFeign.getInfo(candidateId);
|
||||
if ("200".equals(String.valueOf(infoRes.get("code"))) && infoRes.get("data") != null) {
|
||||
UserPo up = JSON.parseObject(JSONObject.toJSONString(infoRes.get("data")), UserPo.class);
|
||||
if (shipperMatchesImporterOrganization(up, loginOrganizationId)) {
|
||||
shipperId = candidateId;
|
||||
log.info("从货主列表中找到货主ID,货主名称:{},货主编号:{},货主ID:{},organizationId={}",
|
||||
shipperName, shipperCode, shipperId, loginOrganizationId);
|
||||
return shipperId;
|
||||
}
|
||||
log.info("货主列表匹配到用户但与当前登录组织不一致,跳过。userId={},货主organizationId={},当前登录organizationId={}",
|
||||
candidateId, up != null ? up.getOrganizationId() : null, loginOrganizationId);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
log.debug("校验货主组织时查询用户信息失败,userId={},{}", candidateId, ex.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+83
-14
@@ -40,6 +40,8 @@ import com.mhd.wms.domain.outMaterialDetail.service.OutMaterialDetailDomainServi
|
||||
import com.mhd.wms.domain.pickingMaterialDetail.repository.facade.IPickingMaterialDetailService;
|
||||
import com.mhd.wms.domain.pickingMaterialDetail.repository.po.PickingMaterialDetailPO;
|
||||
import com.mhd.wms.domain.stockInOrder.entity.StockInOrder;
|
||||
import com.mhd.wms.domain.receiptOrderAccount.entity.ReceiptOrderAccount;
|
||||
import com.mhd.wms.domain.receiptOrderAccount.repository.facade.IReceiptOrderAccountService;
|
||||
import com.mhd.wms.domain.stockOutOrder.entity.StockOutOrder;
|
||||
import com.mhd.wms.domain.stockOutOrder.repository.facade.IStockOutOrderService;
|
||||
import com.mhd.wms.domain.stockOutOrder.repository.po.StockOutOrderPO;
|
||||
@@ -86,6 +88,8 @@ public class StockOutOrderApplicationService {
|
||||
private IOutMaterialDetailService outMaterialDetailService;
|
||||
@Autowired
|
||||
private IPickingMaterialDetailService pickingMaterialDetailService;
|
||||
@Autowired
|
||||
private IReceiptOrderAccountService receiptOrderAccountService;
|
||||
|
||||
|
||||
/**
|
||||
@@ -212,6 +216,8 @@ public class StockOutOrderApplicationService {
|
||||
// 复核总数量:从out_material_detail汇总check_quantity
|
||||
BigDecimal checkSum = materialDetailList.stream().map(OutMaterialDetailPO::getCheckQuantity).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
stockOutOrderPO.setCheckQuantity(checkSum);
|
||||
List<ReceiptOrderAccount> list = receiptOrderAccountService.list(new LambdaQueryWrapper<ReceiptOrderAccount>().eq(ReceiptOrderAccount::getOrderId, stockOutOrderPO.getOutOrderId()));
|
||||
stockOutOrderPO.setReceiptOrderAccountList(list);
|
||||
}
|
||||
return stockOutOrderPOS;
|
||||
}
|
||||
@@ -868,12 +874,32 @@ public class StockOutOrderApplicationService {
|
||||
*/
|
||||
public Boolean cancelAssign(StockOutOrderDO stockOutOrderDO){
|
||||
StockOutOrderPO infoChildren = getInfoChildren(stockOutOrderDO.getOutOrderId());
|
||||
BigDecimal alreadyAllocationQuantityAll = infoChildren.getMaterialDetailList().stream().map(OutMaterialDetailPO::getAlreadyAllocationQuantity)
|
||||
.filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
BigDecimal alreadyAllocationQuantityAll = BigDecimal.ZERO;
|
||||
if (infoChildren != null && !CollectionUtils.isEmpty(infoChildren.getMaterialDetailList())) {
|
||||
for (OutMaterialDetailPO line : infoChildren.getMaterialDetailList()) {
|
||||
alreadyAllocationQuantityAll = alreadyAllocationQuantityAll.add(sumAlreadyAllocationInclusive(line));
|
||||
}
|
||||
}
|
||||
stockOutOrderDO.setAlreadyAllocationQuantityAll(alreadyAllocationQuantityAll);
|
||||
return stockOutOrderDomainService.cancelAssign(stockOutOrderDO);
|
||||
}
|
||||
|
||||
/** 计划行(含子行)已分配数量之和,用于单头汇总、取消分配等 */
|
||||
private static BigDecimal sumAlreadyAllocationInclusive(OutMaterialDetailPO node) {
|
||||
if (node == null) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
BigDecimal s = node.getAlreadyAllocationQuantity() != null ? node.getAlreadyAllocationQuantity() : BigDecimal.ZERO;
|
||||
List<OutMaterialDetailPO> ch = node.getChildren();
|
||||
if (CollectionUtils.isEmpty(ch)) {
|
||||
return s;
|
||||
}
|
||||
for (OutMaterialDetailPO c : ch) {
|
||||
s = s.add(sumAlreadyAllocationInclusive(c));
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 手动取消分配(点击确认后直接取消分配)
|
||||
* @author ZhouGY
|
||||
@@ -1057,16 +1083,15 @@ public class StockOutOrderApplicationService {
|
||||
outMaterialDetailDO.setAllowModify(2);
|
||||
//未分配过货 统计到当前分配单作业分配数
|
||||
}
|
||||
totalAllocationQuantity = outMaterialDetailDO.getAllocationQuantity();
|
||||
// 主行「已分配数量」仅记主行本行分配量;子行各自带自己的已分配,不累加到主行(避免双库位时主项显示成主+子)
|
||||
BigDecimal parentAllocationQuantity = outMaterialDetailDO.getAllocationQuantity();
|
||||
//判断是否存在子项
|
||||
List<OutMaterialDetailDO> returnOutMaterialDetailDOChildList = new ArrayList<>();
|
||||
List<OutMaterialDetailDO> outMaterialDetailDOChildList = outMaterialDetailDO.getChildren();
|
||||
if (!CollectionUtils.isEmpty(outMaterialDetailDOChildList)){
|
||||
BigDecimal totalNowAllocationQuantity = BigDecimal.ZERO;//当前作业分配数量
|
||||
for (OutMaterialDetailDO outMaterialDetailDOChild : outMaterialDetailDOChildList){
|
||||
OutMaterialDetailPO outMaterialDetailPOChildDb = outMaterialDetailDbMap.get(outMaterialDetailDOChild.getMaterialDetailId());
|
||||
if (outMaterialDetailPOChildDb != null){
|
||||
totalAllocationQuantity = totalAllocationQuantity.add(outMaterialDetailDOChild.getAllocationQuantity());
|
||||
returnOutMaterialDetailDOChildList.add(outMaterialDetailDOChild);
|
||||
continue;
|
||||
}
|
||||
@@ -1088,11 +1113,9 @@ public class StockOutOrderApplicationService {
|
||||
returnOutMaterialDetailDOChild.setLevel(2);
|
||||
returnOutMaterialDetailDOChild.setParentUniqueId(outMaterialDetailPO.getUniqueId());
|
||||
returnOutMaterialDetailDOChildList.add(returnOutMaterialDetailDOChild);
|
||||
totalAllocationQuantity = totalAllocationQuantity.add(returnOutMaterialDetailDOChild.getAllocationQuantity());
|
||||
}
|
||||
}
|
||||
//主单当分配作业数量和
|
||||
outMaterialDetailDO.setAlreadyAllocationQuantity(totalAllocationQuantity);
|
||||
outMaterialDetailDO.setAlreadyAllocationQuantity(parentAllocationQuantity);
|
||||
OutMaterialDetailDO returnOutMaterialDetailDO = new OutMaterialDetailDO();
|
||||
BeanUtils.copyProperties(outMaterialDetailPO, returnOutMaterialDetailDO);
|
||||
BeanUtils.copyProperties(outMaterialDetailDO, returnOutMaterialDetailDO, IgnoreNullUtil.getNullPropertyNames(outMaterialDetailDO));
|
||||
@@ -1122,6 +1145,21 @@ public class StockOutOrderApplicationService {
|
||||
stockOutOrderDO.setWarehouseName(warehouseFeignPO.getWarehouseName());
|
||||
}
|
||||
|
||||
/**
|
||||
* 出库单按名称/ID解析货主:解析出的用户是否属于当前登录用户同一组织(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);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 封装货主信息
|
||||
* @author ZhouGY
|
||||
@@ -1130,12 +1168,23 @@ public class StockOutOrderApplicationService {
|
||||
*/
|
||||
private void shipperParam(StockOutOrderDO stockOutOrderDO){
|
||||
String customerName = stockOutOrderDO.getCustomerName();
|
||||
if (customerName == null || !customerName.matches("\\d+")) {
|
||||
if (StringUtils.isEmpty(customerName)) {
|
||||
return;
|
||||
}
|
||||
Long loginOrganizationId = null;
|
||||
LoginUser loginUser = SecurityUtils.getLoginUser();
|
||||
if (loginUser != null && loginUser.getUserPo() != null) {
|
||||
loginOrganizationId = loginUser.getUserPo().getOrganizationId();
|
||||
}
|
||||
if (!customerName.matches("\\d+")) {
|
||||
AjaxResult ajaxResult = userServiceFeign.getInfoByName(customerName);
|
||||
if(!"200".equals(String.valueOf(ajaxResult.get("code")))){
|
||||
throw new ServiceException("获取客户信息失败");
|
||||
}
|
||||
UserPo userPo = JSON.parseObject(JSONObject.toJSONString(ajaxResult.get("data")), UserPo.class);
|
||||
if (!shipperMatchesImporterOrganization(userPo, loginOrganizationId)) {
|
||||
throw new ServiceException("当前登录用户组织下不存在该货主信息或客户名称与组织不匹配");
|
||||
}
|
||||
stockOutOrderDO.setShipperId(userPo.getUserId());
|
||||
stockOutOrderDO.setShipperCode(userPo.getUserMemberCode());
|
||||
stockOutOrderDO.setShipperName(userPo.getUserName());
|
||||
@@ -1145,6 +1194,9 @@ public class StockOutOrderApplicationService {
|
||||
throw new ServiceException("获取货主信息失败");
|
||||
}
|
||||
UserPo userPo = JSON.parseObject(JSONObject.toJSONString(ajaxResult.get("data")), UserPo.class);
|
||||
if (!shipperMatchesImporterOrganization(userPo, loginOrganizationId)) {
|
||||
throw new ServiceException("当前登录用户组织下不存在该货主信息或客户名称与组织不匹配");
|
||||
}
|
||||
stockOutOrderDO.setShipperId(userPo.getUserId());
|
||||
stockOutOrderDO.setShipperCode(userPo.getUserMemberCode());
|
||||
stockOutOrderDO.setShipperName(userPo.getUserName());
|
||||
@@ -1159,12 +1211,23 @@ public class StockOutOrderApplicationService {
|
||||
*/
|
||||
private void customerParam(StockOutOrderDO stockOutOrderDO){
|
||||
String customerName = stockOutOrderDO.getCustomerName();
|
||||
if (customerName == null || !customerName.matches("\\d+")) {
|
||||
if (StringUtils.isEmpty(customerName)) {
|
||||
return;
|
||||
}
|
||||
Long loginOrganizationId = null;
|
||||
LoginUser loginUser = SecurityUtils.getLoginUser();
|
||||
if (loginUser != null && loginUser.getUserPo() != null) {
|
||||
loginOrganizationId = loginUser.getUserPo().getOrganizationId();
|
||||
}
|
||||
if (!customerName.matches("\\d+")) {
|
||||
AjaxResult ajaxResult = userServiceFeign.getInfoByName(customerName);
|
||||
if(!"200".equals(String.valueOf(ajaxResult.get("code")))){
|
||||
throw new ServiceException("获取客户信息失败");
|
||||
}
|
||||
UserPo userPo = JSON.parseObject(JSONObject.toJSONString(ajaxResult.get("data")), UserPo.class);
|
||||
if (!shipperMatchesImporterOrganization(userPo, loginOrganizationId)) {
|
||||
throw new ServiceException("当前登录用户组织下不存在该客户信息或客户名称与组织不匹配");
|
||||
}
|
||||
stockOutOrderDO.setCustomerId(userPo.getUserId());
|
||||
stockOutOrderDO.setCustomerCode(userPo.getUserMemberCode());
|
||||
stockOutOrderDO.setCustomerName(userPo.getUserName());
|
||||
@@ -1174,6 +1237,9 @@ public class StockOutOrderApplicationService {
|
||||
throw new ServiceException("获取客户信息失败");
|
||||
}
|
||||
UserPo userPo = JSON.parseObject(JSONObject.toJSONString(ajaxResult.get("data")), UserPo.class);
|
||||
if (!shipperMatchesImporterOrganization(userPo, loginOrganizationId)) {
|
||||
throw new ServiceException("当前登录用户组织下不存在该客户信息或客户名称与组织不匹配");
|
||||
}
|
||||
stockOutOrderDO.setCustomerId(userPo.getUserId());
|
||||
stockOutOrderDO.setCustomerCode(userPo.getUserMemberCode());
|
||||
stockOutOrderDO.setCustomerName(userPo.getUserName());
|
||||
@@ -1291,7 +1357,11 @@ public class StockOutOrderApplicationService {
|
||||
outMaterialDetailPOList.forEach(outMaterialDetailPO -> {
|
||||
BigDecimal quantity = outMaterialDetailPO.getQuantity(); // 计划数量
|
||||
BigDecimal alreadyAllocationQuantity = outMaterialDetailPO.getAlreadyAllocationQuantity(); // 已分配数量
|
||||
|
||||
List<OutMaterialDetailPO> ch = outMaterialDetailPO.getChildren();
|
||||
if (!CollectionUtils.isEmpty(ch)) {
|
||||
alreadyAllocationQuantity = sumAlreadyAllocationInclusive(outMaterialDetailPO);
|
||||
}
|
||||
|
||||
// 判断按钮显示类型
|
||||
// 已分配数量 = 0:显示"库存分配"按钮(类型1)
|
||||
// 已分配数量 = 计划数量:显示"取消分配"按钮(类型2)
|
||||
@@ -1307,9 +1377,8 @@ public class StockOutOrderApplicationService {
|
||||
}
|
||||
|
||||
// 递归处理子级
|
||||
List<OutMaterialDetailPO> children = outMaterialDetailPO.getChildren();
|
||||
if (!CollectionUtils.isEmpty(children)) {
|
||||
setAllocationButtonTypeRecursively(children);
|
||||
if (!CollectionUtils.isEmpty(ch)) {
|
||||
setAllocationButtonTypeRecursively(ch);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+530
-26
@@ -39,6 +39,7 @@ import com.mhd.wms.domain.receiptMaterialDetail.repository.todo.ReceiptMaterialD
|
||||
import com.mhd.wms.domain.receiptMaterialDetail.service.ReceiptMaterialDetailDomainService;
|
||||
import com.mhd.wms.domain.receiptOrderAccount.entity.ReceiptOrderAccount;
|
||||
import com.mhd.wms.domain.receiptOrderAccount.repository.facade.IReceiptOrderAccountService;
|
||||
import com.mhd.wms.domain.stockInOrder.repository.facade.IStockInOrderService;
|
||||
import com.mhd.wms.domain.stockInOrder.repository.todo.StockInOrderDO;
|
||||
import com.mhd.wms.domain.stockReceiptOrder.repository.po.StockReceiptOrderPO;
|
||||
import com.mhd.wms.domain.stockReceiptOrder.repository.todo.NoReceiptOrderDO;
|
||||
@@ -53,12 +54,14 @@ import org.springframework.util.CollectionUtils;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.text.ParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
@@ -98,6 +101,8 @@ public class StockReceiptOrderApplicationService {
|
||||
private IdGenerator idGenerator;
|
||||
@Autowired
|
||||
private IReceiptOrderAccountService receiptOrderAccountService;
|
||||
@Autowired
|
||||
private IStockInOrderService stockInOrderService;
|
||||
|
||||
|
||||
/**
|
||||
@@ -294,8 +299,9 @@ public class StockReceiptOrderApplicationService {
|
||||
stockReceiptOrderPO.setTotalGrossWeight(totalGrossWeight);
|
||||
stockReceiptOrderPO.setTotalVolume(totalVolume);
|
||||
stockReceiptOrderPO.setTotalArea(totalArea);
|
||||
// 扁平化明细:将子项收货数据合并到主项
|
||||
flattenMaterialDetailList(receiptMaterialDetailPOList);
|
||||
// 扁平化明细:将子项收货数据合并到主项(按汇总已收推导状态,见方法内注释)
|
||||
flattenMaterialDetailList(receiptMaterialDetailPOList,
|
||||
stockReceiptOrderPO.getStatus() != null && stockReceiptOrderPO.getStatus() == 3);
|
||||
// PC 端子项计划数量不展示:递归清空所有子项的 quantity
|
||||
clearChildQuantityRecursively(receiptMaterialDetailPOList);
|
||||
// 计算待收货数量 = 计划数量 - 已收货数量
|
||||
@@ -1218,10 +1224,15 @@ public class StockReceiptOrderApplicationService {
|
||||
fillPendingReceiptQuantityRecursively(materialDetailList);
|
||||
syncReceiptQuantityCumulativeDisplayRecursively(materialDetailList);
|
||||
}
|
||||
// pending* = plan* − already_receipt_*(主行 already* 已为全部已收汇总)
|
||||
fillPlanAndPendingMetricsRecursively(materialDetailList);
|
||||
// PDA 绑定 total* 展示「待收」= plan − 已收;已收货行不覆盖
|
||||
// 未完成行:total* 与 pending* 同值,即「计划总的 − 全部已收」
|
||||
overwriteTotalWithPendingForPdaDisplayRecursively(materialDetailList);
|
||||
clearChildQuantityRecursively(materialDetailList);
|
||||
// 仅在未按 tab 筛明细时纠正整单头状态;筛成「待收/已收」子集时不能据子集推断整单是否已收完
|
||||
if (receiptStatus == null) {
|
||||
refreshPdaReceiptOrderHeaderStatusFromDerivedPlanLines(stockReceiptOrderPO, materialDetailList);
|
||||
}
|
||||
}
|
||||
return stockReceiptOrderPO;
|
||||
}
|
||||
@@ -1234,7 +1245,44 @@ public class StockReceiptOrderApplicationService {
|
||||
}
|
||||
|
||||
/**
|
||||
* PDA 界面「总净重/总毛重/体积/面积」绑定 total*:有计划时展示待收(pending*);无计划联表时保留原 total*(累计实绩)。
|
||||
* PDA 详情:header.status 直接来自库表;若库表仍为部分收货(2),但 flatten 后各计划主行已是收尾明细状态且整单收货数已不少于计划,则将返回头状态纠正为已收货(3),避免列表/详情长期显示「部分收货」。
|
||||
*/
|
||||
private void refreshPdaReceiptOrderHeaderStatusFromDerivedPlanLines(StockReceiptOrderPO order,
|
||||
List<ReceiptMaterialDetailPO> planRoots) {
|
||||
if (order == null || order.getStatus() == null || order.getStatus() != 2) {
|
||||
return;
|
||||
}
|
||||
if (CollectionUtils.isEmpty(planRoots)) {
|
||||
return;
|
||||
}
|
||||
for (ReceiptMaterialDetailPO p : planRoots) {
|
||||
if (p == null) {
|
||||
continue;
|
||||
}
|
||||
if (p.getLevel() != null && p.getLevel() != 1) {
|
||||
continue;
|
||||
}
|
||||
if (!isPdaTerminalReceiptDetailStatus(p.getReceiptStatus())) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
BigDecimal rq = order.getReceiptQuantity() != null ? order.getReceiptQuantity() : BigDecimal.ZERO;
|
||||
BigDecimal pq = order.getQuantity() != null ? order.getQuantity() : BigDecimal.ZERO;
|
||||
if (rq.compareTo(pq) >= 0) {
|
||||
order.setStatus(3);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* PDA:指定计划行(卡片)下分批收货子行列表(level=2),域服务已挂序列号。
|
||||
*/
|
||||
public List<ReceiptMaterialDetailPO> listLevel2ChildrenByParentForApp(Long receiptOrderId, Long parentMaterialDetailId) {
|
||||
return stockReceiptOrderDomainService.listLevel2ChildrenByParentForApp(receiptOrderId, parentMaterialDetailId);
|
||||
}
|
||||
|
||||
/**
|
||||
* PDA 详情:将 total* 覆盖为待收(与 pending* 同值),便于前端仍绑 total* 时展示「计划 − 主项+子项全部已收」。
|
||||
* 回传收货时由 {@link #pickThisReceiptMetricIncrementPda} 识别并按件数比例分摊增量。
|
||||
*/
|
||||
private void overwriteTotalWithPendingForPdaDisplayRecursively(List<ReceiptMaterialDetailPO> list) {
|
||||
if (CollectionUtils.isEmpty(list)) {
|
||||
@@ -1415,8 +1463,16 @@ public class StockReceiptOrderApplicationService {
|
||||
*/
|
||||
public Boolean receivingGoodsByApp(StockReceiptOrderDO stockReceiptOrderDO){
|
||||
List<ReceiptMaterialDetailDO> list = stockReceiptOrderDO.getMaterialDetailList();
|
||||
// 超计划提示:实际收货数量 > 待收数量(计划-已收) 时,先提示确认
|
||||
checkOverPlanReceiptForApp(stockReceiptOrderDO);
|
||||
StockReceiptOrderPO dbOrder = stockReceiptOrderDomainService.getInfo(stockReceiptOrderDO.getReceiptOrderId());
|
||||
if (dbOrder == null) {
|
||||
throw new ServiceException("收货单不存在");
|
||||
}
|
||||
ReceiptMaterialDetailDO queryAll = new ReceiptMaterialDetailDO();
|
||||
queryAll.setReceiptOrderNumber(dbOrder.getReceiptOrderNumber());
|
||||
List<ReceiptMaterialDetailPO> dbListAll = receiptMaterialDetailDomainService.queryList(queryAll);
|
||||
preserveParentReceiptLineHierarchyFromDb(stockReceiptOrderDO, dbListAll);
|
||||
// 超计划:按「计划父行 + 其下 level=2 子行」累计已收 算待收
|
||||
checkOverPlanReceiptForApp(stockReceiptOrderDO, dbListAll);
|
||||
// 记录 PDA 传入时第一项是否已有 children
|
||||
boolean firstItemHadChildrenBefore = !CollectionUtils.isEmpty(list)
|
||||
&& !CollectionUtils.isEmpty(list.get(0).getChildren());
|
||||
@@ -1437,6 +1493,30 @@ public class StockReceiptOrderApplicationService {
|
||||
&& !CollectionUtils.isEmpty(listAfter.get(0).getChildren());
|
||||
stockReceiptOrderDO.setPdaSkipInjectBatchChildLine(skipInjectAfterAssign);
|
||||
stockReceiptOrderDO.setFromPda(true);
|
||||
// assign 后若仍有真实子行,不再 inject(避免与已有子项结构冲突)
|
||||
boolean skipInjectAfterAssign = firstItemHadChildrenBefore
|
||||
&& !CollectionUtils.isEmpty(stockReceiptOrderDO.getMaterialDetailList())
|
||||
&& !CollectionUtils.isEmpty(stockReceiptOrderDO.getMaterialDetailList().get(0).getChildren());
|
||||
Map<Long, ReceiptMaterialDetailPO> dbByIdForInject = dbListAll.stream()
|
||||
.filter(x -> x.getMaterialDetailId() != null)
|
||||
.collect(Collectors.toMap(ReceiptMaterialDetailPO::getMaterialDetailId, Function.identity(), (a, b) -> a));
|
||||
Map<Long, ReceiptMaterialDetailPO> dbByUidForInject = dbListAll.stream()
|
||||
.filter(x -> x.getUniqueId() != null)
|
||||
.collect(Collectors.toMap(ReceiptMaterialDetailPO::getUniqueId, Function.identity(), (a, b) -> a));
|
||||
int injectIdx = 0;
|
||||
for (ReceiptMaterialDetailDO line : stockReceiptOrderDO.getMaterialDetailList()) {
|
||||
ReceiptMaterialDetailPO dbLine = null;
|
||||
if (line.getMaterialDetailId() != null) {
|
||||
dbLine = dbByIdForInject.get(line.getMaterialDetailId());
|
||||
}
|
||||
if (dbLine == null && line.getUniqueId() != null) {
|
||||
dbLine = dbByUidForInject.get(line.getUniqueId());
|
||||
}
|
||||
if (dbLine != null && !(skipInjectAfterAssign && injectIdx == 0)) {
|
||||
injectPdaFlatReceiptAsSyntheticChild(line, dbLine, dbListAll);
|
||||
}
|
||||
injectIdx++;
|
||||
}
|
||||
StockReceiptOrderDO assembleStockReceiptOrderDO = assembleParamByReceipt(stockReceiptOrderDO, false);
|
||||
if (CollectionUtils.isEmpty(assembleStockReceiptOrderDO.getMaterialDetailList())) {
|
||||
throw new ServiceException("无有效收货数据,请确认已填写收货数量(收货数量不能全部为0)");
|
||||
@@ -1445,17 +1525,13 @@ public class StockReceiptOrderApplicationService {
|
||||
return stockReceiptOrderDomainService.receivingGoods(assembleStockReceiptOrderDO);
|
||||
}
|
||||
|
||||
private void checkOverPlanReceiptForApp(StockReceiptOrderDO stockReceiptOrderDO) {
|
||||
private void checkOverPlanReceiptForApp(StockReceiptOrderDO stockReceiptOrderDO, List<ReceiptMaterialDetailPO> dbList) {
|
||||
if (stockReceiptOrderDO == null || CollectionUtils.isEmpty(stockReceiptOrderDO.getMaterialDetailList())) {
|
||||
return;
|
||||
}
|
||||
StockReceiptOrderPO dbOrder = stockReceiptOrderDomainService.getInfo(stockReceiptOrderDO.getReceiptOrderId());
|
||||
if (dbOrder == null) {
|
||||
if (CollectionUtils.isEmpty(dbList)) {
|
||||
return;
|
||||
}
|
||||
ReceiptMaterialDetailDO queryDO = new ReceiptMaterialDetailDO();
|
||||
queryDO.setReceiptOrderNumber(dbOrder.getReceiptOrderNumber());
|
||||
List<ReceiptMaterialDetailPO> dbList = receiptMaterialDetailDomainService.queryList(queryDO);
|
||||
Map<Long, ReceiptMaterialDetailPO> dbById = dbList.stream()
|
||||
.filter(x -> x.getMaterialDetailId() != null)
|
||||
.collect(Collectors.toMap(ReceiptMaterialDetailPO::getMaterialDetailId, Function.identity(), (a, b) -> a));
|
||||
@@ -1470,6 +1546,9 @@ public class StockReceiptOrderApplicationService {
|
||||
/**
|
||||
* 方案二子行 level=2 在库中 quantity 常为 0,不能再用单行 plan-already 校验,须按计划父行汇总已收。
|
||||
*/
|
||||
/**
|
||||
* 分批收货:计划数量在 level=1 父行;待收 = 计划父行 quantity −(父行+其下 level=2 子行 already_receipt 汇总)
|
||||
*/
|
||||
private void validateOverPlanNode(ReceiptMaterialDetailDO item,
|
||||
Map<Long, ReceiptMaterialDetailPO> dbById,
|
||||
Map<Long, ReceiptMaterialDetailPO> dbByUniqueId,
|
||||
@@ -1578,6 +1657,316 @@ public class StockReceiptOrderApplicationService {
|
||||
return sum.compareTo(BigDecimal.ZERO) > 0;
|
||||
}
|
||||
|
||||
/** 雪花/长整型 id 相较,避免部分环境下引用类型不一致 */
|
||||
private static boolean sameLongId(Long a, Long b) {
|
||||
if (a == null || b == null) {
|
||||
return false;
|
||||
}
|
||||
return a.longValue() == b.longValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* 是否为本计划父行下的 level=2 实子行(可参与已收汇总)。
|
||||
* 排除 parent_unique_id 空/0;排除与主行同 unique_id 的镜像行(同源只计主行对象一次)。
|
||||
*/
|
||||
private static boolean isLevel2ChildRowUnderPlanParent(ReceiptMaterialDetailPO planParent, ReceiptMaterialDetailPO x) {
|
||||
if (planParent == 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 = planParent.getUniqueId();
|
||||
Long inUid = planParent.getInUniqueId();
|
||||
boolean linked = (uid != null && sameLongId(uid, puid)) || (inUid != null && sameLongId(inUid, puid));
|
||||
if (!linked) {
|
||||
return false;
|
||||
}
|
||||
if (planParent.getUniqueId() != null && sameLongId(planParent.getUniqueId(), x.getUniqueId())) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/** 计划父行:level=1 自身;level=2 则按 parent_unique_id 找到主计划行 */
|
||||
private static ReceiptMaterialDetailPO resolveReceiptPlanParentRow(ReceiptMaterialDetailPO db,
|
||||
List<ReceiptMaterialDetailPO> dbList) {
|
||||
if (db == null || CollectionUtils.isEmpty(dbList)) {
|
||||
return db;
|
||||
}
|
||||
if (db.getLevel() == null || db.getLevel() == 1) {
|
||||
return db;
|
||||
}
|
||||
if (db.getLevel() == 2 && db.getParentUniqueId() != null) {
|
||||
Long puid = db.getParentUniqueId();
|
||||
for (ReceiptMaterialDetailPO x : dbList) {
|
||||
if (x == null) {
|
||||
continue;
|
||||
}
|
||||
if (puid.equals(x.getUniqueId()) || puid.equals(x.getInUniqueId())) {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
}
|
||||
return db;
|
||||
}
|
||||
|
||||
/**
|
||||
* 父行自身 + 其下 level=2(parent 指向父)的已收数量之和。
|
||||
* <p>主行本行必须取传入的 {@code planParent} 上的累计字段,再在列表中只加子行;勿依赖在 {@code dbList} 中再次按 material_detail_id
|
||||
* 匹配主行,否则 JDBC 类型/映射不一致时会出现「只加子行、主行 100 丢失」。</p>
|
||||
*/
|
||||
private static BigDecimal sumAlreadyReceiptUnderPlanParent(ReceiptMaterialDetailPO planParent,
|
||||
List<ReceiptMaterialDetailPO> dbList) {
|
||||
if (planParent == null || CollectionUtils.isEmpty(dbList)) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
BigDecimal sum = planParent.getAlreadyReceiptQuantity() != null
|
||||
? planParent.getAlreadyReceiptQuantity() : BigDecimal.ZERO;
|
||||
for (ReceiptMaterialDetailPO x : dbList) {
|
||||
if (x == null || !isLevel2ChildRowUnderPlanParent(planParent, x)) {
|
||||
continue;
|
||||
}
|
||||
BigDecimal ar = x.getAlreadyReceiptQuantity() != null ? x.getAlreadyReceiptQuantity() : BigDecimal.ZERO;
|
||||
sum = sum.add(ar);
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
/** 与 {@link #sumAlreadyReceiptUnderPlanParent} 同范围,汇总任意「已收」指标(毛/净重、体积、面积等) */
|
||||
private static BigDecimal sumAlreadyMetricUnderPlanParent(ReceiptMaterialDetailPO planParent,
|
||||
List<ReceiptMaterialDetailPO> dbList,
|
||||
Function<ReceiptMaterialDetailPO, BigDecimal> alreadyGetter) {
|
||||
if (planParent == null || CollectionUtils.isEmpty(dbList) || alreadyGetter == null) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
BigDecimal base = alreadyGetter.apply(planParent);
|
||||
BigDecimal sum = base != null ? base : BigDecimal.ZERO;
|
||||
for (ReceiptMaterialDetailPO x : dbList) {
|
||||
if (x == null || !isLevel2ChildRowUnderPlanParent(planParent, x)) {
|
||||
continue;
|
||||
}
|
||||
BigDecimal v = alreadyGetter.apply(x);
|
||||
sum = sum.add(v != null ? v : BigDecimal.ZERO);
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
/** 首笔不拆子行;已有子行或主行+子行已有累计实收时再拆 */
|
||||
private static boolean shouldPdaSplitIntoChildRow(ReceiptMaterialDetailPO dbLine,
|
||||
List<ReceiptMaterialDetailPO> allDbLines) {
|
||||
if (dbLine == null || CollectionUtils.isEmpty(allDbLines)) {
|
||||
return true;
|
||||
}
|
||||
ReceiptMaterialDetailPO plan = resolveReceiptPlanParentRow(dbLine, allDbLines);
|
||||
if (plan == null) {
|
||||
return true;
|
||||
}
|
||||
Long uid = plan.getUniqueId();
|
||||
Long inUid = plan.getInUniqueId();
|
||||
boolean hasL2 = allDbLines.stream().anyMatch(x -> x != null && x.getLevel() != null && x.getLevel() == 2
|
||||
&& x.getParentUniqueId() != null
|
||||
&& ((uid != null && uid.equals(x.getParentUniqueId()))
|
||||
|| (inUid != null && inUid.equals(x.getParentUniqueId()))));
|
||||
if (hasL2) {
|
||||
return true;
|
||||
}
|
||||
BigDecimal sum = sumAlreadyReceiptUnderPlanParent(plan, allDbLines);
|
||||
return sum.compareTo(BigDecimal.ZERO) > 0;
|
||||
}
|
||||
|
||||
private static boolean isCorruptedStandaloneLineAsLevel2(ReceiptMaterialDetailPO dbLine) {
|
||||
if (dbLine == null || dbLine.getLevel() == null || dbLine.getLevel() != 2) {
|
||||
return false;
|
||||
}
|
||||
return dbLine.getParentUniqueId() == null || Objects.equals(dbLine.getParentUniqueId(), 0L);
|
||||
}
|
||||
|
||||
/** 合成子行挂在计划父行的 uniqueId;误标为 level=2 且无父时,按同物料 level=1 行定位 */
|
||||
private static Long resolveParentUniqueIdForPdaInjectChild(ReceiptMaterialDetailPO dbLine,
|
||||
List<ReceiptMaterialDetailPO> allDbLines) {
|
||||
if (dbLine == null) {
|
||||
return null;
|
||||
}
|
||||
if (isCorruptedStandaloneLineAsLevel2(dbLine) && dbLine.getMaterialDetailId() != null
|
||||
&& !CollectionUtils.isEmpty(allDbLines)) {
|
||||
for (ReceiptMaterialDetailPO x : allDbLines) {
|
||||
if (x != null && Objects.equals(x.getMaterialDetailId(), dbLine.getMaterialDetailId())
|
||||
&& x.getLevel() != null && x.getLevel() == 1) {
|
||||
return x.getUniqueId();
|
||||
}
|
||||
}
|
||||
}
|
||||
ReceiptMaterialDetailPO plan = resolveReceiptPlanParentRow(dbLine, allDbLines);
|
||||
return plan != null ? plan.getUniqueId() : dbLine.getUniqueId();
|
||||
}
|
||||
|
||||
/** 请求行与库主计划行 level 不一致时纠正,避免误当子行 */
|
||||
private void preserveParentReceiptLineHierarchyFromDb(StockReceiptOrderDO order, List<ReceiptMaterialDetailPO> dbList) {
|
||||
if (order == null || CollectionUtils.isEmpty(order.getMaterialDetailList()) || CollectionUtils.isEmpty(dbList)) {
|
||||
return;
|
||||
}
|
||||
Map<Long, ReceiptMaterialDetailPO> byId = dbList.stream()
|
||||
.filter(x -> x.getMaterialDetailId() != null)
|
||||
.collect(Collectors.toMap(ReceiptMaterialDetailPO::getMaterialDetailId, Function.identity(), (a, b) -> a));
|
||||
Map<Long, ReceiptMaterialDetailPO> byUid = dbList.stream()
|
||||
.filter(x -> x.getUniqueId() != null)
|
||||
.collect(Collectors.toMap(ReceiptMaterialDetailPO::getUniqueId, Function.identity(), (a, b) -> a));
|
||||
for (ReceiptMaterialDetailDO line : order.getMaterialDetailList()) {
|
||||
ReceiptMaterialDetailPO db = null;
|
||||
if (line.getMaterialDetailId() != null) {
|
||||
db = byId.get(line.getMaterialDetailId());
|
||||
}
|
||||
if (db == null && line.getUniqueId() != null) {
|
||||
db = byUid.get(line.getUniqueId());
|
||||
}
|
||||
if (db != null && db.getLevel() != null && db.getLevel() == 1
|
||||
&& line.getLevel() != null && line.getLevel() == 2) {
|
||||
line.setLevel(1);
|
||||
line.setParentUniqueId(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void stripPdaUiParentCopyChildren(ReceiptMaterialDetailDO line, ReceiptMaterialDetailPO dbLine) {
|
||||
if (line == null || CollectionUtils.isEmpty(line.getChildren())) {
|
||||
return;
|
||||
}
|
||||
Long parentUid = line.getUniqueId() != null ? line.getUniqueId() : (dbLine != null ? dbLine.getUniqueId() : null);
|
||||
List<ReceiptMaterialDetailDO> realOnly = new ArrayList<>();
|
||||
for (ReceiptMaterialDetailDO c : line.getChildren()) {
|
||||
if (c == null) {
|
||||
continue;
|
||||
}
|
||||
if (parentUid != null && parentUid.equals(c.getUniqueId())) {
|
||||
continue;
|
||||
}
|
||||
realOnly.add(c);
|
||||
}
|
||||
line.setChildren(realOnly);
|
||||
}
|
||||
|
||||
/** getInfoByApp 挂在 children 里的已落库子行,再次收货时需去掉,否则 inject 误判已有子项 */
|
||||
private static void stripPdaExistingDisplayedChildrenForResplit(ReceiptMaterialDetailDO line, ReceiptMaterialDetailPO dbLine,
|
||||
List<ReceiptMaterialDetailPO> allDbLines) {
|
||||
if (line == null || CollectionUtils.isEmpty(line.getChildren()) || dbLine == null || CollectionUtils.isEmpty(allDbLines)) {
|
||||
return;
|
||||
}
|
||||
Long puid = dbLine.getUniqueId();
|
||||
Long pInUid = dbLine.getInUniqueId();
|
||||
List<ReceiptMaterialDetailDO> keep = new ArrayList<>();
|
||||
for (ReceiptMaterialDetailDO c : line.getChildren()) {
|
||||
if (c == null) {
|
||||
continue;
|
||||
}
|
||||
Long mid = c.getMaterialDetailId();
|
||||
Long cuid = c.getUniqueId();
|
||||
boolean isExistingDbChild = false;
|
||||
for (ReceiptMaterialDetailPO x : allDbLines) {
|
||||
if (x == null || x.getLevel() == null || x.getLevel() != 2 || x.getParentUniqueId() == null) {
|
||||
continue;
|
||||
}
|
||||
boolean parentOk = (puid != null && puid.equals(x.getParentUniqueId()))
|
||||
|| (pInUid != null && pInUid.equals(x.getParentUniqueId()));
|
||||
if (!parentOk) {
|
||||
continue;
|
||||
}
|
||||
if (mid != null && mid.equals(x.getMaterialDetailId())) {
|
||||
isExistingDbChild = true;
|
||||
break;
|
||||
}
|
||||
if (cuid != null && cuid.equals(x.getUniqueId())) {
|
||||
isExistingDbChild = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!isExistingDbChild) {
|
||||
keep.add(c);
|
||||
}
|
||||
}
|
||||
line.setChildren(keep);
|
||||
}
|
||||
|
||||
private static boolean hasPdaInjectMetricIncrement(ReceiptMaterialDetailDO line, ReceiptMaterialDetailPO dbLine) {
|
||||
if (line == null || dbLine == null) {
|
||||
return false;
|
||||
}
|
||||
BigDecimal dbNet = dbLine.getAlreadyReceiptNetWeight() != null ? dbLine.getAlreadyReceiptNetWeight() : BigDecimal.ZERO;
|
||||
BigDecimal dbGross = dbLine.getAlreadyReceiptGrossWeight() != null ? dbLine.getAlreadyReceiptGrossWeight() : BigDecimal.ZERO;
|
||||
BigDecimal dbVol = dbLine.getAlreadyReceiptVolume() != null ? dbLine.getAlreadyReceiptVolume() : BigDecimal.ZERO;
|
||||
BigDecimal dbArea = dbLine.getAlreadyReceiptArea() != null ? dbLine.getAlreadyReceiptArea() : BigDecimal.ZERO;
|
||||
return pickThisReceiptMetricIncrement(line.getReceiptNetWeight(), line.getTotalNetWeight(), dbNet).compareTo(BigDecimal.ZERO) > 0
|
||||
|| pickThisReceiptMetricIncrement(line.getReceiptGrossWeight(), line.getTotalGrossWeight(), dbGross).compareTo(BigDecimal.ZERO) > 0
|
||||
|| pickThisReceiptMetricIncrement(line.getReceiptVolume(), line.getTotalVolume(), dbVol).compareTo(BigDecimal.ZERO) > 0
|
||||
|| pickThisReceiptMetricIncrement(line.getReceiptArea(), line.getTotalArea(), dbArea).compareTo(BigDecimal.ZERO) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* PDA 单次仅传主行(无真实子结构需拆时):按业务可拆成一条 level=2 子行。
|
||||
* 首笔仅落主行不拆;第二笔起或已有子行再拆。脏主行(误标 level=2)纠正不受「首笔不拆」限制。
|
||||
*/
|
||||
private void injectPdaFlatReceiptAsSyntheticChild(ReceiptMaterialDetailDO line, ReceiptMaterialDetailPO dbLine,
|
||||
List<ReceiptMaterialDetailPO> allDbLines) {
|
||||
if (line == null || dbLine == null) {
|
||||
return;
|
||||
}
|
||||
stripPdaUiParentCopyChildren(line, dbLine);
|
||||
stripPdaExistingDisplayedChildrenForResplit(line, dbLine, allDbLines);
|
||||
if (dbLine.getLevel() != null && dbLine.getLevel() == 2 && !isCorruptedStandaloneLineAsLevel2(dbLine)) {
|
||||
return;
|
||||
}
|
||||
if (!CollectionUtils.isEmpty(line.getChildren())) {
|
||||
return;
|
||||
}
|
||||
if (!shouldPdaSplitIntoChildRow(dbLine, allDbLines) && !isCorruptedStandaloneLineAsLevel2(dbLine)) {
|
||||
return;
|
||||
}
|
||||
BigDecimal rq = line.getReceiptQuantity();
|
||||
boolean hasQty = rq != null && rq.compareTo(BigDecimal.ZERO) > 0;
|
||||
boolean hasMetricBatch = hasPdaInjectMetricIncrement(line, dbLine);
|
||||
if (!hasQty && !hasMetricBatch) {
|
||||
return;
|
||||
}
|
||||
ReceiptMaterialDetailDO child = new ReceiptMaterialDetailDO();
|
||||
BeanUtils.copyProperties(line, child, "children", "materialDetailId", "uniqueId", "level", "parentUniqueId");
|
||||
child.setUniqueId(idGenerator.snowflakeId(SnowFlakeConstants.wmsId));
|
||||
child.setChildren(null);
|
||||
child.setLevel(2);
|
||||
child.setParentUniqueId(resolveParentUniqueIdForPdaInjectChild(dbLine, allDbLines));
|
||||
if (hasQty) {
|
||||
child.setReceiptQuantity(rq);
|
||||
}
|
||||
child.setReceiptGrossWeight(line.getReceiptGrossWeight());
|
||||
child.setReceiptNetWeight(line.getReceiptNetWeight());
|
||||
child.setReceiptVolume(line.getReceiptVolume());
|
||||
child.setReceiptArea(line.getReceiptArea());
|
||||
child.setTotalGrossWeight(line.getTotalGrossWeight());
|
||||
child.setTotalNetWeight(line.getTotalNetWeight());
|
||||
child.setTotalVolume(line.getTotalVolume());
|
||||
child.setTotalArea(line.getTotalArea());
|
||||
child.setAlreadyReceiptQuantity(null);
|
||||
child.setAlreadyReceiptGrossWeight(null);
|
||||
child.setAlreadyReceiptNetWeight(null);
|
||||
child.setAlreadyReceiptVolume(null);
|
||||
child.setAlreadyReceiptArea(null);
|
||||
line.setChildren(Collections.singletonList(child));
|
||||
line.setReceiptQuantity(BigDecimal.ZERO);
|
||||
line.setReceiptGrossWeight(null);
|
||||
line.setReceiptNetWeight(null);
|
||||
line.setReceiptVolume(null);
|
||||
line.setReceiptArea(null);
|
||||
line.setTotalGrossWeight(null);
|
||||
line.setTotalNetWeight(null);
|
||||
line.setTotalVolume(null);
|
||||
line.setTotalArea(null);
|
||||
line.setLevel(1);
|
||||
line.setParentUniqueId(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 收货时:将 children 中第一条的值赋给主项,并删除第一条。
|
||||
* PDA 收两条时只生成 2 条(主项 + 第二条子项),主项展示第一条子项的数据。
|
||||
@@ -1867,6 +2256,10 @@ public class StockReceiptOrderApplicationService {
|
||||
return stockReceiptOrderDomainService.completeReceipt(receiptOrderId, true);
|
||||
}
|
||||
|
||||
public void updateInOrder(StockReceiptOrderDTO stockReceiptOrderDTO){
|
||||
stockReceiptOrderDomainService.updateInOrder(stockReceiptOrderDTO);
|
||||
}
|
||||
|
||||
public Boolean genStockShelfOrder(Long receiptOrderId){
|
||||
return stockReceiptOrderDomainService.genStockShelfOrder(receiptOrderId);
|
||||
}
|
||||
@@ -2004,6 +2397,65 @@ public class StockReceiptOrderApplicationService {
|
||||
return totalField;
|
||||
}
|
||||
|
||||
private static boolean isApproxEqualReceiptMetric(BigDecimal a, BigDecimal b) {
|
||||
if (a == null && b == null) {
|
||||
return true;
|
||||
}
|
||||
if (a == null || b == null) {
|
||||
return false;
|
||||
}
|
||||
return a.subtract(b).abs().compareTo(new BigDecimal("0.000001")) <= 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* PDA:详情里 total* 为「待收」= 计划 − 组内主项+子项全部已收;提交时若仍等于当前组剩余指标,
|
||||
* 则按本行本次收货件数占「组内待收件数」比例分摊本次毛/净重/体积/面积增量。
|
||||
* 否则按 {@link #pickThisReceiptMetricIncrement}(累计实绩)处理。
|
||||
*/
|
||||
private static BigDecimal pickThisReceiptMetricIncrementPda(
|
||||
BigDecimal receiptField,
|
||||
BigDecimal totalField,
|
||||
BigDecimal dbSingleRowAlready,
|
||||
ReceiptMaterialDetailPO dbLine,
|
||||
List<ReceiptMaterialDetailPO> dbList,
|
||||
Function<ReceiptMaterialDetailPO, BigDecimal> planMetricGetter,
|
||||
Function<ReceiptMaterialDetailPO, BigDecimal> alreadyMetricGetter,
|
||||
BigDecimal thisReceiptQty) {
|
||||
if (receiptField != null) {
|
||||
return receiptField;
|
||||
}
|
||||
if (totalField == null) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
if (dbLine == null || CollectionUtils.isEmpty(dbList) || thisReceiptQty == null
|
||||
|| thisReceiptQty.compareTo(BigDecimal.ZERO) <= 0) {
|
||||
return pickThisReceiptMetricIncrement(receiptField, totalField, dbSingleRowAlready);
|
||||
}
|
||||
ReceiptMaterialDetailPO plan = resolveReceiptPlanParentRow(dbLine, dbList);
|
||||
if (plan == null) {
|
||||
return pickThisReceiptMetricIncrement(receiptField, totalField, dbSingleRowAlready);
|
||||
}
|
||||
BigDecimal planMetric = planMetricGetter.apply(plan);
|
||||
if (planMetric == null) {
|
||||
return pickThisReceiptMetricIncrement(receiptField, totalField, dbSingleRowAlready);
|
||||
}
|
||||
BigDecimal sumAlready = sumAlreadyMetricUnderPlanParent(plan, dbList, alreadyMetricGetter);
|
||||
BigDecimal remainingMetric = planMetric.subtract(sumAlready);
|
||||
if (remainingMetric.compareTo(BigDecimal.ZERO) < 0) {
|
||||
remainingMetric = BigDecimal.ZERO;
|
||||
}
|
||||
BigDecimal planQty = plan.getQuantity() != null ? plan.getQuantity() : BigDecimal.ZERO;
|
||||
BigDecimal sumAlreadyQty = sumAlreadyReceiptUnderPlanParent(plan, dbList);
|
||||
BigDecimal pendingQty = planQty.subtract(sumAlreadyQty);
|
||||
if (pendingQty.compareTo(BigDecimal.ZERO) <= 0) {
|
||||
return pickThisReceiptMetricIncrement(receiptField, totalField, dbSingleRowAlready);
|
||||
}
|
||||
if (isApproxEqualReceiptMetric(totalField, remainingMetric)) {
|
||||
return remainingMetric.multiply(thisReceiptQty).divide(pendingQty, 8, RoundingMode.HALF_UP);
|
||||
}
|
||||
return pickThisReceiptMetricIncrement(receiptField, totalField, dbSingleRowAlready);
|
||||
}
|
||||
|
||||
/**
|
||||
* PC 收货确认:页面提交为「当前全量实绩」,直接取 receipt* / total* 落库,不与历史累计做差或相加。
|
||||
*/
|
||||
@@ -2219,6 +2671,7 @@ public class StockReceiptOrderApplicationService {
|
||||
throw new ServiceException("收货单已完成收货");
|
||||
}
|
||||
StockReceiptOrderDO returnStockReceiptOrderDO = new StockReceiptOrderDO();
|
||||
returnStockReceiptOrderDO.setBillingJson(stockReceiptOrderDO.getBillingJson());
|
||||
returnStockReceiptOrderDO.setReceiptOrderAccountList(stockReceiptOrderDO.getReceiptOrderAccountList());
|
||||
returnStockReceiptOrderDO.setUpdateTime(stockReceiptOrderDO.getUpdateTime());
|
||||
returnStockReceiptOrderDO.setReceiptOrderId(stockReceiptOrderPO.getReceiptOrderId());
|
||||
@@ -2282,14 +2735,25 @@ public class StockReceiptOrderApplicationService {
|
||||
? receiptMaterialDetailPO.getAlreadyReceiptNetWeight() : BigDecimal.ZERO;
|
||||
BigDecimal dbParentGrossForGate = receiptMaterialDetailPO.getAlreadyReceiptGrossWeight() != null
|
||||
? receiptMaterialDetailPO.getAlreadyReceiptGrossWeight() : BigDecimal.ZERO;
|
||||
boolean hasReceiptByMetrics = pickThisReceiptMetricIncrement(
|
||||
BigDecimal gateParentQty = receiptQuantity;
|
||||
boolean hasReceiptByMetrics = pickThisReceiptMetricIncrementPda(
|
||||
receiptMaterialDetailDO.getReceiptNetWeight(),
|
||||
receiptMaterialDetailDO.getTotalNetWeight(),
|
||||
dbParentNetForGate).compareTo(BigDecimal.ZERO) > 0
|
||||
|| pickThisReceiptMetricIncrement(
|
||||
dbParentNetForGate,
|
||||
receiptMaterialDetailPO,
|
||||
receiptMaterialDetailPODbList,
|
||||
ReceiptMaterialDetailPO::getPlanNetWeight,
|
||||
ReceiptMaterialDetailPO::getAlreadyReceiptNetWeight,
|
||||
gateParentQty).compareTo(BigDecimal.ZERO) > 0
|
||||
|| pickThisReceiptMetricIncrementPda(
|
||||
receiptMaterialDetailDO.getReceiptGrossWeight(),
|
||||
receiptMaterialDetailDO.getTotalGrossWeight(),
|
||||
dbParentGrossForGate).compareTo(BigDecimal.ZERO) > 0;
|
||||
dbParentGrossForGate,
|
||||
receiptMaterialDetailPO,
|
||||
receiptMaterialDetailPODbList,
|
||||
ReceiptMaterialDetailPO::getPlanGrossWeight,
|
||||
ReceiptMaterialDetailPO::getAlreadyReceiptGrossWeight,
|
||||
gateParentQty).compareTo(BigDecimal.ZERO) > 0;
|
||||
if (!hasReceiptByMetrics && !CollectionUtils.isEmpty(children)) {
|
||||
for (ReceiptMaterialDetailDO c : children) {
|
||||
if (c == null) {
|
||||
@@ -2303,8 +2767,19 @@ public class StockReceiptOrderApplicationService {
|
||||
? cdb.getAlreadyReceiptNetWeight() : BigDecimal.ZERO;
|
||||
BigDecimal cDbGross = cdb != null && cdb.getAlreadyReceiptGrossWeight() != null
|
||||
? cdb.getAlreadyReceiptGrossWeight() : BigDecimal.ZERO;
|
||||
if (pickThisReceiptMetricIncrement(c.getReceiptNetWeight(), c.getTotalNetWeight(), cDbNet).compareTo(BigDecimal.ZERO) > 0
|
||||
|| pickThisReceiptMetricIncrement(c.getReceiptGrossWeight(), c.getTotalGrossWeight(), cDbGross).compareTo(BigDecimal.ZERO) > 0) {
|
||||
BigDecimal gateChildQty = c.getReceiptQuantity() != null ? c.getReceiptQuantity() : BigDecimal.ZERO;
|
||||
if (pickThisReceiptMetricIncrementPda(
|
||||
c.getReceiptNetWeight(), c.getTotalNetWeight(), cDbNet, cdb,
|
||||
receiptMaterialDetailPODbList,
|
||||
ReceiptMaterialDetailPO::getPlanNetWeight,
|
||||
ReceiptMaterialDetailPO::getAlreadyReceiptNetWeight,
|
||||
gateChildQty).compareTo(BigDecimal.ZERO) > 0
|
||||
|| pickThisReceiptMetricIncrementPda(
|
||||
c.getReceiptGrossWeight(), c.getTotalGrossWeight(), cDbGross, cdb,
|
||||
receiptMaterialDetailPODbList,
|
||||
ReceiptMaterialDetailPO::getPlanGrossWeight,
|
||||
ReceiptMaterialDetailPO::getAlreadyReceiptGrossWeight,
|
||||
gateChildQty).compareTo(BigDecimal.ZERO) > 0) {
|
||||
hasReceiptByMetrics = true;
|
||||
break;
|
||||
}
|
||||
@@ -2347,10 +2822,22 @@ public class StockReceiptOrderApplicationService {
|
||||
BigDecimal childDbAlreadyArea = receiptMaterialDetailPOChildDb != null && receiptMaterialDetailPOChildDb.getAlreadyReceiptArea() != null
|
||||
? receiptMaterialDetailPOChildDb.getAlreadyReceiptArea() : BigDecimal.ZERO;
|
||||
BigDecimal childQty = receiptMaterialDetailDOChild.getReceiptQuantity() != null ? receiptMaterialDetailDOChild.getReceiptQuantity() : BigDecimal.ZERO;
|
||||
BigDecimal childGross = pickThisReceiptMetricIncrement(receiptMaterialDetailDOChild.getReceiptGrossWeight(), receiptMaterialDetailDOChild.getTotalGrossWeight(), childDbAlreadyGross);
|
||||
BigDecimal childNet = pickThisReceiptMetricIncrement(receiptMaterialDetailDOChild.getReceiptNetWeight(), receiptMaterialDetailDOChild.getTotalNetWeight(), childDbAlreadyNet);
|
||||
BigDecimal childVol = pickThisReceiptMetricIncrement(receiptMaterialDetailDOChild.getReceiptVolume(), receiptMaterialDetailDOChild.getTotalVolume(), childDbAlreadyVol);
|
||||
BigDecimal childArea = pickThisReceiptMetricIncrement(receiptMaterialDetailDOChild.getReceiptArea(), receiptMaterialDetailDOChild.getTotalArea(), childDbAlreadyArea);
|
||||
BigDecimal childGross = pickThisReceiptMetricIncrementPda(
|
||||
receiptMaterialDetailDOChild.getReceiptGrossWeight(), receiptMaterialDetailDOChild.getTotalGrossWeight(),
|
||||
childDbAlreadyGross, receiptMaterialDetailPOChildDb, receiptMaterialDetailPODbList,
|
||||
ReceiptMaterialDetailPO::getPlanGrossWeight, ReceiptMaterialDetailPO::getAlreadyReceiptGrossWeight, childQty);
|
||||
BigDecimal childNet = pickThisReceiptMetricIncrementPda(
|
||||
receiptMaterialDetailDOChild.getReceiptNetWeight(), receiptMaterialDetailDOChild.getTotalNetWeight(),
|
||||
childDbAlreadyNet, receiptMaterialDetailPOChildDb, receiptMaterialDetailPODbList,
|
||||
ReceiptMaterialDetailPO::getPlanNetWeight, ReceiptMaterialDetailPO::getAlreadyReceiptNetWeight, childQty);
|
||||
BigDecimal childVol = pickThisReceiptMetricIncrementPda(
|
||||
receiptMaterialDetailDOChild.getReceiptVolume(), receiptMaterialDetailDOChild.getTotalVolume(),
|
||||
childDbAlreadyVol, receiptMaterialDetailPOChildDb, receiptMaterialDetailPODbList,
|
||||
ReceiptMaterialDetailPO::getPlanVolume, ReceiptMaterialDetailPO::getAlreadyReceiptVolume, childQty);
|
||||
BigDecimal childArea = pickThisReceiptMetricIncrementPda(
|
||||
receiptMaterialDetailDOChild.getReceiptArea(), receiptMaterialDetailDOChild.getTotalArea(),
|
||||
childDbAlreadyArea, receiptMaterialDetailPOChildDb, receiptMaterialDetailPODbList,
|
||||
ReceiptMaterialDetailPO::getPlanArea, ReceiptMaterialDetailPO::getAlreadyReceiptArea, childQty);
|
||||
// PC 端子行常只回填 totalNetWeight/totalGrossWeight,不回传 receiptQuantity;用本次称重增量兜底为件数(与千克等重量计量物料一致)
|
||||
if (childQty.compareTo(BigDecimal.ZERO) == 0 && childNet.compareTo(BigDecimal.ZERO) > 0) {
|
||||
childQty = childNet;
|
||||
@@ -2429,10 +2916,22 @@ public class StockReceiptOrderApplicationService {
|
||||
BigDecimal dbParentBeforeNet = receiptMaterialDetailPO.getAlreadyReceiptNetWeight() != null ? receiptMaterialDetailPO.getAlreadyReceiptNetWeight() : BigDecimal.ZERO;
|
||||
BigDecimal dbParentBeforeVol = receiptMaterialDetailPO.getAlreadyReceiptVolume() != null ? receiptMaterialDetailPO.getAlreadyReceiptVolume() : BigDecimal.ZERO;
|
||||
BigDecimal dbParentBeforeArea = receiptMaterialDetailPO.getAlreadyReceiptArea() != null ? receiptMaterialDetailPO.getAlreadyReceiptArea() : BigDecimal.ZERO;
|
||||
BigDecimal parentReceiptGross = pickThisReceiptMetricIncrement(receiptMaterialDetailDO.getReceiptGrossWeight(), receiptMaterialDetailDO.getTotalGrossWeight(), dbParentBeforeGross);
|
||||
BigDecimal parentReceiptNet = pickThisReceiptMetricIncrement(receiptMaterialDetailDO.getReceiptNetWeight(), receiptMaterialDetailDO.getTotalNetWeight(), dbParentBeforeNet);
|
||||
BigDecimal parentReceiptVol = pickThisReceiptMetricIncrement(receiptMaterialDetailDO.getReceiptVolume(), receiptMaterialDetailDO.getTotalVolume(), dbParentBeforeVol);
|
||||
BigDecimal parentReceiptArea = pickThisReceiptMetricIncrement(receiptMaterialDetailDO.getReceiptArea(), receiptMaterialDetailDO.getTotalArea(), dbParentBeforeArea);
|
||||
BigDecimal parentReceiptGross = pickThisReceiptMetricIncrementPda(
|
||||
receiptMaterialDetailDO.getReceiptGrossWeight(), receiptMaterialDetailDO.getTotalGrossWeight(),
|
||||
dbParentBeforeGross, receiptMaterialDetailPO, receiptMaterialDetailPODbList,
|
||||
ReceiptMaterialDetailPO::getPlanGrossWeight, ReceiptMaterialDetailPO::getAlreadyReceiptGrossWeight, mainItemActualQuantity);
|
||||
BigDecimal parentReceiptNet = pickThisReceiptMetricIncrementPda(
|
||||
receiptMaterialDetailDO.getReceiptNetWeight(), receiptMaterialDetailDO.getTotalNetWeight(),
|
||||
dbParentBeforeNet, receiptMaterialDetailPO, receiptMaterialDetailPODbList,
|
||||
ReceiptMaterialDetailPO::getPlanNetWeight, ReceiptMaterialDetailPO::getAlreadyReceiptNetWeight, mainItemActualQuantity);
|
||||
BigDecimal parentReceiptVol = pickThisReceiptMetricIncrementPda(
|
||||
receiptMaterialDetailDO.getReceiptVolume(), receiptMaterialDetailDO.getTotalVolume(),
|
||||
dbParentBeforeVol, receiptMaterialDetailPO, receiptMaterialDetailPODbList,
|
||||
ReceiptMaterialDetailPO::getPlanVolume, ReceiptMaterialDetailPO::getAlreadyReceiptVolume, mainItemActualQuantity);
|
||||
BigDecimal parentReceiptArea = pickThisReceiptMetricIncrementPda(
|
||||
receiptMaterialDetailDO.getReceiptArea(), receiptMaterialDetailDO.getTotalArea(),
|
||||
dbParentBeforeArea, receiptMaterialDetailPO, receiptMaterialDetailPODbList,
|
||||
ReceiptMaterialDetailPO::getPlanArea, ReceiptMaterialDetailPO::getAlreadyReceiptArea, mainItemActualQuantity);
|
||||
// 主行 already_* 只累计主行本行毛净重体面积;子行各自落子行记录,避免主行重复叠加子行导致与数量口径不一致
|
||||
BigDecimal mainGrossIncrement = parentReceiptGross;
|
||||
BigDecimal mainNetIncrement = parentReceiptNet;
|
||||
@@ -2490,6 +2989,11 @@ public class StockReceiptOrderApplicationService {
|
||||
ReceiptMaterialDetailDO returnReceiptMaterialDetailDO = new ReceiptMaterialDetailDO();
|
||||
BeanUtils.copyProperties(receiptMaterialDetailPO, returnReceiptMaterialDetailDO);
|
||||
BeanUtils.copyProperties(receiptMaterialDetailDO, returnReceiptMaterialDetailDO, IgnoreNullUtil.getNullPropertyNames(receiptMaterialDetailDO));
|
||||
// 主行本次收货件数为 0、仅子行有收货时:不从请求覆盖主行批次号(避免 PDA 把子行新批次回写到主行,冲掉首笔批次)
|
||||
if (mainItemActualQuantity.compareTo(BigDecimal.ZERO) == 0
|
||||
&& !CollectionUtils.isEmpty(returnReceiptMaterialDetailDOChildList)) {
|
||||
returnReceiptMaterialDetailDO.setBatchNumber(receiptMaterialDetailPO.getBatchNumber());
|
||||
}
|
||||
returnReceiptMaterialDetailDO.setTotalNetWeight(receiptMaterialDetailDO.getTotalNetWeight());
|
||||
returnReceiptMaterialDetailDO.setTotalGrossWeight(receiptMaterialDetailDO.getTotalGrossWeight());
|
||||
returnReceiptMaterialDetailDO.setTotalVolume(receiptMaterialDetailDO.getTotalVolume());
|
||||
|
||||
+776
-33
@@ -57,9 +57,11 @@ import org.springframework.util.CollectionUtils;
|
||||
import java.lang.reflect.Field;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
@@ -204,31 +206,17 @@ public class StockShelfOrderApplicationService {
|
||||
|
||||
/**
|
||||
* 获取上架单详细信息
|
||||
*
|
||||
* @param shelfOrderId 上架单ID
|
||||
* @param addParentCopyWhenNoChildren 主项无子项时是否添加 parent_copy:true-PDA 详情页从 children 读取数据需要;false-PC 端收货无子项时上架不显示虚拟子项
|
||||
* @param addParentCopyWhenNoChildren 历史参数名保留:为 true 时表示走 {@link #getInfo(Long, boolean, Integer)} 中的 PDA 详情流水线(扁平化、待上架、重量展示等);<b>不再</b>向 children 注入
|
||||
* parent_copy,避免与主行重复两条;无子项时由前端从主项字段读取,与 {@link com.mhd.wms.domain.stockShelfOrder.service.StockShelfOrderDomainService#getInfoByApp(Long)} 一致。为 false 时走 PC 端汇总与扁平化。
|
||||
*/
|
||||
public StockShelfOrderPO getInfo(Long shelfOrderId, boolean addParentCopyWhenNoChildren) {
|
||||
StockShelfOrderPO stockShelfOrderPO = stockShelfOrderDomainService.getInfo(shelfOrderId);
|
||||
ShelfMaterialDetailDO shelfMaterialDetailDO = new ShelfMaterialDetailDO();
|
||||
shelfMaterialDetailDO.setShelfOrderNumber(stockShelfOrderPO.getShelfOrderNumber());
|
||||
List<ShelfMaterialDetailPO> shelfMaterialDetailPOList = shelfMaterialDetailDomainService.queryListChildren(shelfMaterialDetailDO);
|
||||
// PDA:主项无子项时添加 parent_copy 到 children,供详情页展示(详情页从 children 读取数据);PC:不添加,避免收货无子项时上架显示虚拟子项
|
||||
if (addParentCopyWhenNoChildren) {
|
||||
for (ShelfMaterialDetailPO parent : shelfMaterialDetailPOList) {
|
||||
if (CollectionUtils.isEmpty(parent.getChildren())) {
|
||||
ShelfMaterialDetailPO parentCopy = new ShelfMaterialDetailPO();
|
||||
BeanUtils.copyProperties(parent, parentCopy, "children");
|
||||
parentCopy.setLevel(2);
|
||||
parentCopy.setParentUniqueId(parent.getUniqueId());
|
||||
parentCopy.setQuantity(null);
|
||||
parentCopy.setChildren(new ArrayList<>());
|
||||
List<ShelfMaterialDetailPO> children = new ArrayList<>();
|
||||
children.add(parentCopy);
|
||||
parent.setChildren(children);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 性能优化:批量获取批次属性,避免N+1查询问题
|
||||
// 1. 收集所有唯一的materialBaseInfoId
|
||||
Set<Long> materialBaseInfoIdSet = shelfMaterialDetailPOList.stream()
|
||||
@@ -322,11 +310,40 @@ public class StockShelfOrderApplicationService {
|
||||
|
||||
// 第一次上架:主项无子项时,上架数量默认等于收货数量(quantity 由上架单生成时取自收货数量),供 PDA 表单默认展示
|
||||
fillFirstShelvesQuantityDefault(shelfMaterialDetailPOList);
|
||||
|
||||
|
||||
// PC 端(addParentCopyWhenNoChildren==false):单头 total* 仍按明细树递归汇总;明细行净重/毛重/体积/面积<strong>不</strong>做「计划−已上架」覆盖,保持 shelf_material_detail 库表值
|
||||
if (!addParentCopyWhenNoChildren) {
|
||||
BigDecimal totalNetWeight = BigDecimal.ZERO;
|
||||
BigDecimal totalGrossWeight = BigDecimal.ZERO;
|
||||
BigDecimal totalVolume = BigDecimal.ZERO;
|
||||
BigDecimal totalArea = BigDecimal.ZERO;
|
||||
if (!CollectionUtils.isEmpty(shelfMaterialDetailPOList)) {
|
||||
for (ShelfMaterialDetailPO detail : shelfMaterialDetailPOList) {
|
||||
totalNetWeight = totalNetWeight.add(sumShelfDetailRecursively(detail, ShelfMaterialDetailPO::getTotalNetWeight));
|
||||
totalGrossWeight = totalGrossWeight.add(sumShelfDetailRecursively(detail, ShelfMaterialDetailPO::getTotalGrossWeight));
|
||||
totalVolume = totalVolume.add(sumShelfDetailRecursively(detail, ShelfMaterialDetailPO::getTotalVolume));
|
||||
totalArea = totalArea.add(sumShelfDetailRecursively(detail, ShelfMaterialDetailPO::getTotalArea));
|
||||
}
|
||||
}
|
||||
stockShelfOrderPO.setTotalNetWeight(totalNetWeight);
|
||||
stockShelfOrderPO.setTotalGrossWeight(totalGrossWeight);
|
||||
stockShelfOrderPO.setTotalVolume(totalVolume);
|
||||
stockShelfOrderPO.setTotalArea(totalArea);
|
||||
boolean shelfOrderCompleted = stockShelfOrderPO.getStatus() != null && stockShelfOrderPO.getStatus() == 3;
|
||||
flattenShelfMaterialDetailList(shelfMaterialDetailPOList, shelfOrderCompleted);
|
||||
clearChildQuantityShelfRecursively(shelfMaterialDetailPOList);
|
||||
fillPendingShelvesQuantityRecursively(shelfMaterialDetailPOList);
|
||||
syncMaterialMoreDetailWeightValuesRecursively(shelfMaterialDetailPOList);
|
||||
}
|
||||
|
||||
stockShelfOrderPO.setMaterialDetailList(shelfMaterialDetailPOList);
|
||||
log.info("返回上架单信息,shelfOrderId={}, materialDetailList大小={}",
|
||||
stockShelfOrderPO.getShelfOrderId(),
|
||||
shelfMaterialDetailPOList != null ? shelfMaterialDetailPOList.size() : 0);
|
||||
log.info("返回上架单信息,shelfOrderId={}, materialDetailList大小={}, totalNetWeight={}, totalGrossWeight={}, totalVolume={}, totalArea={}",
|
||||
stockShelfOrderPO.getShelfOrderId(),
|
||||
shelfMaterialDetailPOList != null ? shelfMaterialDetailPOList.size() : 0,
|
||||
stockShelfOrderPO.getTotalNetWeight(),
|
||||
stockShelfOrderPO.getTotalGrossWeight(),
|
||||
stockShelfOrderPO.getTotalVolume(),
|
||||
stockShelfOrderPO.getTotalArea());
|
||||
return stockShelfOrderPO;
|
||||
}
|
||||
|
||||
@@ -351,9 +368,12 @@ public class StockShelfOrderApplicationService {
|
||||
if (shelfStatus != null) {
|
||||
materialDetailList = filterShelfMaterialDetailsByShelfStatus(materialDetailList, shelfStatus);
|
||||
}
|
||||
// 已上架完成(3/4/5):主项无子项时注入的 parent_copy 与主项为同一明细,子行可能仍带「本次提交」的 shelves_quantity=0,
|
||||
// 导致「上架数量」误显示为 0;与主项对齐累计已上架数量后再做展示计算
|
||||
// 兼容历史:若 children 中仍有镜像子行(与主项同 uniqueId),已收尾时与主项对齐累计已上架,再扁平化/剔除镜像
|
||||
alignParentCopyShelfQuantityWithParentForTerminal(materialDetailList);
|
||||
boolean shelfOrderCompleted = stockShelfOrderPO.getStatus() != null && stockShelfOrderPO.getStatus() == 3;
|
||||
flattenShelfMaterialDetailList(materialDetailList, shelfOrderCompleted);
|
||||
// 与域层 getInfoByApp 一致:不再注入 parent_copy;若旧客户端缓存等仍带镜像子行,从树中剔除以免详情列表出现两条
|
||||
removeShelfParentCopyMirrorChildrenRecursively(materialDetailList);
|
||||
// PDA 待上架数量 = 计划数量 - 已上架数量,仅接口计算(不落库)
|
||||
fillPendingShelvesQuantityRecursively(materialDetailList);
|
||||
// PDA 展示:shelvesQuantity 显示为累计已上架数量(与 receipt 口径一致);已上架完成行不再用本次提交量
|
||||
@@ -364,10 +384,19 @@ public class StockShelfOrderApplicationService {
|
||||
Map<Long, WeightMetrics> planWeightMetrics = loadReceiptPlanWeightMetrics(stockShelfOrderPO.getReceiptOrderNumber());
|
||||
overwriteTotalWithPendingForPdaWeightDisplayRecursively(materialDetailList, planWeightMetrics);
|
||||
syncMaterialMoreDetailWeightValuesRecursively(materialDetailList);
|
||||
// 与收货 PDA getInfoByApp 一致:保留 children;仅清空子行「计划数量」quantity(见 clearChildQuantityRecursively),不在此剔除分库位 level=2 子行
|
||||
clearChildQuantityShelfRecursively(materialDetailList);
|
||||
stockShelfOrderPO.setMaterialDetailList(materialDetailList);
|
||||
return stockShelfOrderPO;
|
||||
}
|
||||
|
||||
/**
|
||||
* PDA:按父计划行查询分批上架子行(level=2),与收货 {@link com.mhd.wms.application.service.stockReceiptOrder.StockReceiptOrderApplicationService#listLevel2ChildrenByParentForApp} 对称。
|
||||
*/
|
||||
public List<ShelfMaterialDetailPO> listLevel2ChildrenByParentForApp(Long shelfOrderId, Long parentMaterialDetailId) {
|
||||
return stockShelfOrderDomainService.listLevel2ChildrenByParentForApp(shelfOrderId, parentMaterialDetailId);
|
||||
}
|
||||
|
||||
private List<ShelfMaterialDetailPO> filterShelfMaterialDetailsByShelfStatus(List<ShelfMaterialDetailPO> source, Integer shelfStatus) {
|
||||
if (CollectionUtils.isEmpty(source) || shelfStatus == null) {
|
||||
return source;
|
||||
@@ -399,6 +428,46 @@ public class StockShelfOrderApplicationService {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归汇总明细及其子项的某字段值(与收货 {@link com.mhd.wms.application.service.stockReceiptOrder.StockReceiptOrderApplicationService} 中
|
||||
* sumDetailRecursively 一致,用于 PC 单头 total*)
|
||||
*/
|
||||
private static BigDecimal sumShelfDetailRecursively(ShelfMaterialDetailPO detail, Function<ShelfMaterialDetailPO, BigDecimal> getter) {
|
||||
BigDecimal sum = BigDecimal.ZERO;
|
||||
if (detail == null || getter == null) {
|
||||
return sum;
|
||||
}
|
||||
BigDecimal v = getter.apply(detail);
|
||||
if (v != null) {
|
||||
sum = sum.add(v);
|
||||
}
|
||||
List<ShelfMaterialDetailPO> children = detail.getChildren();
|
||||
if (!CollectionUtils.isEmpty(children)) {
|
||||
for (ShelfMaterialDetailPO child : children) {
|
||||
sum = sum.add(sumShelfDetailRecursively(child, getter));
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
/**
|
||||
* PC 端子项计划数量不展示:递归清空所有子项的 quantity(与收货 clearChildQuantityRecursively 一致)
|
||||
*/
|
||||
private void clearChildQuantityShelfRecursively(List<ShelfMaterialDetailPO> shelfMaterialDetailPOList) {
|
||||
if (CollectionUtils.isEmpty(shelfMaterialDetailPOList)) {
|
||||
return;
|
||||
}
|
||||
for (ShelfMaterialDetailPO detail : shelfMaterialDetailPOList) {
|
||||
List<ShelfMaterialDetailPO> children = detail.getChildren();
|
||||
if (!CollectionUtils.isEmpty(children)) {
|
||||
for (ShelfMaterialDetailPO child : children) {
|
||||
child.setQuantity(null);
|
||||
clearChildQuantityShelfRecursively(child.getChildren());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* PDA 待上架数量递归计算:待上架数量 = max(0, 计划数量 - 已上架数量)
|
||||
*/
|
||||
@@ -450,6 +519,418 @@ public class StockShelfOrderApplicationService {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 扁平化明细:主行保留父子结构;主行「已上架数量」与上架状态仍按主行+子行汇总(与分批场景一致)。
|
||||
* 主行净重/毛重/体积/面积<strong>不再</strong>用主+子汇总覆盖,保留库表主行单行值(子行仍为自身行明细)。
|
||||
*
|
||||
* @param shelfOrderCompleted 上架单是否已整单完成(status=3);为 true 时少上为 4,与域服务完成口径一致
|
||||
*/
|
||||
private void flattenShelfMaterialDetailList(List<ShelfMaterialDetailPO> shelfMaterialDetailPOList,
|
||||
boolean shelfOrderCompleted) {
|
||||
if (CollectionUtils.isEmpty(shelfMaterialDetailPOList)) {
|
||||
return;
|
||||
}
|
||||
List<ShelfMaterialDetailPO> allNodes = new ArrayList<>();
|
||||
collectShelfMaterialDetailNodesRecursively(shelfMaterialDetailPOList, allNodes);
|
||||
Map<Long, List<ShelfMaterialDetailPO>> childrenByParentUid = new HashMap<>();
|
||||
for (ShelfMaterialDetailPO node : allNodes) {
|
||||
if (node == null || node.getLevel() == null || node.getLevel() != 2) {
|
||||
continue;
|
||||
}
|
||||
Long puid = node.getParentUniqueId();
|
||||
if (puid == null || Long.valueOf(0).equals(puid)) {
|
||||
continue;
|
||||
}
|
||||
childrenByParentUid.computeIfAbsent(puid, k -> new ArrayList<>()).add(node);
|
||||
}
|
||||
for (ShelfMaterialDetailPO parent : shelfMaterialDetailPOList) {
|
||||
if (parent == null) {
|
||||
continue;
|
||||
}
|
||||
if (parent.getLevel() != null && parent.getLevel() != 1) {
|
||||
continue;
|
||||
}
|
||||
BigDecimal qtySum = sumAlreadyShelvesUnderPlanParent(parent, allNodes);
|
||||
Integer derived = deriveShelfStatusFromAggregatedVsPlan(qtySum, parent.getQuantity(), shelfOrderCompleted);
|
||||
|
||||
parent.setAlreadyShelvesQuantity(qtySum);
|
||||
if (derived != null) {
|
||||
parent.setShelvesStatus(derived);
|
||||
}
|
||||
|
||||
LinkedHashMap<Long, ShelfMaterialDetailPO> mergedChildren = new LinkedHashMap<>();
|
||||
mergeShelfChildRowsIntoMap(mergedChildren, parent.getChildren());
|
||||
Long uid = parent.getUniqueId();
|
||||
Long inUid = parent.getInUniqueId();
|
||||
if (uid != null) {
|
||||
mergeShelfChildRowsIntoMap(mergedChildren, childrenByParentUid.get(uid));
|
||||
}
|
||||
if (inUid != null && !inUid.equals(uid)) {
|
||||
mergeShelfChildRowsIntoMap(mergedChildren, childrenByParentUid.get(inUid));
|
||||
}
|
||||
if (mergedChildren.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
for (ShelfMaterialDetailPO child : mergedChildren.values()) {
|
||||
if (child == null) {
|
||||
continue;
|
||||
}
|
||||
if (parent.getUniqueId() != null && parent.getUniqueId().equals(child.getUniqueId())) {
|
||||
child.setQuantity(null);
|
||||
continue;
|
||||
}
|
||||
child.setQuantity(null);
|
||||
if (derived != null && child.getLevel() != null && child.getLevel() == 2) {
|
||||
child.setShelvesStatus(derived);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 主行展示用上架状态:按「主行+子行汇总已上架」与主行计划量比较。
|
||||
*/
|
||||
private static Integer deriveShelfStatusFromAggregatedVsPlan(BigDecimal aggregatedShelves, BigDecimal planQty,
|
||||
boolean shelfOrderCompleted) {
|
||||
BigDecimal r = aggregatedShelves != null ? aggregatedShelves : BigDecimal.ZERO;
|
||||
BigDecimal p = planQty != null ? planQty : BigDecimal.ZERO;
|
||||
if (shelfOrderCompleted) {
|
||||
int cmp = r.compareTo(p);
|
||||
if (cmp > 0) {
|
||||
return 5;
|
||||
}
|
||||
if (cmp < 0) {
|
||||
return 4;
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
if (r.compareTo(BigDecimal.ZERO) == 0) {
|
||||
return 1;
|
||||
}
|
||||
int cmp = r.compareTo(p);
|
||||
if (cmp < 0) {
|
||||
return 2;
|
||||
}
|
||||
if (cmp > 0) {
|
||||
return 5;
|
||||
}
|
||||
return 3;
|
||||
}
|
||||
|
||||
private static void collectShelfMaterialDetailNodesRecursively(List<ShelfMaterialDetailPO> list, List<ShelfMaterialDetailPO> out) {
|
||||
if (CollectionUtils.isEmpty(list)) {
|
||||
return;
|
||||
}
|
||||
for (ShelfMaterialDetailPO n : list) {
|
||||
if (n == null) {
|
||||
continue;
|
||||
}
|
||||
out.add(n);
|
||||
collectShelfMaterialDetailNodesRecursively(n.getChildren(), out);
|
||||
}
|
||||
}
|
||||
|
||||
private static void mergeShelfChildRowsIntoMap(Map<Long, ShelfMaterialDetailPO> byKey, List<ShelfMaterialDetailPO> children) {
|
||||
if (CollectionUtils.isEmpty(children)) {
|
||||
return;
|
||||
}
|
||||
for (ShelfMaterialDetailPO c : children) {
|
||||
if (c == null) {
|
||||
continue;
|
||||
}
|
||||
Long key = c.getUniqueId();
|
||||
if (key == null) {
|
||||
key = c.getMaterialDetailId();
|
||||
}
|
||||
if (key == null) {
|
||||
continue;
|
||||
}
|
||||
byKey.putIfAbsent(key, c);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean sameLongId(Long a, Long b) {
|
||||
if (a == null || b == null) {
|
||||
return false;
|
||||
}
|
||||
return a.longValue() == b.longValue();
|
||||
}
|
||||
|
||||
private static boolean isLevel2ChildShelfRowUnderPlanParent(ShelfMaterialDetailPO planParent, ShelfMaterialDetailPO x) {
|
||||
if (planParent == 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 = planParent.getUniqueId();
|
||||
Long inUid = planParent.getInUniqueId();
|
||||
boolean linked = (uid != null && sameLongId(uid, puid)) || (inUid != null && sameLongId(inUid, puid));
|
||||
if (!linked) {
|
||||
return false;
|
||||
}
|
||||
if (planParent.getUniqueId() != null && sameLongId(planParent.getUniqueId(), x.getUniqueId())) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static BigDecimal sumAlreadyShelvesUnderPlanParent(ShelfMaterialDetailPO planParent,
|
||||
List<ShelfMaterialDetailPO> dbList) {
|
||||
if (planParent == null || CollectionUtils.isEmpty(dbList)) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
BigDecimal sum = planParent.getAlreadyShelvesQuantity() != null
|
||||
? planParent.getAlreadyShelvesQuantity() : BigDecimal.ZERO;
|
||||
for (ShelfMaterialDetailPO x : dbList) {
|
||||
if (x == null || !isLevel2ChildShelfRowUnderPlanParent(planParent, x)) {
|
||||
continue;
|
||||
}
|
||||
BigDecimal ar = x.getAlreadyShelvesQuantity() != null ? x.getAlreadyShelvesQuantity() : BigDecimal.ZERO;
|
||||
sum = sum.add(ar);
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
private static BigDecimal sumAlreadyShelfMetricUnderPlanParent(ShelfMaterialDetailPO planParent,
|
||||
List<ShelfMaterialDetailPO> dbList,
|
||||
Function<ShelfMaterialDetailPO, BigDecimal> alreadyGetter) {
|
||||
if (planParent == null || CollectionUtils.isEmpty(dbList) || alreadyGetter == null) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
BigDecimal base = alreadyGetter.apply(planParent);
|
||||
BigDecimal sum = base != null ? base : BigDecimal.ZERO;
|
||||
for (ShelfMaterialDetailPO x : dbList) {
|
||||
if (x == null || !isLevel2ChildShelfRowUnderPlanParent(planParent, x)) {
|
||||
continue;
|
||||
}
|
||||
BigDecimal v = alreadyGetter.apply(x);
|
||||
sum = sum.add(v != null ? v : BigDecimal.ZERO);
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
/**
|
||||
* 计划主行维度累计(重量/体面积):主行库表单行 + 树下 level=2 子行。
|
||||
* 待上架展示用「计划 − 已上架」时,子行需按整卡扣减;主行接口字段不再汇总后仍用此合计参与计算。
|
||||
*/
|
||||
private static BigDecimal sumShelfPlanRowAggregatedAlreadyMetric(ShelfMaterialDetailPO planParent,
|
||||
Function<ShelfMaterialDetailPO, BigDecimal> alreadyGetter) {
|
||||
if (planParent == null || alreadyGetter == null) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
BigDecimal base = alreadyGetter.apply(planParent);
|
||||
BigDecimal sum = base != null ? base : BigDecimal.ZERO;
|
||||
List<ShelfMaterialDetailPO> ch = planParent.getChildren();
|
||||
if (CollectionUtils.isEmpty(ch)) {
|
||||
return sum;
|
||||
}
|
||||
for (ShelfMaterialDetailPO c : ch) {
|
||||
if (c == null || c.getLevel() == null || c.getLevel() != 2) {
|
||||
continue;
|
||||
}
|
||||
if (planParent.getUniqueId() != null && planParent.getUniqueId().equals(c.getUniqueId())) {
|
||||
continue;
|
||||
}
|
||||
BigDecimal v = alreadyGetter.apply(c);
|
||||
if (v != null) {
|
||||
sum = sum.add(v);
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
/** 计划父行:level=1 自身;level=2 则按 parent_unique_id 定位主计划行(对齐收货 {@code resolveReceiptPlanParentRow}) */
|
||||
private static ShelfMaterialDetailPO resolveShelfPlanParentRow(ShelfMaterialDetailPO db,
|
||||
List<ShelfMaterialDetailPO> dbList) {
|
||||
if (db == null || CollectionUtils.isEmpty(dbList)) {
|
||||
return db;
|
||||
}
|
||||
if (db.getLevel() == null || db.getLevel() == 1) {
|
||||
return db;
|
||||
}
|
||||
if (db.getLevel() == 2 && db.getParentUniqueId() != null) {
|
||||
Long puid = db.getParentUniqueId();
|
||||
for (ShelfMaterialDetailPO x : dbList) {
|
||||
if (x == null) {
|
||||
continue;
|
||||
}
|
||||
if (puid.equals(x.getUniqueId()) || puid.equals(x.getInUniqueId())) {
|
||||
return x;
|
||||
}
|
||||
}
|
||||
}
|
||||
return db;
|
||||
}
|
||||
|
||||
/**
|
||||
* 首次可只落主行不拆;已有 level=2 子行或主行+子行已有累计已上架时再拆(对齐收货 {@code shouldPdaSplitIntoChildRow})
|
||||
*/
|
||||
private static boolean shouldPdaSplitIntoShelfChildRow(ShelfMaterialDetailPO dbLine,
|
||||
List<ShelfMaterialDetailPO> allDbLines) {
|
||||
if (dbLine == null || CollectionUtils.isEmpty(allDbLines)) {
|
||||
return true;
|
||||
}
|
||||
ShelfMaterialDetailPO plan = resolveShelfPlanParentRow(dbLine, allDbLines);
|
||||
if (plan == null) {
|
||||
return true;
|
||||
}
|
||||
Long uid = plan.getUniqueId();
|
||||
Long inUid = plan.getInUniqueId();
|
||||
boolean hasL2 = allDbLines.stream().anyMatch(x -> x != null && x.getLevel() != null && x.getLevel() == 2
|
||||
&& x.getParentUniqueId() != null
|
||||
&& ((uid != null && uid.equals(x.getParentUniqueId()))
|
||||
|| (inUid != null && inUid.equals(x.getParentUniqueId()))));
|
||||
if (hasL2) {
|
||||
return true;
|
||||
}
|
||||
BigDecimal sum = sumAlreadyShelvesUnderPlanParent(plan, allDbLines);
|
||||
return sum.compareTo(BigDecimal.ZERO) > 0;
|
||||
}
|
||||
|
||||
private static boolean isCorruptedStandaloneLineAsLevel2Shelf(ShelfMaterialDetailPO dbLine) {
|
||||
if (dbLine == null || dbLine.getLevel() == null || dbLine.getLevel() != 2) {
|
||||
return false;
|
||||
}
|
||||
return dbLine.getParentUniqueId() == null || Objects.equals(dbLine.getParentUniqueId(), 0L);
|
||||
}
|
||||
|
||||
private static void stripPdaUiParentCopyChildrenShelf(ShelfMaterialDetailDO line, ShelfMaterialDetailPO dbLine) {
|
||||
if (line == null || CollectionUtils.isEmpty(line.getChildren())) {
|
||||
return;
|
||||
}
|
||||
Long parentUid = line.getUniqueId() != null ? line.getUniqueId() : (dbLine != null ? dbLine.getUniqueId() : null);
|
||||
List<ShelfMaterialDetailDO> realOnly = new ArrayList<>();
|
||||
for (ShelfMaterialDetailDO c : line.getChildren()) {
|
||||
if (c == null) {
|
||||
continue;
|
||||
}
|
||||
if (parentUid != null && parentUid.equals(c.getUniqueId())) {
|
||||
continue;
|
||||
}
|
||||
realOnly.add(c);
|
||||
}
|
||||
line.setChildren(realOnly);
|
||||
}
|
||||
|
||||
/** getInfo 挂在 children 里的已落库子行,再次上架时需去掉,否则无法走「拆新子行」注入(对齐收货 stripPdaExistingDisplayedChildrenForResplit) */
|
||||
private static void stripPdaExistingDisplayedChildrenForResplitShelf(ShelfMaterialDetailDO line,
|
||||
ShelfMaterialDetailPO dbLine,
|
||||
List<ShelfMaterialDetailPO> allDbLines) {
|
||||
if (line == null || CollectionUtils.isEmpty(line.getChildren()) || dbLine == null || CollectionUtils.isEmpty(allDbLines)) {
|
||||
return;
|
||||
}
|
||||
Long puid = dbLine.getUniqueId();
|
||||
Long pInUid = dbLine.getInUniqueId();
|
||||
List<ShelfMaterialDetailDO> keep = new ArrayList<>();
|
||||
for (ShelfMaterialDetailDO c : line.getChildren()) {
|
||||
if (c == null) {
|
||||
continue;
|
||||
}
|
||||
Long mid = c.getMaterialDetailId();
|
||||
Long cuid = c.getUniqueId();
|
||||
boolean isExistingDbChild = false;
|
||||
for (ShelfMaterialDetailPO x : allDbLines) {
|
||||
if (x == null || x.getLevel() == null || x.getLevel() != 2 || x.getParentUniqueId() == null) {
|
||||
continue;
|
||||
}
|
||||
boolean parentOk = (puid != null && puid.equals(x.getParentUniqueId()))
|
||||
|| (pInUid != null && pInUid.equals(x.getParentUniqueId()));
|
||||
if (!parentOk) {
|
||||
continue;
|
||||
}
|
||||
if (mid != null && mid.equals(x.getMaterialDetailId())) {
|
||||
isExistingDbChild = true;
|
||||
break;
|
||||
}
|
||||
if (cuid != null && cuid.equals(x.getUniqueId())) {
|
||||
isExistingDbChild = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!isExistingDbChild) {
|
||||
keep.add(c);
|
||||
}
|
||||
}
|
||||
line.setChildren(keep);
|
||||
}
|
||||
|
||||
/** 本次上架毛/净重、体积、面积增量(对齐收货 pickThisReceiptMetricIncrement;上架无 receipt* 字段,用 total*) */
|
||||
private static BigDecimal pickThisShelfMetricIncrement(BigDecimal receiptField, BigDecimal totalField,
|
||||
BigDecimal dbTotalAlreadyBefore) {
|
||||
if (receiptField != null) {
|
||||
return receiptField;
|
||||
}
|
||||
if (totalField == null) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
if (dbTotalAlreadyBefore == null) {
|
||||
return totalField;
|
||||
}
|
||||
if (totalField.compareTo(dbTotalAlreadyBefore) == 0) {
|
||||
return BigDecimal.ZERO;
|
||||
}
|
||||
if (totalField.compareTo(dbTotalAlreadyBefore) > 0) {
|
||||
return totalField.subtract(dbTotalAlreadyBefore);
|
||||
}
|
||||
return totalField;
|
||||
}
|
||||
|
||||
private static boolean hasPdaShelfMetricIncrement(ShelfMaterialDetailDO line, ShelfMaterialDetailPO dbLine) {
|
||||
if (line == null || dbLine == null) {
|
||||
return false;
|
||||
}
|
||||
BigDecimal dbNet = dbLine.getTotalNetWeight() != null ? dbLine.getTotalNetWeight() : BigDecimal.ZERO;
|
||||
BigDecimal dbGross = dbLine.getTotalGrossWeight() != null ? dbLine.getTotalGrossWeight() : BigDecimal.ZERO;
|
||||
BigDecimal dbVol = dbLine.getTotalVolume() != null ? dbLine.getTotalVolume() : BigDecimal.ZERO;
|
||||
BigDecimal dbArea = dbLine.getTotalArea() != null ? dbLine.getTotalArea() : BigDecimal.ZERO;
|
||||
return pickThisShelfMetricIncrement(null, line.getTotalNetWeight(), dbNet).compareTo(BigDecimal.ZERO) > 0
|
||||
|| pickThisShelfMetricIncrement(null, line.getTotalGrossWeight(), dbGross).compareTo(BigDecimal.ZERO) > 0
|
||||
|| pickThisShelfMetricIncrement(null, line.getTotalVolume(), dbVol).compareTo(BigDecimal.ZERO) > 0
|
||||
|| pickThisShelfMetricIncrement(null, line.getTotalArea(), dbArea).compareTo(BigDecimal.ZERO) > 0;
|
||||
}
|
||||
|
||||
private static Long resolveParentUniqueIdForPdaInjectChildShelf(ShelfMaterialDetailPO dbLine,
|
||||
List<ShelfMaterialDetailPO> allDbLines) {
|
||||
if (dbLine == null) {
|
||||
return null;
|
||||
}
|
||||
if (isCorruptedStandaloneLineAsLevel2Shelf(dbLine) && dbLine.getMaterialDetailId() != null
|
||||
&& !CollectionUtils.isEmpty(allDbLines)) {
|
||||
for (ShelfMaterialDetailPO x : allDbLines) {
|
||||
if (x != null && Objects.equals(dbLine.getMaterialDetailId(), x.getMaterialDetailId())
|
||||
&& x.getLevel() != null && x.getLevel() == 1) {
|
||||
return x.getUniqueId();
|
||||
}
|
||||
}
|
||||
}
|
||||
ShelfMaterialDetailPO plan = resolveShelfPlanParentRow(dbLine, allDbLines);
|
||||
return plan != null ? plan.getUniqueId() : dbLine.getUniqueId();
|
||||
}
|
||||
|
||||
/**
|
||||
* PDA 详情:从树上移除与主行同 material_detail_id / unique_id 的镜像子行(旧逻辑注入的 parent_copy),避免与主行并列两条。
|
||||
*/
|
||||
private void removeShelfParentCopyMirrorChildrenRecursively(List<ShelfMaterialDetailPO> list) {
|
||||
if (CollectionUtils.isEmpty(list)) {
|
||||
return;
|
||||
}
|
||||
for (ShelfMaterialDetailPO parent : list) {
|
||||
if (parent == null) {
|
||||
continue;
|
||||
}
|
||||
List<ShelfMaterialDetailPO> ch = parent.getChildren();
|
||||
if (!CollectionUtils.isEmpty(ch)) {
|
||||
ch.removeIf(c -> isShelfParentCopyPo(parent, c));
|
||||
removeShelfParentCopyMirrorChildrenRecursively(ch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断子项是否为 getInfo 时注入的 parent_copy(与主项同 materialDetailId 或 uniqueId)
|
||||
*/
|
||||
@@ -551,9 +1032,23 @@ public class StockShelfOrderApplicationService {
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* PDA/PC 详情:未完成行将 total* 覆盖为「待上架重量/体积」= 计划 − 累计已上架。
|
||||
* 与收货 {@link com.mhd.wms.application.service.stockReceiptOrder.StockReceiptOrderApplicationService#fillPlanAndPendingMetricsRecursively} 一致:
|
||||
* level=2 子行计算时用<strong>计划主行(level=1)上已汇总的 alreadyShelves*</strong>,不能用子行本行累计,
|
||||
* 否则「计划」是整张卡的计划,「已减」却只有子行一批,待上架会偏大。
|
||||
*/
|
||||
private void overwriteTotalWithPendingForPdaWeightDisplayRecursively(
|
||||
List<ShelfMaterialDetailPO> list,
|
||||
Map<Long, WeightMetrics> planWeightMetrics
|
||||
) {
|
||||
overwriteTotalWithPendingForPdaWeightDisplayRecursively(list, planWeightMetrics, null);
|
||||
}
|
||||
|
||||
private void overwriteTotalWithPendingForPdaWeightDisplayRecursively(
|
||||
List<ShelfMaterialDetailPO> list,
|
||||
Map<Long, WeightMetrics> planWeightMetrics,
|
||||
ShelfMaterialDetailPO planParent
|
||||
) {
|
||||
if (CollectionUtils.isEmpty(list)) {
|
||||
return;
|
||||
@@ -562,6 +1057,10 @@ public class StockShelfOrderApplicationService {
|
||||
if (d == null) {
|
||||
continue;
|
||||
}
|
||||
ShelfMaterialDetailPO nextPlanParent = planParent;
|
||||
if (d.getLevel() != null && d.getLevel() == 1) {
|
||||
nextPlanParent = d;
|
||||
}
|
||||
// 已上架:不覆盖,展示累计已上架实绩(与 DB 同口径)
|
||||
if (isShelfTerminalShelvesStatus(d.getShelvesStatus())) {
|
||||
// 参考收货:已完成行不参与「计划−待收」,total* 直接展示累计 already
|
||||
@@ -577,7 +1076,7 @@ public class StockShelfOrderApplicationService {
|
||||
if (d.getAlreadyShelvesArea() != null) {
|
||||
d.setTotalArea(d.getAlreadyShelvesArea());
|
||||
}
|
||||
overwriteTotalWithPendingForPdaWeightDisplayRecursively(d.getChildren(), planWeightMetrics);
|
||||
overwriteTotalWithPendingForPdaWeightDisplayRecursively(d.getChildren(), planWeightMetrics, nextPlanParent);
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -593,17 +1092,38 @@ public class StockShelfOrderApplicationService {
|
||||
BigDecimal alreadyVol = d.getAlreadyShelvesVolume() != null ? d.getAlreadyShelvesVolume() : BigDecimal.ZERO;
|
||||
BigDecimal alreadyArea = d.getAlreadyShelvesArea() != null ? d.getAlreadyShelvesArea() : BigDecimal.ZERO;
|
||||
|
||||
// level=1 有子行:待上架 = 计划 − (主行+子行)已上架;flatten 不再把主行重量汇总后,此处必须用整卡累计参与扣减,否则会只减主行
|
||||
if (d.getLevel() != null && d.getLevel() == 1 && !CollectionUtils.isEmpty(d.getChildren())) {
|
||||
alreadyNet = sumShelfPlanRowAggregatedAlreadyMetric(d, ShelfMaterialDetailPO::getAlreadyShelvesNetWeight);
|
||||
alreadyGross = sumShelfPlanRowAggregatedAlreadyMetric(d, ShelfMaterialDetailPO::getAlreadyShelvesGrossWeight);
|
||||
alreadyVol = sumShelfPlanRowAggregatedAlreadyMetric(d, ShelfMaterialDetailPO::getAlreadyShelvesVolume);
|
||||
alreadyArea = sumShelfPlanRowAggregatedAlreadyMetric(d, ShelfMaterialDetailPO::getAlreadyShelvesArea);
|
||||
}
|
||||
|
||||
// level=2 子行:计划为整张卡;已上架量用主行+子行 DB 累计之和(主行自身字段不再汇总时仍按整卡扣计划)
|
||||
if (planParent != null && d.getLevel() != null && d.getLevel() == 2) {
|
||||
alreadyNet = sumShelfPlanRowAggregatedAlreadyMetric(planParent, ShelfMaterialDetailPO::getAlreadyShelvesNetWeight);
|
||||
alreadyGross = sumShelfPlanRowAggregatedAlreadyMetric(planParent, ShelfMaterialDetailPO::getAlreadyShelvesGrossWeight);
|
||||
alreadyVol = sumShelfPlanRowAggregatedAlreadyMetric(planParent, ShelfMaterialDetailPO::getAlreadyShelvesVolume);
|
||||
alreadyArea = sumShelfPlanRowAggregatedAlreadyMetric(planParent, ShelfMaterialDetailPO::getAlreadyShelvesArea);
|
||||
}
|
||||
|
||||
// 参考收货:只对「有计划值」的字段覆盖 total*,否则保留原 total*
|
||||
if (planNet == null && planGross == null && planVol == null && planArea == null) {
|
||||
overwriteTotalWithPendingForPdaWeightDisplayRecursively(d.getChildren(), planWeightMetrics);
|
||||
overwriteTotalWithPendingForPdaWeightDisplayRecursively(d.getChildren(), planWeightMetrics, nextPlanParent);
|
||||
continue;
|
||||
}
|
||||
|
||||
// 兜底:待上架(1/2) 且已上架数量为 0 时,
|
||||
// DB 里的 total_* 可能被初始化为“计划值”,此时不应把它当作 already。
|
||||
// 按“数量为准”把 already 权重当 0,使 pending 展示为计划值。
|
||||
// level=2 时与收货一致:用主行累计数量判断是否已有上架实绩。
|
||||
BigDecimal alreadyShelvesQty = d.getAlreadyShelvesQuantity() != null ? d.getAlreadyShelvesQuantity() : BigDecimal.ZERO;
|
||||
boolean hasAlreadyQty = alreadyShelvesQty.compareTo(BigDecimal.ZERO) > 0;
|
||||
if (planParent != null && d.getLevel() != null && d.getLevel() == 2) {
|
||||
BigDecimal pq = planParent.getAlreadyShelvesQuantity() != null ? planParent.getAlreadyShelvesQuantity() : BigDecimal.ZERO;
|
||||
hasAlreadyQty = pq.compareTo(BigDecimal.ZERO) > 0;
|
||||
}
|
||||
if (!hasAlreadyQty) {
|
||||
alreadyNet = BigDecimal.ZERO;
|
||||
alreadyGross = BigDecimal.ZERO;
|
||||
@@ -624,7 +1144,7 @@ public class StockShelfOrderApplicationService {
|
||||
d.setTotalArea(calcPendingMetric(planArea, alreadyArea));
|
||||
}
|
||||
|
||||
overwriteTotalWithPendingForPdaWeightDisplayRecursively(d.getChildren(), planWeightMetrics);
|
||||
overwriteTotalWithPendingForPdaWeightDisplayRecursively(d.getChildren(), planWeightMetrics, nextPlanParent);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -743,6 +1263,15 @@ public class StockShelfOrderApplicationService {
|
||||
public Boolean upShelfByApp(StockShelfOrderDO stockReceiptOrderDO){
|
||||
// 标记 PDA:权重/数量都按“累计”语义处理(与收货保持一致)
|
||||
stockReceiptOrderDO.setFromApp(Boolean.TRUE);
|
||||
StockShelfOrderPO dbOrder = stockShelfOrderDomainService.getInfo(stockReceiptOrderDO.getShelfOrderId());
|
||||
if (dbOrder == null) {
|
||||
throw new ServiceException("上架单不存在");
|
||||
}
|
||||
ShelfMaterialDetailDO queryAll = new ShelfMaterialDetailDO();
|
||||
queryAll.setShelfOrderNumber(dbOrder.getShelfOrderNumber());
|
||||
List<ShelfMaterialDetailPO> dbListAll = shelfMaterialDetailDomainService.queryList(queryAll);
|
||||
preserveParentShelfLineHierarchyFromDb(stockReceiptOrderDO, dbListAll);
|
||||
|
||||
List<ShelfMaterialDetailDO> shelfMaterialDetailDOList = stockReceiptOrderDO.getMaterialDetailList();
|
||||
boolean firstItemHadChildrenBefore = !CollectionUtils.isEmpty(shelfMaterialDetailDOList)
|
||||
&& !CollectionUtils.isEmpty(shelfMaterialDetailDOList.get(0).getChildren());
|
||||
@@ -764,7 +1293,7 @@ public class StockShelfOrderApplicationService {
|
||||
shelfMaterialDetailDO.setStorageSectionId(firstChild.getStorageSectionId());
|
||||
shelfMaterialDetailDO.setStorageLocationId(firstChild.getStorageLocationId());
|
||||
shelfMaterialDetailDO.setContainerId(firstChild.getContainerId());
|
||||
shelfMaterialDetailDO.setLevel(firstChild.getLevel());
|
||||
// 不把子行 level 复制到主项;assembleParamByShelf 会以库表主行 level 为准
|
||||
shelfMaterialDetailDO.setMaterialDetailSerialNumberList(firstChild.getMaterialDetailSerialNumberList());
|
||||
// 保留其余子项(从索引1开始),统一设为 level 2
|
||||
List<ShelfMaterialDetailDO> restChildren = new ArrayList<>();
|
||||
@@ -777,6 +1306,30 @@ public class StockShelfOrderApplicationService {
|
||||
}
|
||||
});
|
||||
}
|
||||
// 与收货 receivingGoodsByApp 一致:assign 后按库表剥离 UI 镜像/已落库展示子行,必要时合成新的 level=2 承接本次量,避免多次提交仍写主行(对齐 injectPdaFlatReceiptAsSyntheticChild)
|
||||
boolean skipInjectAfterAssign = firstItemHadChildrenBefore
|
||||
&& !CollectionUtils.isEmpty(stockReceiptOrderDO.getMaterialDetailList())
|
||||
&& !CollectionUtils.isEmpty(stockReceiptOrderDO.getMaterialDetailList().get(0).getChildren());
|
||||
Map<Long, ShelfMaterialDetailPO> dbByIdForInject = dbListAll.stream()
|
||||
.filter(x -> x.getMaterialDetailId() != null)
|
||||
.collect(Collectors.toMap(ShelfMaterialDetailPO::getMaterialDetailId, Function.identity(), (a, b) -> a));
|
||||
Map<Long, ShelfMaterialDetailPO> dbByUidForInject = dbListAll.stream()
|
||||
.filter(x -> x.getUniqueId() != null)
|
||||
.collect(Collectors.toMap(ShelfMaterialDetailPO::getUniqueId, Function.identity(), (a, b) -> a));
|
||||
int injectIdx = 0;
|
||||
for (ShelfMaterialDetailDO line : stockReceiptOrderDO.getMaterialDetailList()) {
|
||||
ShelfMaterialDetailPO dbLine = null;
|
||||
if (line.getMaterialDetailId() != null) {
|
||||
dbLine = dbByIdForInject.get(line.getMaterialDetailId());
|
||||
}
|
||||
if (dbLine == null && line.getUniqueId() != null) {
|
||||
dbLine = dbByUidForInject.get(line.getUniqueId());
|
||||
}
|
||||
if (dbLine != null && !(skipInjectAfterAssign && injectIdx == 0)) {
|
||||
injectPdaFlatShelfAsSyntheticChild(line, dbLine, dbListAll);
|
||||
}
|
||||
injectIdx++;
|
||||
}
|
||||
//上架装配参数
|
||||
StockShelfOrderDO assembleStockShelfOrderDO = assembleParamByShelf(stockReceiptOrderDO);
|
||||
assembleStockShelfOrderDO.setFromApp(Boolean.TRUE);
|
||||
@@ -1019,6 +1572,29 @@ public class StockShelfOrderApplicationService {
|
||||
if (shelfMaterialDetailPO == null){
|
||||
throw new ServiceException("物料明细不存在");
|
||||
}
|
||||
// PDA 注入虚拟子行时:净重毛重体积面积只落在子行,主计划行不再把本次增量再累加一遍。
|
||||
// upShelfByApp 中 injectPdaFlatShelfAsSyntheticChild 会先写入 children 再进入本方法,需用标志位与下面「无 children」虚拟子行等价处理。
|
||||
boolean injectedVirtualShelfChild = Boolean.TRUE.equals(shelfMaterialDetailDO.getPdaShelfSyntheticChildInjected());
|
||||
// PDA 常只传主行 materialDetailId、本次数量在 shelvesQuantity,不带 children:第二次起会走主行 UPDATE。
|
||||
// 与带子项时一致:计划主行(level=1)且已有上架实绩时,用虚拟子项承接本次量,主行本次数量置 0,子循环走 INSERT 新行。
|
||||
if (!injectedVirtualShelfChild && fromApp && CollectionUtils.isEmpty(shelfMaterialDetailDO.getChildren())) {
|
||||
BigDecimal parentSqRaw = shelfMaterialDetailDO.getShelvesQuantity() == null ? BigDecimal.ZERO : shelfMaterialDetailDO.getShelvesQuantity();
|
||||
BigDecimal dbAlreadyMain = shelfMaterialDetailPO.getAlreadyShelvesQuantity() != null
|
||||
? shelfMaterialDetailPO.getAlreadyShelvesQuantity() : BigDecimal.ZERO;
|
||||
if (shelfMaterialDetailPO.getLevel() != null && shelfMaterialDetailPO.getLevel() == 1
|
||||
&& dbAlreadyMain.compareTo(BigDecimal.ZERO) > 0
|
||||
&& parentSqRaw.compareTo(BigDecimal.ZERO) > 0) {
|
||||
ShelfMaterialDetailDO virtualChild = new ShelfMaterialDetailDO();
|
||||
BeanUtils.copyProperties(shelfMaterialDetailDO, virtualChild);
|
||||
virtualChild.setMaterialDetailId(null);
|
||||
virtualChild.setUniqueId(null);
|
||||
shelfMaterialDetailDO.setChildren(Collections.singletonList(virtualChild));
|
||||
shelfMaterialDetailDO.setShelvesQuantity(BigDecimal.ZERO);
|
||||
injectedVirtualShelfChild = true;
|
||||
// 请求主行仍带本次扫描库位;末尾 copy 到 return 时会覆盖库表主行。子行已承载新库位,主行保留库表原库位。
|
||||
restorePlanLineStorageFromDb(shelfMaterialDetailDO, shelfMaterialDetailPO);
|
||||
}
|
||||
}
|
||||
List<ShelfMaterialDetailDO> children = shelfMaterialDetailDO.getChildren();
|
||||
BigDecimal childrenShelvesQuantitySum = BigDecimal.ZERO;
|
||||
if (!CollectionUtils.isEmpty(children)) {
|
||||
@@ -1033,6 +1609,15 @@ public class StockShelfOrderApplicationService {
|
||||
//未进行上架直接跳过
|
||||
continue;
|
||||
}
|
||||
// PDA:本次上架量只在子行、主行 shelvesQuantity=0 时,upShelfByApp 会把「第一个子行」的仓库/库位回填到主行 DO(见首子赋值逻辑),assemble 末尾再 merge 到 return,会把本次库位写回库表主行覆盖原库位。
|
||||
// 与虚拟子行分支里的 restorePlanLineStorageFromDb 一致:主行恢复为库表值;库表主行尚无库位时不恢复,以免清空后无法走下方 setStorageLocationInfo。
|
||||
if (fromApp && !CollectionUtils.isEmpty(shelfMaterialDetailDO.getChildren())
|
||||
&& shelvesQuantity.compareTo(BigDecimal.ZERO) == 0) {
|
||||
Long dbMainLocId = shelfMaterialDetailPO.getStorageLocationId();
|
||||
if (dbMainLocId != null && dbMainLocId != 0L) {
|
||||
restorePlanLineStorageFromDb(shelfMaterialDetailDO, shelfMaterialDetailPO);
|
||||
}
|
||||
}
|
||||
BigDecimal mainItemActualQuantity = shelvesQuantity;//主项本次上架数(不含子项)
|
||||
BigDecimal childrenActualQuantity = BigDecimal.ZERO;//子项本次上架总数
|
||||
// PDA 权重/体积/面积:记录“本次增量”
|
||||
@@ -1079,6 +1664,19 @@ public class StockShelfOrderApplicationService {
|
||||
}
|
||||
}
|
||||
BigDecimal childShelvesQty = shelfMaterialDetailDOChild.getShelvesQuantity() != null ? shelfMaterialDetailDOChild.getShelvesQuantity() : BigDecimal.ZERO;
|
||||
// PDA:计划主行(level=1)或已落库的子行(level=2)上已有上架实绩时,再次携带同一 materialDetailId 提交应与「收货」分拆一致:INSERT 新子行(level=2),不在同一行上累加覆盖;否则会 UPDATE 旧子行导致“第二次上架盖住第一次”。
|
||||
if (fromApp && shelfMaterialDetailPOChildDb != null) {
|
||||
Integer dbPlanLevel = shelfMaterialDetailPOChildDb.getLevel();
|
||||
BigDecimal dbAlreadyShelved = shelfMaterialDetailPOChildDb.getAlreadyShelvesQuantity() != null
|
||||
? shelfMaterialDetailPOChildDb.getAlreadyShelvesQuantity() : BigDecimal.ZERO;
|
||||
boolean lineHasShelvedHistory = Integer.valueOf(1).equals(dbPlanLevel)
|
||||
|| Integer.valueOf(2).equals(dbPlanLevel);
|
||||
if (lineHasShelvedHistory
|
||||
&& dbAlreadyShelved.compareTo(BigDecimal.ZERO) > 0
|
||||
&& childShelvesQty.compareTo(BigDecimal.ZERO) > 0) {
|
||||
shelfMaterialDetailPOChildDb = null;
|
||||
}
|
||||
}
|
||||
if (fromApp) {
|
||||
// 子项未上架数量时,不累加重量增量
|
||||
BigDecimal childNetInc = childShelvesQty.compareTo(BigDecimal.ZERO) > 0
|
||||
@@ -1180,7 +1778,9 @@ public class StockShelfOrderApplicationService {
|
||||
}
|
||||
setStorageLocationInfo(returnShelfMaterialDetailDOChild);
|
||||
returnShelfMaterialDetailDOChild.setAllowModify(2);
|
||||
returnShelfMaterialDetailDOChild.setLevel(2);
|
||||
// 库表已存在的行:保留其 level(计划主行=1、分批子行=2)。不可一律写 2,否则 PDA 把计划行 id 放在 children 里时会误把主行改成子行。
|
||||
Integer dbChildLevel = shelfMaterialDetailPOChildDb.getLevel();
|
||||
returnShelfMaterialDetailDOChild.setLevel(dbChildLevel != null ? dbChildLevel : 2);
|
||||
returnShelfMaterialDetailDOChild.setParentUniqueId(shelfMaterialDetailPO.getUniqueId());
|
||||
// 子项不维护独立计划数量,计划量仅由主项承载
|
||||
returnShelfMaterialDetailDOChild.setQuantity(null);
|
||||
@@ -1192,6 +1792,8 @@ public class StockShelfOrderApplicationService {
|
||||
BeanUtils.copyProperties(shelfMaterialDetailPO, returnShelfMaterialDetailDOChild, "materialDetailId","createBy","createByName","createTime",
|
||||
"updateBy","updateByName","updateTime");
|
||||
BeanUtils.copyProperties(shelfMaterialDetailDOChild, returnShelfMaterialDetailDOChild, IgnoreNullUtil.getNullPropertyNames(shelfMaterialDetailDOChild));
|
||||
// 新子行必须 INSERT;请求里若仍带上一笔子行的 materialDetailId,上面会把本段误判为 UPDATE
|
||||
returnShelfMaterialDetailDOChild.setMaterialDetailId(null);
|
||||
if (fromApp) {
|
||||
// 子项不存在:new already = 0 + 本次增量(并不超过计划)
|
||||
WeightMetrics childPlan = shelfMaterialDetailDOChild.getInUniqueId() != null
|
||||
@@ -1253,6 +1855,30 @@ public class StockShelfOrderApplicationService {
|
||||
childrenActualQuantity = childrenActualQuantity.add(returnShelfMaterialDetailDOChild.getShelvesQuantity());
|
||||
}
|
||||
}
|
||||
// PDA 分批上架:子行已承载本次量时,主行平面 shelvesQuantity 不应再计入主项累计(与 inject 成功后主行=0 一致)。
|
||||
// inject 因 UI 仍带 children 等提前 return 时,主行与子行会双计,此处兜底。
|
||||
boolean pdaSplitChildCarriesThisShelf = false;
|
||||
if (fromApp && shouldPdaSplitIntoShelfChildRow(shelfMaterialDetailPO, shelfMaterialDetailPODbList)
|
||||
&& !CollectionUtils.isEmpty(shelfMaterialDetailDOChildList)) {
|
||||
boolean anyChildPositiveQty = false;
|
||||
for (ShelfMaterialDetailDO ch : shelfMaterialDetailDOChildList) {
|
||||
if (ch != null && ch.getShelvesQuantity() != null
|
||||
&& ch.getShelvesQuantity().compareTo(BigDecimal.ZERO) > 0) {
|
||||
anyChildPositiveQty = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (anyChildPositiveQty && shelfMaterialDetailPO.getLevel() != null
|
||||
&& shelfMaterialDetailPO.getLevel() == 1) {
|
||||
mainItemActualQuantity = BigDecimal.ZERO;
|
||||
pdaSplitChildCarriesThisShelf = true;
|
||||
// inject 未把主行 shelvesQuantity 置 0 时,上面「shelvesQuantity==0 才 restore」分支不执行,主行 DO 仍带本次子行库位,merge 会覆盖库表主项库位;与子行兜底双计一致,此处恢复计划主行库位。
|
||||
Long dbMainLocId = shelfMaterialDetailPO.getStorageLocationId();
|
||||
if (dbMainLocId != null && dbMainLocId != 0L) {
|
||||
restorePlanLineStorageFromDb(shelfMaterialDetailDO, shelfMaterialDetailPO);
|
||||
}
|
||||
}
|
||||
}
|
||||
BigDecimal dbParentAlready = shelfMaterialDetailPO.getAlreadyShelvesQuantity() != null
|
||||
? shelfMaterialDetailPO.getAlreadyShelvesQuantity() : BigDecimal.ZERO;
|
||||
// PC:already_shelves_quantity 使用本次上架量;PDA 保持累计口径
|
||||
@@ -1280,10 +1906,22 @@ public class StockShelfOrderApplicationService {
|
||||
? shelfMaterialDetailPO.getTotalArea()
|
||||
: BigDecimal.ZERO;
|
||||
|
||||
BigDecimal newAlreadyNet = oldAlreadyNet.add(netIncrement);
|
||||
BigDecimal newAlreadyGross = oldAlreadyGross.add(grossIncrement);
|
||||
BigDecimal newAlreadyVol = oldAlreadyVol.add(volIncrement);
|
||||
BigDecimal newAlreadyArea = oldAlreadyArea.add(areaIncrement);
|
||||
BigDecimal newAlreadyNet;
|
||||
BigDecimal newAlreadyGross;
|
||||
BigDecimal newAlreadyVol;
|
||||
BigDecimal newAlreadyArea;
|
||||
if (injectedVirtualShelfChild || pdaSplitChildCarriesThisShelf) {
|
||||
// 与分拆子行一致:本次 total_* 增量只落在子行;主行保持库表累计不变(否则 netIncrement 已由子循环写入子行,父行再 old+net 会双计)。
|
||||
newAlreadyNet = oldAlreadyNet;
|
||||
newAlreadyGross = oldAlreadyGross;
|
||||
newAlreadyVol = oldAlreadyVol;
|
||||
newAlreadyArea = oldAlreadyArea;
|
||||
} else {
|
||||
newAlreadyNet = oldAlreadyNet.add(netIncrement);
|
||||
newAlreadyGross = oldAlreadyGross.add(grossIncrement);
|
||||
newAlreadyVol = oldAlreadyVol.add(volIncrement);
|
||||
newAlreadyArea = oldAlreadyArea.add(areaIncrement);
|
||||
}
|
||||
|
||||
WeightMetrics plan = shelfMaterialDetailPO.getInUniqueId() != null
|
||||
? planWeightMetrics.get(shelfMaterialDetailPO.getReceiptUniqueId() != null
|
||||
@@ -1334,6 +1972,8 @@ public class StockShelfOrderApplicationService {
|
||||
ShelfMaterialDetailDO returnShelfMaterialDetailDO = new ShelfMaterialDetailDO();
|
||||
BeanUtils.copyProperties(shelfMaterialDetailPO, returnShelfMaterialDetailDO);
|
||||
BeanUtils.copyProperties(shelfMaterialDetailDO, returnShelfMaterialDetailDO, IgnoreNullUtil.getNullPropertyNames(shelfMaterialDetailDO));
|
||||
// 主行 level 以库表为准,避免 upShelfByApp 等路径把 firstChild.level 合到主项后覆盖为 2
|
||||
returnShelfMaterialDetailDO.setLevel(shelfMaterialDetailPO.getLevel());
|
||||
if (shelfMaterialDetailPO.getShelvesStatus() == 1){
|
||||
//首次上架
|
||||
//是否开启了序列号管理
|
||||
@@ -1355,6 +1995,109 @@ public class StockShelfOrderApplicationService {
|
||||
return returnStockShelfOrderDO;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将计划主行上的仓库/库区/库位/容器恢复为库表现值,避免 PDA 二次上架时把「本次子行库位」写回主行。
|
||||
*/
|
||||
private void restorePlanLineStorageFromDb(ShelfMaterialDetailDO parentDo, ShelfMaterialDetailPO dbPo) {
|
||||
if (parentDo == null || dbPo == null) {
|
||||
return;
|
||||
}
|
||||
parentDo.setWarehouseId(dbPo.getWarehouseId());
|
||||
parentDo.setWarehouseCode(dbPo.getWarehouseCode());
|
||||
parentDo.setWarehouseName(dbPo.getWarehouseName());
|
||||
parentDo.setStorageSectionId(dbPo.getStorageSectionId());
|
||||
parentDo.setStorageCode(dbPo.getStorageCode());
|
||||
parentDo.setStorageName(dbPo.getStorageName());
|
||||
parentDo.setStorageLocationId(dbPo.getStorageLocationId());
|
||||
parentDo.setStorageLocationCode(dbPo.getStorageLocationCode());
|
||||
parentDo.setStorageLocationName(dbPo.getStorageLocationName());
|
||||
parentDo.setContainerId(dbPo.getContainerId());
|
||||
parentDo.setContainerCode(dbPo.getContainerCode());
|
||||
parentDo.setContainerType(dbPo.getContainerType());
|
||||
parentDo.setContainerTypeName(dbPo.getContainerTypeName());
|
||||
}
|
||||
|
||||
/**
|
||||
* 请求行与库主计划行 level 不一致时纠正,避免误当子行(对齐收货 preserveParentReceiptLineHierarchyFromDb)。
|
||||
*/
|
||||
private void preserveParentShelfLineHierarchyFromDb(StockShelfOrderDO order, List<ShelfMaterialDetailPO> dbList) {
|
||||
if (order == null || CollectionUtils.isEmpty(order.getMaterialDetailList()) || CollectionUtils.isEmpty(dbList)) {
|
||||
return;
|
||||
}
|
||||
Map<Long, ShelfMaterialDetailPO> byId = dbList.stream()
|
||||
.filter(x -> x.getMaterialDetailId() != null)
|
||||
.collect(Collectors.toMap(ShelfMaterialDetailPO::getMaterialDetailId, Function.identity(), (a, b) -> a));
|
||||
Map<Long, ShelfMaterialDetailPO> byUid = dbList.stream()
|
||||
.filter(x -> x.getUniqueId() != null)
|
||||
.collect(Collectors.toMap(ShelfMaterialDetailPO::getUniqueId, Function.identity(), (a, b) -> a));
|
||||
for (ShelfMaterialDetailDO line : order.getMaterialDetailList()) {
|
||||
ShelfMaterialDetailPO db = null;
|
||||
if (line.getMaterialDetailId() != null) {
|
||||
db = byId.get(line.getMaterialDetailId());
|
||||
}
|
||||
if (db == null && line.getUniqueId() != null) {
|
||||
db = byUid.get(line.getUniqueId());
|
||||
}
|
||||
if (db != null && db.getLevel() != null && db.getLevel() == 1
|
||||
&& line.getLevel() != null && line.getLevel() == 2) {
|
||||
line.setLevel(1);
|
||||
line.setParentUniqueId(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* PDA 单次传主行平面(无真实子结构需拆时):与收货 {@code injectPdaFlatReceiptAsSyntheticChild} 对齐——
|
||||
* 去掉 UI 镜像行与已落库展示子行后,将本次上架数量与 total* 指标挪到新建 level=2 子行,主行清零并恢复库表库位,避免第 2、3 次仍累加到主项、覆盖主行库位。
|
||||
*/
|
||||
private void injectPdaFlatShelfAsSyntheticChild(ShelfMaterialDetailDO line, ShelfMaterialDetailPO dbLine,
|
||||
List<ShelfMaterialDetailPO> allDbLines) {
|
||||
if (line == null || dbLine == null) {
|
||||
return;
|
||||
}
|
||||
stripPdaUiParentCopyChildrenShelf(line, dbLine);
|
||||
stripPdaExistingDisplayedChildrenForResplitShelf(line, dbLine, allDbLines);
|
||||
if (dbLine.getLevel() != null && dbLine.getLevel() == 2 && !isCorruptedStandaloneLineAsLevel2Shelf(dbLine)) {
|
||||
return;
|
||||
}
|
||||
if (!CollectionUtils.isEmpty(line.getChildren())) {
|
||||
return;
|
||||
}
|
||||
if (!shouldPdaSplitIntoShelfChildRow(dbLine, allDbLines) && !isCorruptedStandaloneLineAsLevel2Shelf(dbLine)) {
|
||||
return;
|
||||
}
|
||||
BigDecimal sq = line.getShelvesQuantity();
|
||||
boolean hasQty = sq != null && sq.compareTo(BigDecimal.ZERO) > 0;
|
||||
boolean hasMetricBatch = hasPdaShelfMetricIncrement(line, dbLine);
|
||||
if (!hasQty && !hasMetricBatch) {
|
||||
return;
|
||||
}
|
||||
ShelfMaterialDetailDO child = new ShelfMaterialDetailDO();
|
||||
BeanUtils.copyProperties(line, child, "children", "materialDetailId", "uniqueId", "level", "parentUniqueId");
|
||||
child.setUniqueId(idGenerator.snowflakeId(SnowFlakeConstants.wmsId));
|
||||
child.setChildren(null);
|
||||
child.setLevel(2);
|
||||
child.setParentUniqueId(resolveParentUniqueIdForPdaInjectChildShelf(dbLine, allDbLines));
|
||||
if (hasQty) {
|
||||
child.setShelvesQuantity(sq);
|
||||
}
|
||||
child.setTotalNetWeight(line.getTotalNetWeight());
|
||||
child.setTotalGrossWeight(line.getTotalGrossWeight());
|
||||
child.setTotalVolume(line.getTotalVolume());
|
||||
child.setTotalArea(line.getTotalArea());
|
||||
child.setAlreadyShelvesQuantity(null);
|
||||
line.setChildren(Collections.singletonList(child));
|
||||
line.setShelvesQuantity(BigDecimal.ZERO);
|
||||
line.setTotalNetWeight(null);
|
||||
line.setTotalGrossWeight(null);
|
||||
line.setTotalVolume(null);
|
||||
line.setTotalArea(null);
|
||||
line.setLevel(1);
|
||||
line.setParentUniqueId(null);
|
||||
restorePlanLineStorageFromDb(line, dbLine);
|
||||
line.setPdaShelfSyntheticChildInjected(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @description 设置上架库位信息
|
||||
* @author ZhouGY
|
||||
|
||||
+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();
|
||||
|
||||
+3
-1
@@ -172,4 +172,6 @@ public class HandoverTaskOrderDTO extends BaseVOEntity {
|
||||
|
||||
@ApiModelProperty("app上传的图片")
|
||||
private String pictureApp;
|
||||
}
|
||||
|
||||
private String billingJson;
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package com.mhd.wms.interfaces.dto.stockInOrder;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.mhd.common.core.annotation.Excel;
|
||||
import com.mhd.wms.domain.receiptOrderAccount.entity.ReceiptOrderAccount;
|
||||
import com.mhd.wms.interfaces.dto.inMaterialDetail.InMaterialDetailDTO;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
@@ -376,4 +377,15 @@ public class StockInOrderDTO extends StockInOrderBaseDTO {
|
||||
|
||||
@ApiModelProperty("入库明细-物料编码,模糊匹配,与前端参数 materialCode 一致")
|
||||
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;
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package com.mhd.wms.interfaces.dto.stockOutOrder;
|
||||
import com.fasterxml.jackson.annotation.JsonAlias;
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.mhd.common.core.annotation.Excel;
|
||||
import com.mhd.wms.domain.receiptOrderAccount.entity.ReceiptOrderAccount;
|
||||
import com.mhd.wms.interfaces.dto.outMaterialDetail.OutMaterialDetailDTO;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
@@ -430,4 +431,14 @@ public class StockOutOrderDTO extends StockOutOrderBaseDTO {
|
||||
@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
@@ -156,4 +156,7 @@ public class StockReceiptOrderDTO extends StockInOrderBaseDTO {
|
||||
|
||||
@ApiModelProperty("费用")
|
||||
List<ReceiptOrderAccount> receiptOrderAccountList;
|
||||
|
||||
@ApiModelProperty(name = "费用参数json")
|
||||
private String billingJson;
|
||||
}
|
||||
+27
@@ -10,8 +10,11 @@ import com.mhd.wms.domain.inMaterialDetail.entity.InMaterialDetail;
|
||||
import com.mhd.wms.domain.stockInOrder.entity.StockInOrder;
|
||||
import com.mhd.wms.domain.stockInOrder.repository.po.StockInOrderPO;
|
||||
import com.mhd.wms.domain.stockInOrder.repository.todo.StockInOrderDO;
|
||||
import com.mhd.wms.domain.stockOutOrder.repository.todo.StockOutOrderDO;
|
||||
import com.mhd.wms.interfaces.assember.stockInOrder.StockInOrderAssembler;
|
||||
import com.mhd.wms.interfaces.assember.stockOutOrder.StockOutOrderAssembler;
|
||||
import com.mhd.wms.interfaces.dto.stockInOrder.StockInOrderDTO;
|
||||
import com.mhd.wms.interfaces.dto.stockOutOrder.StockOutOrderDTO;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
@@ -34,6 +37,8 @@ public class StockInOrderApi extends BaseController {
|
||||
|
||||
@Resource
|
||||
private StockInOrderAssembler stockInOrderAssembler;
|
||||
@Resource
|
||||
private StockOutOrderAssembler stockOutOrderAssembler;
|
||||
|
||||
/**
|
||||
* 分页查询入库单列表
|
||||
@@ -65,6 +70,28 @@ public class StockInOrderApi extends BaseController {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑入库单
|
||||
*/
|
||||
@ApiOperation("编辑入库单")
|
||||
@PostMapping("/saveAmount")
|
||||
public AjaxResult saveAmount(@RequestBody StockInOrderDTO stockInOrderDTO)
|
||||
{
|
||||
StockInOrderDO stockInOrderDO = stockInOrderAssembler.toDO(stockInOrderDTO);
|
||||
return toAjax(stockInOrderApplicationService.saveAmount(stockInOrderDO));
|
||||
}
|
||||
|
||||
/**
|
||||
* 编辑入库单
|
||||
*/
|
||||
@ApiOperation("编辑入库单")
|
||||
@PostMapping("/saveOutAmount")
|
||||
public AjaxResult saveOutAmount(@RequestBody StockOutOrderDTO stockOutOrderDTO)
|
||||
{
|
||||
StockOutOrderDO stockOutOrderDO = stockOutOrderAssembler.toDO(stockOutOrderDTO);
|
||||
return toAjax(stockInOrderApplicationService.saveOutAmount(stockOutOrderDO));
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除入库单
|
||||
*/
|
||||
|
||||
+9
-1
@@ -98,6 +98,14 @@ public class StockReceiptOrderApi extends BaseController {
|
||||
return toAjax(stockReceiptOrderApplicationService.completeReceipt(receiptOrderId));
|
||||
}
|
||||
|
||||
@ApiOperation("完成收货")
|
||||
@PostMapping("/completeReceiptAndUpdateJson")
|
||||
public AjaxResult completeReceipt(@RequestBody StockReceiptOrderDTO stockReceiptOrderDTO) {
|
||||
Long receiptOrderId = stockReceiptOrderDTO.getReceiptOrderId();
|
||||
stockReceiptOrderApplicationService.updateInOrder(stockReceiptOrderDTO);
|
||||
return toAjax(stockReceiptOrderApplicationService.completeReceipt(receiptOrderId));
|
||||
}
|
||||
|
||||
@ApiOperation("整单收货")
|
||||
@GetMapping("/entireReceipt/{receiptOrderIds}")
|
||||
public AjaxResult entireReceipt(@PathVariable("receiptOrderIds") Long[] receiptOrderIds) {
|
||||
@@ -111,4 +119,4 @@ public class StockReceiptOrderApi extends BaseController {
|
||||
return AjaxResult.success(list);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+6
-4
@@ -64,13 +64,14 @@ public class StockReceiptOrderAppApi extends BaseController {
|
||||
}
|
||||
|
||||
/**
|
||||
* PDA:查询当前卡片(计划行)下全部分批收货子行(level=2,库表真实子行,无 parent_copy)
|
||||
* PDA:查询某计划行(卡片)下所有 level=2 分批收货子行(含首笔仅落主行时的主行快照),附带序列号。
|
||||
*/
|
||||
@ApiOperation("查询指定收货明细下的分批子行列表(level=2)")
|
||||
@ApiOperation("按父计划行查询分批收货子行(level=2)")
|
||||
@GetMapping("/listLevel2ChildrenByParent")
|
||||
public AjaxResult listLevel2ChildrenByParent(
|
||||
@ApiParam(value = "收货单ID", required = true) @RequestParam Long receiptOrderId,
|
||||
@ApiParam(value = "卡片对应明细主键 material_detail_id", required = true) @RequestParam Long materialDetailId) {
|
||||
@ApiParam(value = "收货明细 material_detail_id(计划行或子行均可,会解析到计划父行)", required = true)
|
||||
@RequestParam Long materialDetailId) {
|
||||
List<ReceiptMaterialDetailPO> list = stockReceiptOrderApplicationService.listLevel2ChildrenByParentForApp(
|
||||
receiptOrderId, materialDetailId);
|
||||
return AjaxResult.success(list);
|
||||
@@ -93,6 +94,7 @@ public class StockReceiptOrderAppApi extends BaseController {
|
||||
@ApiOperation("完成收货")
|
||||
@PostMapping("/completeReceipt")
|
||||
public AjaxResult completeReceipt(@RequestBody StockReceiptOrderDTO stockReceiptOrderDTO) {
|
||||
stockReceiptOrderApplicationService.updateInOrder(stockReceiptOrderDTO);
|
||||
return toAjax(stockReceiptOrderApplicationService.completeReceiptByApp(stockReceiptOrderDTO.getReceiptOrderId()));
|
||||
}
|
||||
|
||||
@@ -112,4 +114,4 @@ public class StockReceiptOrderAppApi extends BaseController {
|
||||
return toAjax(stockReceiptOrderApplicationService.noOrderReceipt(stockReceiptOrderDO));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
+16
-1
@@ -5,11 +5,13 @@ import com.mhd.common.core.web.domain.AjaxResult;
|
||||
import com.mhd.common.core.web.page.TableDataInfoApi;
|
||||
import com.mhd.common.security.utils.SecurityUtils;
|
||||
import com.mhd.wms.application.service.stockShelfOrder.StockShelfOrderApplicationService;
|
||||
import com.mhd.wms.domain.shelfMaterialDetail.repository.po.ShelfMaterialDetailPO;
|
||||
import com.mhd.wms.domain.stockShelfOrder.repository.po.StockShelfOrderPO;
|
||||
import com.mhd.wms.domain.stockShelfOrder.repository.todo.StockShelfOrderDO;
|
||||
import com.mhd.wms.interfaces.assember.stockShelfOrder.StockShelfOrderAssembler;
|
||||
import com.mhd.wms.interfaces.dto.stockShelfOrder.StockShelfOrderDTO;
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import io.swagger.annotations.ApiParam;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
@@ -47,7 +49,7 @@ public class StockShelfOrderAppApi extends BaseController {
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取上架单详细信息(PDA:主项无子项时添加 parent_copy,供详情页从 children 读取数据)
|
||||
* 获取上架单详细信息(PDA:与收货 getInfoByApp 一致保留父子结构;子行计划数量在服务端清空,见 StockShelfOrderApplicationService#getInfo)
|
||||
*/
|
||||
@ApiOperation("获取上架单")
|
||||
@GetMapping(value = "/getInfo")
|
||||
@@ -58,6 +60,19 @@ public class StockShelfOrderAppApi extends BaseController {
|
||||
return AjaxResult.success(stockShelfOrderApplicationService.getInfo(shelfOrderId, true, shelfStatus));
|
||||
}
|
||||
|
||||
/**
|
||||
* PDA:查询某计划行(卡片)下所有 level=2 分批上架子行(含首笔仅落主行时的主行快照),附带序列号。
|
||||
*/
|
||||
@ApiOperation("按父计划行查询分批上架子行(level=2)")
|
||||
@GetMapping("/listLevel2ChildrenByParent")
|
||||
public AjaxResult listLevel2ChildrenByParent(
|
||||
@ApiParam(value = "上架单ID", required = true) @RequestParam Long shelfOrderId,
|
||||
@ApiParam(value = "上架明细 material_detail_id(计划行或子行均可,会解析到计划父行)", required = true)
|
||||
@RequestParam Long materialDetailId) {
|
||||
List<ShelfMaterialDetailPO> list = stockShelfOrderApplicationService.listLevel2ChildrenByParentForApp(
|
||||
shelfOrderId, materialDetailId);
|
||||
return AjaxResult.success(list);
|
||||
}
|
||||
|
||||
@ApiOperation("上架")
|
||||
@PostMapping("/upShelf")
|
||||
|
||||
@@ -14,24 +14,24 @@ spring:
|
||||
nacos:
|
||||
discovery:
|
||||
# server-addr: 127.0.0.1:8848
|
||||
server-addr: 10.33.0.129:6010
|
||||
# 线上测试环境配置 容器名+端口号
|
||||
# server-addr: 10.102.192.5:6848
|
||||
# username: nacos
|
||||
# password: manhuoda@2023
|
||||
#线上正式环境
|
||||
# server-addr: 10.102.192.105:6848
|
||||
# server-addr: 10.33.0.129:6010
|
||||
# 线上测试环境配置 容器名+端口号
|
||||
server-addr: 10.102.192.5:6848
|
||||
username: nacos
|
||||
password: manhuoda@2023
|
||||
#线上正式环境
|
||||
# server-addr: 10.102.192.105:6848
|
||||
config:
|
||||
# server-addr: 127.0.0.1:8848
|
||||
server-addr: 10.33.0.129:6010
|
||||
# server-addr: 10.33.0.129:6010
|
||||
# 线上测试环境配置 容器名+端口号
|
||||
# server-addr: 10.102.192.5:6848
|
||||
# username: nacos
|
||||
# password: manhuoda@2023
|
||||
server-addr: 10.102.192.5:6848
|
||||
username: nacos
|
||||
password: manhuoda@2023
|
||||
#线上正式环境
|
||||
# server-addr: 10.102.192.105:6848
|
||||
# 配置文件格式
|
||||
file-extension: yml
|
||||
# 共享配置
|
||||
shared-configs:
|
||||
- application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
|
||||
- application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension}
|
||||
|
||||
@@ -40,6 +40,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<result property="updateByName" column="update_by_name" />
|
||||
<result property="delFlag" column="del_flag" />
|
||||
<result property="pictureApp" column="picture_app" />
|
||||
<result property="billingJson" column="billing_json" />
|
||||
</resultMap>
|
||||
|
||||
|
||||
@@ -48,7 +49,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
a.platform_code, a.platform_name, a.platform_use_time_id, a.platform_use_start_time, a.platform_use_end_time, a.platform_use_status,
|
||||
a.order_type_code, a.order_type_name, a.expect_time, a.warehouse_id, a.warehouse_code, a.warehouse_name, a.shipper_id,
|
||||
a.shipper_name, a.order_number, a.picking_order_number, a.remark, a.task_distribution, a.task_distribution_time, a.create_time, a.create_by, a.create_by_name, a.update_time,
|
||||
a.update_by, a.update_by_name, a.del_flag, a.picture_app
|
||||
a.update_by, a.update_by_name, a.del_flag, a.picture_app,a.billing_json
|
||||
</sql>
|
||||
|
||||
<sql id="selectHandoverTaskOrderPo1">
|
||||
|
||||
@@ -81,8 +81,20 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<result property="completionTime" column="COMPLETION_TIME" />
|
||||
<result property="orderDate" column="ORDER_DATE" />
|
||||
<result property="batchNumber" column="BATCH_NUMBER" />
|
||||
<result property="billingJson" column="billing_json" />
|
||||
<result property="salesmanId" column="SALESMAN_ID" />
|
||||
<result property="salesmanName" column="SALESMAN_NAME" />
|
||||
<result property="settlementCurrency" column="SETTLEMENT_CURRENCY" />
|
||||
</resultMap>
|
||||
|
||||
|
||||
<sql id="selectStockInOrderPo">
|
||||
a.in_order_id, a.organization_id, a.organization_name, a.top_organization_id, a.notice_number, a.in_order_number, a.status,
|
||||
a.audit_status, a.audit_remark, a.audit_by, a.audit_by_name, a.audit_time, a.warehouse_id, a.warehouse_code, a.warehouse_name, a.shipper_id, a.shipper_code,
|
||||
a.shipper_name, a.order_type_code, a.order_type_name, a.supplier_id, a.supplier_code, a.supplier_name, a.expect_time, a.supply_chain_number,
|
||||
a.priority_level_code, a.priority_level_name, a.direct_warehouse, a.annex_url, a.material_quantity, a.quantity,a.billing_json,a.SETTLEMENT_CURRENCY,
|
||||
a.SALESMAN_ID,a.SALESMAN_NAME,
|
||||
-- 计划入库数量:入库明细表 in_material_detail 的 quantity 汇总
|
||||
<!-- 计划入库数量:入库明细主行 quantity 汇总(列表 quantity / plan_in_quantity 均以此为准展示) -->
|
||||
<sql id="sumPlanInMaterialQuantity">
|
||||
(select ifnull(sum(imd.quantity), 0)
|
||||
|
||||
@@ -82,6 +82,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<result property="needDeclareFlag" column="need_declare_flag"/>
|
||||
<result property="needTransportFlag" column="need_transport_flag"/>
|
||||
<result property="pictureApp" column="picture_app"/>
|
||||
<result property="billingJson" column="billing_json" />
|
||||
<result property="salesmanId" column="SALESMAN_ID" />
|
||||
<result property="salesmanName" column="SALESMAN_NAME" />
|
||||
<result property="settlementCurrency" column="SETTLEMENT_CURRENCY" />
|
||||
</resultMap>
|
||||
|
||||
|
||||
@@ -97,7 +101,8 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
a.CONTACT_PERSON,a.VEHICLE_MODEL_PLATE,a.ENTRUST_NO,a.TEL,a.DRIVER_SIGN,a.FAX,a.DECLARE_CUSTOMS,a.MANUFACTURER,
|
||||
a.CUSTOMS_DECLARER_INFO,a.DELIVERY_ADDR,a.ENTRY_EXIT_CUSTOMS,a.DEPARTURE_ARRIVAL_COUNTRY,a.CARRIER,a.CONTAINER_NO,a.CONTAINER_NO_NAME,a.OUTBOUND_DATE,
|
||||
a.COMPLETE_TIME,a.ORDER_DATE,a.TRANSPORT_MODE_CODE,a.TRANSPORT_MODE_NAME,a.SUPERVISION_MODE_CODE,a.SUPERVISION_MODE_NAME,
|
||||
a.CUSTOMS_INSPECTION_FLAG,a.NEED_DECLARE_FLAG,a.NEED_TRANSPORT_FLAG,a.picture_app
|
||||
a.CUSTOMS_INSPECTION_FLAG,a.NEED_DECLARE_FLAG,a.NEED_TRANSPORT_FLAG,a.picture_app,a.billing_json,a.SETTLEMENT_CURRENCY,
|
||||
a.SALESMAN_ID,a.SALESMAN_NAME
|
||||
</sql>
|
||||
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<result property="grossWeight" column="grossWeight"/>
|
||||
<result property="boxPalletNo" column="boxPalletNo"/>
|
||||
<result property="serialNumber" column="serial_number"/>
|
||||
<result property="billingJson" column="billing_json" />
|
||||
</resultMap>
|
||||
|
||||
|
||||
@@ -50,7 +51,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
a.status, a.platform_id, a.platform_code, a.platform_name, a.platform_use_time_id, a.platform_use_start_time, a.platform_use_end_time,
|
||||
a.platform_use_status, a.quantity, a.receipt_quantity, a.receipt_material_quantity, a.material_quantity, a.abnormal, a.task_distribution, a.task_distribution_time,
|
||||
a.operators_by, a.operators_name, a.remark, a.create_time, a.create_by, a.create_by_name,
|
||||
a.update_time, a.update_by, a.update_by_name, a.del_flag
|
||||
a.update_time, a.update_by, a.update_by_name, a.del_flag, a.billing_json
|
||||
</sql>
|
||||
|
||||
<sql id="selectStockReceiptOrderPo1">
|
||||
@@ -155,26 +156,4 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
</where>
|
||||
ORDER BY a.create_time DESC
|
||||
</select>
|
||||
|
||||
|
||||
<select id="queryPrintInfo" resultMap="StockReceiptOrderResult">
|
||||
SELECT
|
||||
a.batch_number,
|
||||
ifnull(a.material_code, c.material_code) AS material_code,
|
||||
c.copy_code,
|
||||
ifnull(a.total_net_weight, b.total_net_weight) AS netWeight,
|
||||
ifnull(a.total_gross_weight, b.total_gross_weight) AS grossWeight,
|
||||
ifnull(a.box_pallet_no, b.box_pallet_no) AS boxPalletNo,
|
||||
ims.serial_number
|
||||
FROM receipt_material_detail a
|
||||
LEFT JOIN stock_receipt_order sro ON a.receipt_order_number = sro.receipt_order_number AND sro.del_flag = 1
|
||||
LEFT JOIN in_material_detail b ON a.in_unique_id = b.unique_id AND b.del_flag = 1
|
||||
LEFT JOIN material_base_info c ON a.material_base_info_id = c.material_base_info_id AND c.del_flag = 1
|
||||
LEFT JOIN in_material_detail_serial_number ims ON a.material_detail_id = ims.material_detail_unique_id AND ims.del_flag = 1
|
||||
WHERE sro.receipt_order_number = #{receiptOrderNumber}
|
||||
AND a.del_flag = 1
|
||||
|
||||
</select>
|
||||
|
||||
|
||||
</mapper>
|
||||
Reference in New Issue
Block a user