Merge branch 'dev_qinhongzhanWMS' into wms_dev

This commit is contained in:
秦鸿展
2026-01-24 17:39:19 +08:00
2 changed files with 224 additions and 8 deletions
@@ -342,8 +342,59 @@ public class StockInOrderApplicationService {
headerInfo.setManufacturer(value);
log.info("从表头第{}行读取到生产商: {}", rowIdx + 1, value);
} else if (labelValue.contains("报关员") && StringUtils.isBlank(headerInfo.getCustomsBrokerInfo())) {
headerInfo.setCustomsBrokerInfo(value);
log.info("从表头第{}行读取到报关员姓名及联系方式: {}", rowIdx + 1, value);
// 过滤掉标签文本(包含冒号、常见标签关键词等)
if (StringUtils.isNotBlank(value) &&
!value.contains("") && !value.contains(":") &&
!value.contains("完成时间") && !value.contains("下单日期") && !value.contains("入仓日期") &&
!value.contains("联系人") && !value.contains("Tel") && !value.contains("Fax") &&
!value.contains("客户") && !value.contains("地址") && !value.contains("日期") &&
!value.contains("方式") && !value.contains("关区") && !value.contains("关别") &&
!value.contains("报关员") && !value.contains("生产商") && !value.contains("承运方")) {
headerInfo.setCustomsBrokerInfo(value);
log.info("从表头第{}行读取到报关员姓名及联系方式: {}", rowIdx + 1, value);
} else {
// 如果找到的值是标签,继续向后查找
boolean found = false;
for (int searchColIdx = colIdx + 2; searchColIdx < colIdx + 10 && searchColIdx < row.getPhysicalNumberOfCells(); searchColIdx++) {
Cell nextValueCell = row.getCell(searchColIdx);
if (nextValueCell != null) {
String nextValue = getCellValueAsString(nextValueCell);
// 跳过标签文本(包含冒号、常见标签关键词等)
if (StringUtils.isNotBlank(nextValue) &&
!nextValue.contains("") && !nextValue.contains(":") &&
!nextValue.contains("完成时间") && !nextValue.contains("下单日期") && !nextValue.contains("入仓日期") &&
!nextValue.contains("联系人") && !nextValue.contains("Tel") && !nextValue.contains("Fax") &&
!nextValue.contains("客户") && !nextValue.contains("地址") && !nextValue.contains("日期") &&
!nextValue.contains("方式") && !nextValue.contains("关区") && !nextValue.contains("关别") &&
!nextValue.contains("报关员") && !nextValue.contains("生产商") && !nextValue.contains("承运方")) {
headerInfo.setCustomsBrokerInfo(nextValue);
log.info("从表头第{}行读取到报关员姓名及联系方式: {}", rowIdx + 1, nextValue);
found = true;
break;
}
}
}
// 如果没找到合适的值,尝试查找下一行的同一列
if (!found) {
Row nextRow = sheet.getRow(rowIdx + 1);
if (nextRow != null) {
Cell nextRowCell = nextRow.getCell(colIdx);
if (nextRowCell != null) {
String nextRowValue = getCellValueAsString(nextRowCell);
if (StringUtils.isNotBlank(nextRowValue) &&
!nextRowValue.contains("") && !nextRowValue.contains(":") &&
!nextRowValue.contains("完成时间") && !nextRowValue.contains("下单日期") && !nextRowValue.contains("入仓日期") &&
!nextRowValue.contains("联系人") && !nextRowValue.contains("Tel") && !nextRowValue.contains("Fax") &&
!nextRowValue.contains("客户") && !nextRowValue.contains("地址") && !nextRowValue.contains("日期") &&
!nextRowValue.contains("方式") && !nextRowValue.contains("关区") && !nextRowValue.contains("关别") &&
!nextRowValue.contains("报关员") && !nextRowValue.contains("生产商") && !nextRowValue.contains("承运方")) {
headerInfo.setCustomsBrokerInfo(nextRowValue);
log.info("从表头第{}行(下一行)读取到报关员姓名及联系方式: {}", rowIdx + 2, nextRowValue);
}
}
}
}
}
} else if (labelValue.contains("送货地址") && StringUtils.isBlank(headerInfo.getDeliveryAddress())) {
headerInfo.setDeliveryAddress(value);
log.info("从表头第{}行读取到送货地址: {}", rowIdx + 1, value);
@@ -384,11 +435,119 @@ public class StockInOrderApplicationService {
}
log.info("从表头第{}行读取到是否需要运输: {}", rowIdx + 1, value);
} else if (labelValue.contains("完成时间") && StringUtils.isBlank(headerInfo.getCompletionTime())) {
headerInfo.setCompletionTime(value);
log.info("从表头第{}行读取到完成时间: {}", rowIdx + 1, value);
// 过滤掉标签文本(包含冒号、常见标签关键词等)
if (StringUtils.isNotBlank(value) &&
!value.contains("") && !value.contains(":") &&
!value.contains("下单日期") && !value.contains("入仓日期") &&
!value.contains("起运") && !value.contains("运抵国") && !value.contains("地区") &&
!value.contains("联系人") && !value.contains("Tel") && !value.contains("Fax") &&
!value.contains("客户") && !value.contains("地址") && !value.contains("日期") &&
!value.contains("方式") && !value.contains("关区") && !value.contains("关别") &&
!value.contains("报关员") && !value.contains("生产商") && !value.contains("承运方")) {
headerInfo.setCompletionTime(value);
log.info("从表头第{}行读取到完成时间: {}", rowIdx + 1, value);
} else {
// 如果找到的值是标签,继续向后查找
boolean found = false;
for (int searchColIdx = colIdx + 2; searchColIdx < colIdx + 10 && searchColIdx < row.getPhysicalNumberOfCells(); searchColIdx++) {
Cell nextValueCell = row.getCell(searchColIdx);
if (nextValueCell != null) {
String nextValue = getCellValueAsString(nextValueCell);
// 跳过标签文本(包含冒号、常见标签关键词等)
if (StringUtils.isNotBlank(nextValue) &&
!nextValue.contains("") && !nextValue.contains(":") &&
!nextValue.contains("下单日期") && !nextValue.contains("入仓日期") &&
!nextValue.contains("起运") && !nextValue.contains("运抵国") && !nextValue.contains("地区") &&
!nextValue.contains("联系人") && !nextValue.contains("Tel") && !nextValue.contains("Fax") &&
!nextValue.contains("客户") && !nextValue.contains("地址") && !nextValue.contains("日期") &&
!nextValue.contains("方式") && !nextValue.contains("关区") && !nextValue.contains("关别") &&
!nextValue.contains("报关员") && !nextValue.contains("生产商") && !nextValue.contains("承运方")) {
headerInfo.setCompletionTime(nextValue);
log.info("从表头第{}行读取到完成时间: {}", rowIdx + 1, nextValue);
found = true;
break;
}
}
}
// 如果没找到合适的值,尝试查找下一行的同一列
if (!found) {
Row nextRow = sheet.getRow(rowIdx + 1);
if (nextRow != null) {
Cell nextRowCell = nextRow.getCell(colIdx);
if (nextRowCell != null) {
String nextRowValue = getCellValueAsString(nextRowCell);
if (StringUtils.isNotBlank(nextRowValue) &&
!nextRowValue.contains("") && !nextRowValue.contains(":") &&
!nextRowValue.contains("下单日期") && !nextRowValue.contains("入仓日期") &&
!nextRowValue.contains("起运") && !nextRowValue.contains("运抵国") && !nextRowValue.contains("地区") &&
!nextRowValue.contains("联系人") && !nextRowValue.contains("Tel") && !nextRowValue.contains("Fax") &&
!nextRowValue.contains("客户") && !nextRowValue.contains("地址") && !nextRowValue.contains("日期") &&
!nextRowValue.contains("方式") && !nextRowValue.contains("关区") && !nextRowValue.contains("关别") &&
!nextRowValue.contains("报关员") && !nextRowValue.contains("生产商") && !nextRowValue.contains("承运方")) {
headerInfo.setCompletionTime(nextRowValue);
log.info("从表头第{}行(下一行)读取到完成时间: {}", rowIdx + 2, nextRowValue);
}
}
}
}
}
} else if (labelValue.contains("下单日期") && StringUtils.isBlank(headerInfo.getOrderDate())) {
headerInfo.setOrderDate(value);
log.info("从表头第{}行读取到下单日期: {}", rowIdx + 1, value);
// 过滤掉标签文本(包含冒号、常见标签关键词等)
if (StringUtils.isNotBlank(value) &&
!value.contains("") && !value.contains(":") &&
!value.contains("起运") && !value.contains("运抵国") && !value.contains("地区") &&
!value.contains("完成时间") && !value.contains("入仓日期") &&
!value.contains("联系人") && !value.contains("Tel") && !value.contains("Fax") &&
!value.contains("客户") && !value.contains("地址") && !value.contains("日期") &&
!value.contains("方式") && !value.contains("关区") && !value.contains("关别") &&
!value.contains("报关员") && !value.contains("生产商") && !value.contains("承运方")) {
headerInfo.setOrderDate(value);
log.info("从表头第{}行读取到下单日期: {}", rowIdx + 1, value);
} else {
// 如果找到的值是标签,继续向后查找
boolean found = false;
for (int searchColIdx = colIdx + 2; searchColIdx < colIdx + 10 && searchColIdx < row.getPhysicalNumberOfCells(); searchColIdx++) {
Cell nextValueCell = row.getCell(searchColIdx);
if (nextValueCell != null) {
String nextValue = getCellValueAsString(nextValueCell);
// 跳过标签文本(包含冒号、常见标签关键词等)
if (StringUtils.isNotBlank(nextValue) &&
!nextValue.contains("") && !nextValue.contains(":") &&
!nextValue.contains("起运") && !nextValue.contains("运抵国") && !nextValue.contains("地区") &&
!nextValue.contains("完成时间") && !nextValue.contains("入仓日期") &&
!nextValue.contains("联系人") && !nextValue.contains("Tel") && !nextValue.contains("Fax") &&
!nextValue.contains("客户") && !nextValue.contains("地址") && !nextValue.contains("日期") &&
!nextValue.contains("方式") && !nextValue.contains("关区") && !nextValue.contains("关别") &&
!nextValue.contains("报关员") && !nextValue.contains("生产商") && !nextValue.contains("承运方")) {
headerInfo.setOrderDate(nextValue);
log.info("从表头第{}行读取到下单日期: {}", rowIdx + 1, nextValue);
found = true;
break;
}
}
}
// 如果没找到合适的值,尝试查找下一行的同一列
if (!found) {
Row nextRow = sheet.getRow(rowIdx + 1);
if (nextRow != null) {
Cell nextRowCell = nextRow.getCell(colIdx);
if (nextRowCell != null) {
String nextRowValue = getCellValueAsString(nextRowCell);
if (StringUtils.isNotBlank(nextRowValue) &&
!nextRowValue.contains("") && !nextRowValue.contains(":") &&
!nextRowValue.contains("起运") && !nextRowValue.contains("运抵国") && !nextRowValue.contains("地区") &&
!nextRowValue.contains("完成时间") && !nextRowValue.contains("入仓日期") &&
!nextRowValue.contains("联系人") && !nextRowValue.contains("Tel") && !nextRowValue.contains("Fax") &&
!nextRowValue.contains("客户") && !nextRowValue.contains("地址") && !nextRowValue.contains("日期") &&
!nextRowValue.contains("方式") && !nextRowValue.contains("关区") && !nextRowValue.contains("关别") &&
!nextRowValue.contains("报关员") && !nextRowValue.contains("生产商") && !nextRowValue.contains("承运方")) {
headerInfo.setOrderDate(nextRowValue);
log.info("从表头第{}行(下一行)读取到下单日期: {}", rowIdx + 2, nextRowValue);
}
}
}
}
}
} else if (labelValue.contains("备注") && StringUtils.isBlank(headerInfo.getRemark())) {
headerInfo.setRemark(value);
log.info("从表头第{}行读取到备注: {}", rowIdx + 1, value);
@@ -682,6 +841,11 @@ public class StockInOrderApplicationService {
// 明细
List<InMaterialDetailDO> details = new ArrayList<>();
for (StockInOrderImportRowDTO r : groupRows) {
// 记录当前明细行的关键信息,用于调试
log.info("处理明细行 - 委托编号NO: {}, 商品名称: [{}], 料号: [{}], SKU码: [{}], 仓库数量: [{}], 入库数量: [{}]",
h.getConsignmentNo(), r.getMaterialName(), r.getMaterialCode(), r.getSkuCode(),
r.getWarehouseQuantity(), r.getInboundQuantity());
// 根据明细表中的字段查询物料基础信息(优先:料号 > 商品SKU码 > 商品名称)
Long materialBaseInfoId = null;
LoginUser currentLoginUser = SecurityUtils.getLoginUser();
@@ -695,11 +859,17 @@ public class StockInOrderApplicationService {
if (topOrganizationId != null) {
queryDO.setTopOrganizationId(topOrganizationId);
}
log.info("尝试通过料号查询物料基础信息,料号: [{}], topOrganizationId: {}", r.getMaterialCode(), topOrganizationId);
List<MaterialBaseInfoPO> materialList = materialBaseInfoService.queryList(queryDO);
log.info("料号查询结果,查询到 {} 条记录", materialList != null ? materialList.size() : 0);
if (materialList != null && !materialList.isEmpty()) {
materialBaseInfoId = materialList.get(0).getMaterialBaseInfoId();
log.info("通过料号查询到物料基础信息,料号: {}, 物料ID: {}", r.getMaterialCode(), materialBaseInfoId);
} else {
log.warn("通过料号未查询到物料基础信息,料号: [{}]", r.getMaterialCode());
}
} else {
log.warn("料号为空,跳过料号查询");
}
// 如果料号查询不到,使用商品SKU码查询
@@ -709,11 +879,17 @@ public class StockInOrderApplicationService {
if (topOrganizationId != null) {
queryDO.setTopOrganizationId(topOrganizationId);
}
log.info("尝试通过商品SKU码查询物料基础信息,SKU码: [{}], topOrganizationId: {}", r.getSkuCode(), topOrganizationId);
List<MaterialBaseInfoPO> materialList = materialBaseInfoService.queryList(queryDO);
log.info("SKU码查询结果,查询到 {} 条记录", materialList != null ? materialList.size() : 0);
if (materialList != null && !materialList.isEmpty()) {
materialBaseInfoId = materialList.get(0).getMaterialBaseInfoId();
log.info("通过商品SKU码查询到物料基础信息,SKU码: {}, 物料ID: {}", r.getSkuCode(), materialBaseInfoId);
} else {
log.warn("通过SKU码未查询到物料基础信息,SKU码: [{}]", r.getSkuCode());
}
} else if (materialBaseInfoId == null) {
log.warn("SKU码为空,跳过SKU码查询");
}
// 如果料号和SKU码都查询不到,使用商品名称查询
@@ -723,26 +899,38 @@ public class StockInOrderApplicationService {
if (topOrganizationId != null) {
queryDO.setTopOrganizationId(topOrganizationId);
}
log.info("尝试通过商品名称查询物料基础信息,商品名称: [{}], topOrganizationId: {}", r.getMaterialName(), topOrganizationId);
List<MaterialBaseInfoPO> materialList = materialBaseInfoService.queryList(queryDO);
log.info("商品名称查询结果,查询到 {} 条记录", materialList != null ? materialList.size() : 0);
if (materialList != null && !materialList.isEmpty()) {
materialBaseInfoId = materialList.get(0).getMaterialBaseInfoId();
log.info("通过商品名称查询到物料基础信息,商品名称: {}, 物料ID: {}", r.getMaterialName(), materialBaseInfoId);
} else {
log.warn("通过商品名称未查询到物料基础信息,商品名称: [{}]", r.getMaterialName());
}
} else if (materialBaseInfoId == null) {
log.warn("商品名称为空,跳过商品名称查询");
}
// 如果都查询不到,记录警告但不阻止导入(允许后续手动关联)
if (materialBaseInfoId == null) {
log.warn("未查询到物料基础信息,料号: {}, SKU码: {}, 商品名称: {},将使用null值,后续可能需要手动关联",
log.warn("未查询到物料基础信息,料号: [{}], SKU码: [{}], 商品名称: [{}],将使用null值,后续可能需要手动关联",
r.getMaterialCode(), r.getSkuCode(), r.getMaterialName());
}
// 使用仓库数量或入库数量(优先使用仓库数量,如果为空则使用入库数量)
BigDecimal quantity = r.getWarehouseQuantity();
log.info("数量字段检查 - 仓库数量: [{}], 入库数量: [{}]", r.getWarehouseQuantity(), r.getInboundQuantity());
if (quantity == null) {
quantity = r.getInboundQuantity();
log.info("仓库数量为空,使用入库数量: [{}]", quantity);
}
// 如果数量为空,跳过该明细行,记录警告,继续处理其他行
if (quantity == null) {
throw new ServiceException("导入失败:仓库数量或入库数量不能为空委托编号NO=" + h.getConsignmentNo() + ",物料基础信息ID=" + materialBaseInfoId + "");
log.warn("跳过明细行:仓库数量或入库数量不能为空 - 委托编号NO: [{}], 物料基础信息ID: [{}], 商品名称: [{}], 料号: [{}], SKU码: [{}], 仓库数量: [{}], 入库数量: [{}]",
h.getConsignmentNo(), materialBaseInfoId, r.getMaterialName(), r.getMaterialCode(),
r.getSkuCode(), r.getWarehouseQuantity(), r.getInboundQuantity());
continue; // 跳过该明细行,继续处理下一行
}
InMaterialDetailDO d = new InMaterialDetailDO();
@@ -780,12 +968,31 @@ public class StockInOrderApplicationService {
d.setTotalPrice(r.getTotalPrice());
d.setCurrency(r.getCurrency());
d.setRemark(r.getDetailRemark());
// 记录即将保存的明细数据,用于调试
log.info("准备保存明细数据 - 商品名称: [{}], 料号: [{}], SKU码: [{}], 规格型号: [{}], 入库数量: [{}], 数量: [{}], 单位: [{}], 总净重: [{}], 总毛重: [{}], 总体积: [{}], 总面积: [{}], 原产国: [{}], 币制: [{}], 备注: [{}]",
r.getMaterialName(), r.getMaterialCode(), r.getSkuCode(), r.getSpecificationModel(),
r.getInboundQuantity(), quantity, unit, d.getTotalNetWeight(), d.getTotalGrossWeight(),
d.getTotalVolume(), d.getTotalArea(), r.getOriginCountry(), r.getCurrency(), r.getDetailRemark());
details.add(d);
}
// 如果该订单的所有明细行都被跳过(details为空),跳过该订单
if (details.isEmpty()) {
log.warn("跳过入库单:委托编号NO [{}] 的所有明细行都因数据不完整被跳过,该入库单将不会被导入", h.getConsignmentNo());
continue; // 跳过该订单,继续处理下一个订单
}
order.setMaterialDetailList(details);
orderList.add(order);
}
// 如果所有订单都被跳过(orderList为空),抛出异常提示用户
if (orderList.isEmpty()) {
throw new ServiceException("导入失败:所有入库单的明细行都因数据不完整(数量为空或物料基础信息缺失)被跳过,请检查Excel数据");
}
return stockInOrderDomainService.batchInsert(orderList);
} catch (ServiceException e) {
throw e;
@@ -301,6 +301,15 @@ public class StockInOrderDomainService {
});
stockReceiptOrderDO.setMaterialDetailList(receiptMaterialDetailDOList);
stockReceiptOrderDO.setMaterialQuantity(receiptMaterialDetailDOList.size());
// 重新计算计划数量:从物料明细中汇总quantity字段
BigDecimal quantity = receiptMaterialDetailDOList.stream()
.map(ReceiptMaterialDetailDO::getQuantity)
.filter(Objects::nonNull)
.reduce(BigDecimal.ZERO, BigDecimal::add);
stockReceiptOrderDO.setQuantity(quantity);
} else {
// 如果没有物料明细,将数量设置为0
stockReceiptOrderDO.setQuantity(BigDecimal.ZERO);
}
stockReceiptOrderDOList.add(stockReceiptOrderDO);
});