Browse Source

&问题和体积计算问题

master
han\hanst 4 weeks ago
parent
commit
900b0b8a36
  1. 198
      src/main/java/com/xujie/sys/modules/ecss/service/impl/CoDelExcelServiceImpl.java

198
src/main/java/com/xujie/sys/modules/ecss/service/impl/CoDelExcelServiceImpl.java

@ -264,21 +264,21 @@ public class CoDelExcelServiceImpl implements CoDelExcelService {
String cnativeKey = "cnative_" + cmcInvoice;
String salesAreaKey = "salesArea_" + cmcInvoice;
// 从请求参数中获取按发票号设置的客户信息
String customerName = request.getParameter(customerNameKey);
String localShipAddress = request.getParameter(localShipAddressKey);
String overseasShipper = request.getParameter(overseasShipperKey);
String overseasAddress = request.getParameter(overseasAddressKey);
String cnative = request.getParameter(cnativeKey);
String salesArea = request.getParameter(salesAreaKey);
// 从请求参数中获取按发票号设置的客户信息并进行 HTML 反转义处理
String customerName = unescapeHtml(request.getParameter(customerNameKey));
String localShipAddress = unescapeHtml(request.getParameter(localShipAddressKey));
String overseasShipper = unescapeHtml(request.getParameter(overseasShipperKey));
String overseasAddress = unescapeHtml(request.getParameter(overseasAddressKey));
String cnative = unescapeHtml(request.getParameter(cnativeKey));
String salesArea = unescapeHtml(request.getParameter(salesAreaKey));
// 如果按发票号的信息不存在则使用全局信息
headerList.setCustomerName(customerName != null ? customerName : inData.getCustomerName());
headerList.setLocalShipAddress(localShipAddress != null ? localShipAddress : inData.getLocalShipAddress());
headerList.setOverseasShipper(overseasShipper != null ? overseasShipper : inData.getOverseasShipper());
headerList.setOverseasAddress(overseasAddress != null ? overseasAddress : inData.getOverseasAddress());
headerList.setCnative(cnative != null ? cnative : inData.getCnative());
headerList.setSalesArea(salesArea != null ? salesArea : inData.getSalesArea());
headerList.setCustomerName(customerName != null ? customerName : unescapeHtml(inData.getCustomerName()));
headerList.setLocalShipAddress(localShipAddress != null ? localShipAddress : unescapeHtml(inData.getLocalShipAddress()));
headerList.setOverseasShipper(overseasShipper != null ? overseasShipper : unescapeHtml(inData.getOverseasShipper()));
headerList.setOverseasAddress(overseasAddress != null ? overseasAddress : unescapeHtml(inData.getOverseasAddress()));
headerList.setCnative(cnative != null ? cnative : unescapeHtml(inData.getCnative()));
headerList.setSalesArea(salesArea != null ? salesArea : unescapeHtml(inData.getSalesArea()));
headerList.setCmcInvoice(cmcInvoice);
headerList.setCreateBy(inData.getUsername());
coDelMapper.saveEcssCoDelNotifyHeader(headerList);
@ -3446,40 +3446,77 @@ public class CoDelExcelServiceImpl implements CoDelExcelService {
}
/**
* 根据装箱明细的物料计算体积
* 每种物料每个pn是一种物料维护的箱子的长***箱数
* 根据装箱明细计算总体积
*
* @return 总体积
* <p><b>计算逻辑</b></p>
* <ul>
* <li>1. 查询所有装箱明细不按pn分组避免箱数统计错误</li>
* <li>2. 按箱子seq_no分组每个箱子只计算一次体积</li>
* <li>3. 根据箱子里的主要物料获取包装信息长宽高</li>
* <li>4. 单箱体积 = * * 总体积 = Σ(单箱体积)</li>
* </ul>
*
* <p><b>修复说明</b></p>
* 原方法使用 SQL GROUP BY pn + SUM(DISTINCT box_qty)
* 导致10个相同pn的箱子被统计为1个箱子DISTINCT去重
* 现改为按箱号遍历确保每个箱子都被正确计算
*
* @param notifyHeader 发货通知单头信息
* @return 总体积立方米保留2位小数
*/
private BigDecimal calculateVolumeByMaterials(EcssCoDelNotifyHeaderData notifyHeader) {
List<Map> palletDetailList = coDelMapper.getCoDelPalletDetailGroupByPn(notifyHeader);
try {
// 1. 查询箱子列表每个箱子包含box_qty长宽高等信息
List<Map> boxList = coDelMapper.selectBoxList(notifyHeader);
if (palletDetailList == null || palletDetailList.isEmpty()) {
if (boxList == null || boxList.isEmpty()) {
log.debug("未找到装箱数据,发货单号: {}", notifyHeader.getDelNo());
return BigDecimal.ZERO;
}
try {
// 获取所有物料编号
List<String> pns = palletDetailList.stream()
.map(detail -> (String) detail.get("pn"))
.filter(Objects::nonNull)
.distinct()
.collect(Collectors.toList());
// 2. 查询所有装箱明细获取每个箱子里的物料信息
EcssCoDelPalletHeaderData queryParam = new EcssCoDelPalletHeaderData();
queryParam.setSite(notifyHeader.getSite());
queryParam.setBuNo(notifyHeader.getBuNo());
queryParam.setDelNo(notifyHeader.getDelNo());
// 获取所有明细中的物料编号
Set<String> allPns = new HashSet<>();
for (Map box : boxList) {
Object seqNoObj = box.get("item_no");
if (seqNoObj == null) {
continue;
}
queryParam.setSeqNo(Integer.valueOf(seqNoObj.toString()));
List<Map> detailList = coDelMapper.selectPalletDetailList(queryParam);
if (detailList != null && !detailList.isEmpty()) {
for (Map detail : detailList) {
String pn = (String) detail.get("pn");
if (pn != null) {
allPns.add(pn);
}
}
}
}
if (pns.isEmpty()) {
if (allPns.isEmpty()) {
log.warn("装箱明细中未找到物料信息,发货单号: {}", notifyHeader.getDelNo());
return BigDecimal.ZERO;
}
// 根据物料编号获取packageNo
List<Map> packageNoList = coDelMapper.getPackageNoByPn(notifyHeader.getSite(), pns);
// 3. 获取物料对应的包装信息
List<String> pnList = new ArrayList<>(allPns);
List<Map> packageNoList = coDelMapper.getPackageNoByPn(notifyHeader.getSite(), pnList);
Map<String, String> partNoToPackageNoMap = packageNoList.stream()
.collect(Collectors.toMap(
map -> (String) map.get("pn"),
map -> (String) map.get("packageNo"),
(existing, replacement) -> existing // 处理重复key的情况
(existing, replacement) -> existing
));
// 获取所有packageNo对应的包装信息
// 4. 获取包装的长宽高信息
List<String> packageNos = packageNoList.stream()
.map(map -> (String) map.get("packageNo"))
.filter(Objects::nonNull)
@ -3487,11 +3524,10 @@ public class CoDelExcelServiceImpl implements CoDelExcelService {
.collect(Collectors.toList());
if (packageNos.isEmpty()) {
log.warn("未找到物料对应的包装信息,物料编号: {}", pns);
log.warn("未找到物料对应的包装信息,发货单号: {}", notifyHeader.getDelNo());
return BigDecimal.ZERO;
}
// 获取包装信息长宽高
List<EcssPackageData> packageDataList = coDelMapper.getPackageList(notifyHeader.getSite(), notifyHeader.getBuNo(), packageNos);
Map<String, EcssPackageData> packageNoToDataMap = packageDataList.stream()
.collect(Collectors.toMap(
@ -3500,61 +3536,67 @@ public class CoDelExcelServiceImpl implements CoDelExcelService {
(existing, replacement) -> existing
));
// 计算体积
// 5. 遍历每个箱子计算体积
BigDecimal totalVolume = BigDecimal.ZERO;
for (Map detail : palletDetailList) {
String pn = (String) detail.get("pn");
Object boxQtyObj = detail.get("box_qty");
int processedBoxCount = 0;
if (pn == null || boxQtyObj == null) {
for (Map box : boxList) {
Object seqNoObj = box.get("item_no");
if (seqNoObj == null) {
continue;
}
// 获取箱数
BigDecimal boxQty;
if (boxQtyObj instanceof BigDecimal) {
boxQty = (BigDecimal) boxQtyObj;
} else {
boxQty = new BigDecimal(boxQtyObj.toString());
// 查询该箱子的明细获取主要物料取第一个物料
queryParam.setSeqNo(Integer.valueOf(seqNoObj.toString()));
List<Map> detailList = coDelMapper.selectPalletDetailList(queryParam);
if (detailList == null || detailList.isEmpty()) {
log.warn("箱号 {} 没有装箱明细", seqNoObj);
continue;
}
// 获取包装信息
String packageNo = partNoToPackageNoMap.get(pn);
if (packageNo == null) {
log.warn("物料 {} 未维护packageNo", pn);
// 获取该箱子的第一个物料作为代表物料
String mainPn = (String) detailList.get(0).get("pn");
if (mainPn == null) {
log.warn("箱号 {} 的物料编号为空", seqNoObj);
continue;
}
EcssPackageData packageData = packageNoToDataMap.get(packageNo);
if (packageData == null) {
log.warn("包装编号 {} 未找到对应的包装信息", packageNo);
// 获取包装信息
String packageNo = partNoToPackageNoMap.get(mainPn);
if (packageNo == null) {
log.warn("箱号 {} 的物料 {} 未维护packageNo", seqNoObj, mainPn);
continue;
}
// 检查长宽高是否都有值
if (packageData.getLength() == null || packageData.getWidth() == null || packageData.getHeight() == null) {
log.warn("包装编号 {} 的长宽高信息不完整", packageNo);
EcssPackageData packageData = packageNoToDataMap.get(packageNo);
if (packageData == null || packageData.getLength() == null
|| packageData.getWidth() == null || packageData.getHeight() == null) {
log.warn("箱号 {} 的包装 {} 信息不完整", seqNoObj, packageNo);
continue;
}
// 计算该物料的体积***箱数
BigDecimal materialVolume = packageData.getLength()
// 计算单箱体积 * *
BigDecimal singleBoxVolume = packageData.getLength()
.multiply(packageData.getWidth())
.multiply(packageData.getHeight())
.multiply(boxQty);
.multiply(packageData.getHeight());
totalVolume = totalVolume.add(materialVolume);
// 累加到总体积
totalVolume = totalVolume.add(singleBoxVolume);
processedBoxCount++;
log.debug("物料 {} 包装 {} 箱数 {} 单箱体积 {} 总体积 {}",
pn, packageNo, boxQty,
packageData.getLength().multiply(packageData.getWidth()).multiply(packageData.getHeight()),
materialVolume);
log.debug("箱号 {} 物料 {} 包装 {} 单箱体积 {} m³",
seqNoObj, mainPn, packageNo, singleBoxVolume.setScale(4, RoundingMode.HALF_UP));
}
log.info("体积计算完成,发货单号: {}, 处理箱数: {}/{}, 总体积: {} m³",
notifyHeader.getDelNo(), processedBoxCount, boxList.size(),
totalVolume.setScale(2, RoundingMode.HALF_UP));
return totalVolume.setScale(2, RoundingMode.HALF_UP);
} catch (Exception e) {
log.error("计算物料体积时发生异常", e);
log.error("计算物料体积时发生异常,发货单号: {}", notifyHeader.getDelNo(), e);
return BigDecimal.ZERO;
}
}
@ -4919,4 +4961,34 @@ public class CoDelExcelServiceImpl implements CoDelExcelService {
return lineCount;
}
/**
* HTML 反转义处理
* HTML 实体字符转换回原始字符
*
*
* @param text 需要反转义的文本
* @return 反转义后的文本
*/
private String unescapeHtml(String text) {
if (text == null || text.isEmpty()) {
return text;
}
// 当前临时方案处理常见的 HTML 实体
String result = text;
result = result.replace("&amp;", "&"); // & 符号
result = result.replace("&lt;", "<"); // < 符号
result = result.replace("&gt;", ">"); // > 符号
result = result.replace("&quot;", "\""); // " 双引号
result = result.replace("&#39;", "'"); // ' 单引号
result = result.replace("&apos;", "'"); // ' 单引号XML风格
result = result.replace("&nbsp;", " "); // 空格
result = result.replace("&copy;", "©"); // 版权符号
result = result.replace("&reg;", "®"); // 注册商标
result = result.replace("&times;", "×"); // 乘号
result = result.replace("&divide;", "÷"); // 除号
return result;
}
}
Loading…
Cancel
Save